{"version":3,"file":"app-d5402680.xxxxxxxx.bundle.js","mappings":"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","sources":["webpack://iadviser/./src/config/plugins.ts","webpack://iadviser/./src/core/events/logout.ts","webpack://iadviser/./src/core/events/base-event.ts","webpack://iadviser/./src/core/events/index.ts","webpack://iadviser/./src/core/fetch-with-retry.ts","webpack://iadviser/./src/core/http-client-config.ts","webpack://iadviser/./src/core/sentry.ts"],"sourcesContent":["import { Aurelia, PLATFORM } from 'aurelia-framework';\r\nimport { I18N, TCustomAttribute } from 'aurelia-i18n';\r\nimport { environment } from 'environment';\r\nimport * as Backend from 'i18next-xhr-backend';\r\nimport { defaultFeatureFlags } from 'resources/plugins/feature-flags/default-feature-flags';\r\nimport { initialState } from 'store/state';\r\n\r\nexport function configurePlugins(aurelia: Aurelia) {\r\n aurelia.use\r\n .standardConfiguration()\r\n .plugin(PLATFORM.moduleName('aurelia-animator-css'))\r\n .plugin(PLATFORM.moduleName('aurelia-dynamic-html'))\r\n .plugin(PLATFORM.moduleName('aurelia-validation'))\r\n .feature(PLATFORM.moduleName('components/forms/phone-number/index'))\r\n .feature(PLATFORM.moduleName('resources/index'))\r\n .feature(PLATFORM.moduleName('components/index'))\r\n .feature(PLATFORM.moduleName('resources/plugins/aurelia-table/index'))\r\n .plugin(PLATFORM.moduleName('aurelia-portal-attribute'))\r\n .plugin(PLATFORM.moduleName('aurelia-application-insights'), (config) => {\r\n config.init('d182b2db-211c-4a36-b950-289015ad8436');\r\n config.attach({\r\n logging: {\r\n enabled: true,\r\n },\r\n logForwarding: {\r\n enabled: true,\r\n },\r\n pageTracking: {\r\n enabled: true,\r\n },\r\n clickTracking: {\r\n enabled: true,\r\n },\r\n });\r\n })\r\n .plugin(PLATFORM.moduleName('aurelia-i18n'), async (instance: I18N) => {\r\n const aliases = ['t', 'i18n'];\r\n // add aliases for 't' attribute\r\n TCustomAttribute.configureAliases(aliases);\r\n\r\n // register backend plugin\r\n instance.i18next.use(Backend);\r\n\r\n // adapt options to your needs (see http://i18next.com/docs/options/)\r\n // make sure to return the promise of the setup method, in order to guarantee proper loading\r\n return instance.setup({\r\n backend: {\r\n // <-- configure backend settings\r\n loadPath: `./locales/{{lng}}/{{ns}}.json?v=${process.env.BUILD_VERSION}`, // <-- XHR settings for where to get the files from\r\n },\r\n attributes: aliases,\r\n lng: environment.defaultLocale,\r\n ns: ['translation', 'buttonLabels', 'errors', 'lookups', 'navigation'],\r\n defaultNS: 'translation',\r\n fallbackLng: 'en',\r\n debug: false,\r\n });\r\n })\r\n .plugin(PLATFORM.moduleName('aurelia-store'), {\r\n initialState,\r\n measurePerformance: false,\r\n history: {\r\n limit: 2,\r\n },\r\n })\r\n .plugin(PLATFORM.moduleName('resources/plugins/feature-flags/index'), {\r\n defaultFlags: defaultFeatureFlags,\r\n });\r\n\r\n if (environment.testing) {\r\n aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));\r\n }\r\n}\r\n","import { momentToLocalDateTimeString, newMoment } from 'resources/moment-helpers';\r\nimport { TabbedModeLocalStorageKey as QuestionEditorTabbedModeLocalStorageKey } from 'routes/app-admin/question-collection-editor/components/question-editor/question-editor';\r\nimport { BaseEvent } from './base-event';\r\n\r\nexport class LogoutEvent extends BaseEvent {\r\n protected getEventName(): string {\r\n return 'ia-logout';\r\n }\r\n\r\n protected handleEvent(): void {\r\n const itemsToKeep = [\r\n 'ia_recent_clients',\r\n 'theme',\r\n 'deviceId',\r\n 'device_tokens',\r\n QuestionEditorTabbedModeLocalStorageKey,\r\n ];\r\n Object.keys(localStorage)\r\n .filter((x) => !itemsToKeep.includes(x))\r\n .map((x) => localStorage.removeItem(x));\r\n window.location.href = '/';\r\n\r\n // Debug information\r\n localStorage.setItem('debug', JSON.stringify({ lastLogout: this.generateLastLogoutDebugInfo() }));\r\n }\r\n\r\n private generateLastLogoutDebugInfo(): string {\r\n return momentToLocalDateTimeString(newMoment());\r\n }\r\n}\r\n","import { EventAggregator } from 'aurelia-event-aggregator';\r\n\r\nexport abstract class BaseEvent {\r\n constructor(protected ea: EventAggregator) {\r\n this.ea.subscribe(this.getEventName(), (data: T) => this.handleEvent(data));\r\n }\r\n\r\n protected abstract getEventName(): string;\r\n protected abstract handleEvent(data: T): void;\r\n}\r\n","import { EventAggregator } from 'aurelia-event-aggregator';\r\nimport { LogoutEvent } from './logout';\r\n\r\nexport function configureEvents(ea: EventAggregator) {\r\n new LogoutEvent(ea);\r\n\r\n // You can add more events here, and configure them similarly\r\n // new SomeOtherEvent(ea);\r\n}\r\n","import { HttpClient } from 'aurelia-fetch-client';\r\n\r\n// Allow delay function to be injected for testing\r\nexport async function fetchWithRetry(\r\n http: HttpClient, \r\n url: string, \r\n maxAttempts = 5,\r\n delayFn = (attempt: number) => new Promise((resolve) => setTimeout(resolve, attempt * 3000))\r\n) {\r\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\r\n try {\r\n const response = await http.fetch(url);\r\n return response;\r\n } catch (error) {\r\n if (attempt === maxAttempts) {\r\n throw error; // If this was the last attempt, throw the error\r\n }\r\n await delayFn(attempt);\r\n }\r\n }\r\n}\r\n","import { EventAggregator } from 'aurelia-event-aggregator';\r\nimport { HttpClient } from 'aurelia-fetch-client';\r\nimport { getDeviceTokenForUser } from 'resources/device-token-manager';\r\nimport { RequestEx } from 'resources/endpoints/endpoints';\r\nimport { parseJwt } from 'resources/parse-jwt';\r\nimport { FeatureFlagService } from 'resources/plugins/feature-flags/feature-flags-service';\r\nimport { TokenService } from 'resources/services/token-service';\r\nimport { httpErrorResponseHandler } from 'resources/utilities/api-error-handler';\r\nimport { fetchWithRetry } from './fetch-with-retry';\r\n\r\nexport function configureHttpClient(\r\n http: HttpClient,\r\n tokenService: TokenService,\r\n ea: EventAggregator,\r\n featureFlagService?: FeatureFlagService,\r\n) {\r\n http.configure((config) => {\r\n config.withInterceptor({\r\n async request(request: Request) {\r\n const token = tokenService.getAuthToken();\r\n request.headers.append('Authorization', 'Bearer ' + token);\r\n if (tokenService.getDeviceId()) {\r\n request.headers.append('X-Device-Id', tokenService.getDeviceId());\r\n }\r\n if (token) {\r\n const emailAddress = parseJwt(token).sub;\r\n const deviceToken = getDeviceTokenForUser(emailAddress);\r\n if (deviceToken) {\r\n request.headers.append('X-Device-Token', deviceToken);\r\n }\r\n }\r\n return request;\r\n },\r\n async response(response: Response, request?: Request) {\r\n featureFlagService?.applyServerFlagsFromResponse(response);\r\n\r\n const requestEx = request as RequestEx;\r\n if (requestEx?.canHandleError != null && (await requestEx.canHandleError(response.clone()))) {\r\n return response;\r\n } else if (response.status === 401) {\r\n try {\r\n if (tokenService.getRefreshToken()) {\r\n await tokenService.refreshAuthToken();\r\n const retry: any = await fetchWithRetry(http, response.url);\r\n return retry;\r\n } else {\r\n if (ea) {\r\n ea.publish('ia-logout');\r\n }\r\n }\r\n } catch (e) {\r\n if (ea) {\r\n ea.publish('ia-logout');\r\n }\r\n }\r\n } else if (response.status === 403) {\r\n // 2FA checks not passed - user must login again (all subsequent API requests will be rejected until the user authenticates again)\r\n if (ea) {\r\n ea.publish('ia-logout');\r\n }\r\n } else if (response.status === 400) {\r\n // cloning the response is extremely important so we don't step on other code's toes,\r\n // this is because a Response object's body can only be read once\r\n const responseClone = response.clone();\r\n const responseJSON = await responseClone.json();\r\n\r\n httpErrorResponseHandler(response);\r\n\r\n if (responseJSON && responseJSON.grant_type) {\r\n const redirectEvents = ['invalid_refresh_token', 'invalid_client', 'expired_refresh'];\r\n if (redirectEvents.includes(responseJSON.grant_type)) {\r\n ea.publish('ia-logout');\r\n }\r\n }\r\n } else if (response.status === 500) {\r\n httpErrorResponseHandler(response);\r\n }\r\n\r\n return response;\r\n },\r\n });\r\n });\r\n\r\n return http;\r\n}\r\n","import { Event, init, Replay } from '@sentry/browser';\r\n\r\nexport function isLocalHost(url: string): boolean {\r\n return url.includes('localhost');\r\n}\r\n\r\nexport function isProductionEnvironment(hostname: string): boolean {\r\n return !hostname.includes('-');\r\n}\r\n\r\nexport function getSentryReplaysSampleRate(hostname: string): number {\r\n return isProductionEnvironment(hostname) ? 0.01 : 0;\r\n}\r\n\r\nconst isNotLocalHost = !isLocalHost(window.location.href);\r\nconst sentryDsn = 'https://40b9a8f8fd5d41228df0835f956bd078@o217251.ingest.sentry.io/1358951';\r\n\r\nif (isNotLocalHost) {\r\n init({\r\n dsn: sentryDsn,\r\n // Only capture replays in production (1% of sessions), none in staging/dev environments\r\n replaysSessionSampleRate: getSentryReplaysSampleRate(window.location.hostname),\r\n replaysOnErrorSampleRate: 1.0,\r\n integrations: [new Replay()],\r\n beforeSend(event: Event) {\r\n event.extra = event.extra || {};\r\n event.extra.featureFlags = window.featureFlags;\r\n return event;\r\n }\r\n });\r\n}\r\n"],"names":["configurePlugins","aurelia","_this","this","use","standardConfiguration","plugin","feature","config","init","attach","logging","enabled","logForwarding","pageTracking","clickTracking","instance","__awaiter","aliases","aurelia_i18n__WEBPACK_IMPORTED_MODULE_1__","TCustomAttribute","configureAliases","i18next","i18next_xhr_backend__WEBPACK_IMPORTED_MODULE_3__","setup","backend","loadPath","concat","attributes","lng","environment__WEBPACK_IMPORTED_MODULE_2__","c","defaultLocale","ns","defaultNS","fallbackLng","debug","initialState","store_state__WEBPACK_IMPORTED_MODULE_5__","u","measurePerformance","history","limit","defaultFlags","resources_plugins_feature_flags_default_feature_flags__WEBPACK_IMPORTED_MODULE_4__","b","testing","LogoutEvent","_super","__extends","prototype","getEventName","handleEvent","itemsToKeep","question_editor","S","Object","keys","localStorage","filter","x","includes","map","removeItem","window","location","href","setItem","JSON","stringify","lastLogout","generateLastLogoutDebugInfo","moment_helpers","$E","j7","ea","subscribe","data","configureEvents","fetchWithRetry","http_1","url_1","http","url","maxAttempts","delayFn","attempt","Promise","resolve","setTimeout","fetch","_a","sent","error_1","configureHttpClient","tokenService","featureFlagService","configure","withInterceptor","request","token","getAuthToken","headers","append","getDeviceId","emailAddress","parse_jwt","$n","sub","deviceToken","device_token_manager","W","response","applyServerFlagsFromResponse","requestEx","canHandleError","clone","_b","status","getRefreshToken","refreshAuthToken","publish","json","responseJSON","api_error_handler","grant_type","hostname","_sentry_browser__WEBPACK_IMPORTED_MODULE_0__","Ts","dsn","replaysSessionSampleRate","isProductionEnvironment","replaysOnErrorSampleRate","integrations","_sentry_browser__WEBPACK_IMPORTED_MODULE_1__","fe","beforeSend","event","extra","featureFlags"],"sourceRoot":""}