{"version":3,"file":"app-adea02ea.xxxxxxxx.bundle.js","mappings":"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","sources":["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/http-client-config.ts","webpack://iadviser/./src/core/scoped-route-loader.ts","webpack://iadviser/./src/core/sentry.ts"],"sourcesContent":["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\r\n sessionStorage.removeItem('access_token');\r\n sessionStorage.removeItem('refresh_token');\r\n sessionStorage.removeItem('access_token_expiry');\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 { EventAggregator } from 'aurelia-event-aggregator';\r\nimport { HttpClient } from 'aurelia-fetch-client';\r\nimport { environment } from 'environment';\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 const requests = new WeakMap();\r\n const retriedRequests = new WeakSet();\r\n const tokenUrl = new Request(`${environment.apiHost}/token`).url;\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 if (token) {\r\n request.headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n if (tokenService.getDeviceId()) {\r\n request.headers.set('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 && !request.headers.has('X-Device-Token')) {\r\n request.headers.append('X-Device-Token', deviceToken);\r\n }\r\n }\r\n requests.set(request, request.clone());\r\n return request;\r\n },\r\n async response(response: Response, request?: Request) {\r\n featureFlagService?.applyServerFlagsFromResponse(response);\r\n const retry = requests.get(request);\r\n requests.delete(request);\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 if (request.url === tokenUrl) {\r\n return response;\r\n }\r\n\r\n try {\r\n if (tokenService.getRefreshToken() && !retriedRequests.has(request)) {\r\n if (request.headers.get('Authorization') === 'Bearer ' + tokenService.getAuthToken()) {\r\n await tokenService.refreshAuthToken();\r\n }\r\n retriedRequests.add(retry);\r\n return http.fetch(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","/**\r\n * Route-scoped dependency registration for Aurelia v1.\r\n *\r\n * Routes opt in through `settings.configureScope`. The callback configures a new\r\n * child container before the routed view model is constructed. Aurelia also uses\r\n * that container for layout composition, allowing descendants to resolve the same\r\n * explicitly registered instances without placing them in the root container.\r\n *\r\n * The scope belongs to a loaded route component, not a URL parameter or client.\r\n * Reusing a component reuses its scope; loading another component creates a new\r\n * scope. Only resources explicitly added to the cleanup registry are disposed.\r\n * Cleanup runs after component unbinding or when navigation abandons a loaded scope.\r\n *\r\n * Scoped routes require a view-model moduleId. Routes without a callback retain\r\n * the default loader's behavior, including HTML-only and empty routes.\r\n */\r\nimport { Container } from 'aurelia-dependency-injection';\r\nimport { EventAggregator, Subscription } from 'aurelia-event-aggregator';\r\nimport { CompositionContext, CompositionEngine, HtmlBehaviorResource, LogManager } from 'aurelia-framework';\r\nimport { Origin } from 'aurelia-metadata';\r\nimport { relativeToFile } from 'aurelia-path';\r\nimport { NavigationInstruction, RouteConfig, Router } from 'aurelia-router';\r\nimport { RouterViewLocator, TemplatingRouteLoader } from 'aurelia-templating-router';\r\n\r\n/**\r\n * Registers dependencies needed by a routed component and its layout descendants.\r\n *\r\n * @param container - The new route container, which inherits application dependencies.\r\n * @param instruction - The navigation instruction containing route parameters and settings.\r\n * @param cleanup - Optional-use registry for subscriptions, timers or other owned resources.\r\n * @returns Nothing, or a promise awaited before constructing the routed view model.\r\n *\r\n * Throwing or rejecting prevents the component from loading. Register scoped\r\n * instances in the supplied container rather than its parent or root.\r\n * Existing callbacks taking only container/instruction need no changes.\r\n *\r\n * @example\r\n * const configureScope: ConfigureRouteScope = (container, instruction, cleanup) => {\r\n * const subscription = container.get(EventAggregator).subscribe('changed', onChanged);\r\n * cleanup.add(subscription);\r\n * const timer = window.setInterval(refresh, 30000);\r\n * cleanup.add(() => window.clearInterval(timer));\r\n * };\r\n *\r\n * Register cleanup immediately after acquisition so partial configuration failures\r\n * are covered. Cleanup callbacks and dispose methods must be synchronous; async\r\n * scope configuration and an asynchronous owner unbind are supported.\r\n */\r\nexport type ConfigureRouteScope = (\r\n container: Container,\r\n instruction: NavigationInstruction,\r\n cleanup: IRouteScopeCleanup,\r\n) => void | Promise;\r\n\r\n/**\r\n * Optional route settings understood by ScopedRouteLoader.\r\n *\r\n * These settings belong on the full route definition alongside existing settings\r\n * such as claims and navigation labels, not on a viewport's component configuration.\r\n */\r\nexport interface ScopedRouteSettings {\r\n /** Configures dependencies before construction; omit to use the default route loader. */\r\n configureScope?: ConfigureRouteScope;\r\n}\r\n\r\n/** A resource with synchronous teardown, such as an Aurelia event subscription. */\r\nexport interface IRouteScopeDisposable {\r\n dispose(): void;\r\n}\r\n\r\n/**\r\n * Allows scope configuration to register owned resources without controlling teardown.\r\n * The loader owns disposal; configuration callbacks only register synchronous cleanup.\r\n */\r\nexport interface IRouteScopeCleanup {\r\n /**\r\n * Registers cleanup immediately after acquiring a resource.\r\n * Resources added after scope teardown are disposed immediately.\r\n */\r\n add(resource: IRouteScopeDisposable | (() => void)): void;\r\n}\r\n\r\n/**\r\n * Loads opted-in view-model routes using a container configured for that component.\r\n *\r\n * The default loader creates its own container internally, so scoped routes must\r\n * reproduce its container setup and delegate view-model preparation directly to\r\n * CompositionEngine. Rendering, activation and layout composition remain the\r\n * router's responsibility.\r\n */\r\nexport class ScopedRouteLoader extends TemplatingRouteLoader {\r\n public static inject = [CompositionEngine, EventAggregator];\r\n\r\n private scopes = new Map();\r\n private navigationSubscription: Subscription | undefined;\r\n\r\n /**\r\n * @param engine - Aurelia's composition engine used to prepare routed view models.\r\n */\r\n constructor(\r\n private engine: CompositionEngine,\r\n private events: EventAggregator,\r\n ) {\r\n super(engine);\r\n }\r\n\r\n /**\r\n * Prepares a routed component after registering any route-scoped dependencies.\r\n *\r\n * @param router - The router loading the component and owning the parent container.\r\n * @param config - The viewport configuration describing the component to load.\r\n * @param instruction - The full navigation instruction, including route-level settings.\r\n * @returns The prepared component context consumed by Aurelia's router.\r\n * @throws If scope configuration is invalid, the scoped route is not a view-model\r\n * module, the parent view model is unavailable, or configuration/loading fails.\r\n */\r\n public async loadRoute(router: Router, config: RouteConfig, instruction: NavigationInstruction) {\r\n // The loader receives a viewport config; route-level settings live on the instruction.\r\n const settings: ScopedRouteSettings = instruction.config.settings || {};\r\n const configureScope = settings.configureScope;\r\n\r\n if (configureScope === undefined) {\r\n return super.loadRoute(router, config, instruction);\r\n }\r\n\r\n if (typeof configureScope !== 'function') {\r\n throw new Error('Route settings.configureScope must be a function.');\r\n }\r\n\r\n if (typeof config.moduleId !== 'string' || /\\.html(?:[?#]|$)/i.test(config.moduleId)) {\r\n throw new Error('Scoped routes require a view-model moduleId.');\r\n }\r\n\r\n // getChildRouter is a runtime extension used by Aurelia's templating router.\r\n const container: Container & { getChildRouter?: () => Router } = router.container.createChild();\r\n\r\n let childRouter: Router | undefined;\r\n\r\n // RouterViewLocator links the loaded component to its hosting router-view.\r\n container.registerSingleton(RouterViewLocator);\r\n container.getChildRouter = () => {\r\n // Resolve a nested router lazily and reuse it for this component's container.\r\n container.registerHandler(Router, () => childRouter || (childRouter = router.createChild(container)));\r\n\r\n return container.get(Router);\r\n };\r\n\r\n const cleanup = new RouteScopeCleanup();\r\n let rootRouter = router;\r\n while (rootRouter.parent) rootRouter = rootRouter.parent;\r\n this.scopes.set(container, { router: rootRouter, cleanup, committed: false });\r\n this.watchNavigation();\r\n\r\n try {\r\n // Constructor injection must see completed registrations, including async setup.\r\n await configureScope(container, instruction, cleanup);\r\n\r\n // RouterView assigns viewModel at runtime, but Container's public typings omit it.\r\n const parentContainer = router.container as Container & {\r\n viewModel?: object;\r\n };\r\n\r\n if (!parentContainer.viewModel) {\r\n throw new Error('The router container has no parent view model.');\r\n }\r\n\r\n // Match the standard loader's module resolution relative to the parent view model.\r\n const parentModuleId = Origin.get(parentContainer.viewModel.constructor).moduleId;\r\n\r\n // The router needs this partial context, including its extra router property.\r\n // ensureViewModel mutates it to add the constructed instance and resource metadata.\r\n const context = {\r\n viewModel: relativeToFile(config.moduleId, parentModuleId),\r\n childContainer: container,\r\n view: config.view || config.viewStrategy,\r\n router,\r\n } as Partial;\r\n\r\n // The API types require full composition fields (e.g. viewSlot) that this\r\n // preparation step does not use. The router supplies the later rendering setup.\r\n const component = await this.engine.ensureViewModel(context as CompositionContext);\r\n if (cleanup.hasResources) {\r\n this.watchUnbind(component, container);\r\n } else {\r\n this.releaseScope(container);\r\n }\r\n return component;\r\n } catch (error) {\r\n this.releaseScope(container);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * The completion event also follows cancellation, redirects and pipeline errors.\r\n * Compare against the committed component tree, not the attempted destination:\r\n * a cancelled navigation must preserve the existing component's resources.\r\n */\r\n private watchNavigation(): void {\r\n if (this.navigationSubscription) {\r\n return;\r\n }\r\n\r\n this.navigationSubscription = this.events.subscribe(\r\n 'router:navigation:complete',\r\n ({ instruction, result }: { instruction: NavigationInstruction; result: { completed: boolean } }) => {\r\n let router = instruction.router;\r\n while (router.parent) {\r\n router = router.parent;\r\n }\r\n const active = new Set();\r\n this.collectContainers(router.currentInstruction, active);\r\n for (const [container, scope] of this.scopes) {\r\n if (scope.router === router) {\r\n if (scope.unbinding) {\r\n continue;\r\n }\r\n\r\n // A render/activation failure can leave an attempted instruction as current.\r\n // Only successful navigation may commit a newly created scope.\r\n if (!active.has(container) || (!result.completed && !scope.committed)) {\r\n this.releaseScope(container);\r\n } else if (result.completed) {\r\n scope.committed = true;\r\n }\r\n }\r\n }\r\n },\r\n );\r\n }\r\n\r\n /** Collects committed component containers across every viewport and nested router. */\r\n private collectContainers(instruction: NavigationInstruction | null, active: Set): void {\r\n if (!instruction) return;\r\n const viewPorts: Record = instruction.viewPortInstructions;\r\n for (const viewPort of Object.values(viewPorts)) {\r\n if (viewPort.component) active.add(viewPort.component.childContainer);\r\n if (viewPort.childNavigationInstruction) {\r\n this.collectContainers(viewPort.childNavigationInstruction, active);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Covers teardown without navigation, such as removing the application view.\r\n * Clone resource metadata so enabling the hook affects only this component.\r\n * Defer cleanup until the synchronous view/layout unbind traversal has finished.\r\n */\r\n private watchUnbind(component: CompositionContext, container: Container): void {\r\n const viewModel = component.viewModel as { unbind?: () => unknown };\r\n const original = viewModel.unbind;\r\n const release = () => this.releaseScope(container);\r\n const scope = this.scopes.get(container);\r\n viewModel.unbind = function () {\r\n if (scope) scope.unbinding = true;\r\n let result: unknown;\r\n try {\r\n result = original?.call(this);\r\n return result;\r\n } finally {\r\n // Aurelia does not await unbind, but cleanup should wait if the owner does async work.\r\n Promise.resolve(result).then(release, (error) => {\r\n LogManager.getLogger('route-scope-cleanup').error('Route view model unbind failed.', error);\r\n release();\r\n });\r\n }\r\n };\r\n // ResourceDescription's public typings omit the analyzed behavior metadata.\r\n const resource = component.viewModelResource as NonNullable & {\r\n metadata: HtmlBehaviorResource & { handlesUnbind: boolean };\r\n };\r\n const metadata: typeof resource.metadata = Object.create(resource.metadata);\r\n metadata.handlesUnbind = true;\r\n component.viewModelResource = Object.assign(Object.create(Object.getPrototypeOf(resource)), resource, { metadata });\r\n }\r\n\r\n /** Releases tracked ownership once, and drops the event subscription when no scopes remain. */\r\n private releaseScope(container: Container): void {\r\n const scope = this.scopes.get(container);\r\n if (!scope) return;\r\n this.scopes.delete(container);\r\n scope.cleanup.dispose();\r\n if (this.scopes.size === 0) {\r\n this.navigationSubscription?.dispose();\r\n this.navigationSubscription = undefined;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Owns resources explicitly registered during route scope configuration.\r\n * Cleanup is synchronous, runs in reverse order, and is safe to invoke repeatedly.\r\n * Inherited application services are never discovered or disposed automatically.\r\n */\r\nclass RouteScopeCleanup implements IRouteScopeCleanup {\r\n private callbacks: Array<() => void> = [];\r\n private disposed = false;\r\n\r\n /**\r\n * Registers a disposable or cleanup callback immediately after acquiring a resource.\r\n * Registration after teardown cleans up immediately, covering async setup still in flight.\r\n */\r\n public add(resource: IRouteScopeDisposable | (() => void)): void {\r\n const callback = typeof resource === 'function' ? resource : () => resource.dispose();\r\n if (this.disposed) {\r\n this.run(callback);\r\n } else {\r\n this.callbacks.push(callback);\r\n }\r\n }\r\n\r\n /** Whether this scope has opted into automatic resource cleanup. */\r\n public get hasResources(): boolean {\r\n return this.callbacks.length > 0;\r\n }\r\n\r\n /** Releases every resource, reporting failures without skipping remaining cleanup. */\r\n public dispose(): void {\r\n if (this.disposed) {\r\n return;\r\n }\r\n\r\n this.disposed = true;\r\n const callbacks = this.callbacks;\r\n this.callbacks = [];\r\n\r\n // Dispose in reverse order, use internal runner with error handling to best effort dispose\r\n for (let index = callbacks.length - 1; index >= 0; index--) {\r\n this.run(callbacks[index]);\r\n }\r\n }\r\n\r\n private run(callback: () => void): void {\r\n try {\r\n callback();\r\n } catch (error) {\r\n LogManager.getLogger('route-scope-cleanup').error('Failed to dispose a route scope resource.', error);\r\n }\r\n }\r\n}\r\n\r\ninterface OwnedScope {\r\n router: Router;\r\n cleanup: RouteScopeCleanup;\r\n committed: boolean;\r\n unbinding?: boolean;\r\n}\r\n\r\ninterface ScopeViewPort {\r\n component?: { childContainer: Container };\r\n childNavigationInstruction?: NavigationInstruction;\r\n}\r\n","import { captureException, Event, init, Replay } from '@sentry/browser';\r\nimport { reportBridgeErrors } from 'components/au2-bridge/bridge-error-reporting';\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\r\nreportBridgeErrors(captureException);\r\n"],"names":["getEventName","handleEvent","itemsToKeep","Object","keys","localStorage","filter","x","includes","map","removeItem","sessionStorage","window","location","href","setItem","JSON","stringify","lastLogout","this","generateLastLogoutDebugInfo","ea","subscribe","data","configureEvents","LogoutEvent","configureHttpClient","http","tokenService","featureFlagService","requests","WeakMap","retriedRequests","WeakSet","tokenUrl","Request","apiHost","url","configure","config","withInterceptor","request","token","getAuthToken","headers","set","getDeviceId","emailAddress","sub","deviceToken","has","append","clone","response","applyServerFlagsFromResponse","retry","get","delete","requestEx","canHandleError","status","getRefreshToken","refreshAuthToken","add","fetch","publish","json","responseJSON","grant_type","engine","events","scopes","Map","loadRoute","router","instruction","settings","undefined","configureScope","Error","moduleId","test","container","createChild","registerSingleton","getChildRouter","registerHandler","childRouter","cleanup","RouteScopeCleanup","rootRouter","parent","committed","watchNavigation","parentContainer","viewModel","parentModuleId","constructor","context","childContainer","view","viewStrategy","ensureViewModel","component","hasResources","watchUnbind","releaseScope","navigationSubscription","result","active","Set","collectContainers","currentInstruction","scope","unbinding","completed","viewPorts","viewPortInstructions","values","viewPort","childNavigationInstruction","original","unbind","release","call","Promise","resolve","then","error","LogManager","resource","viewModelResource","metadata","create","handlesUnbind","assign","getPrototypeOf","dispose","size","inject","CompositionEngine","EventAggregator","callbacks","disposed","callback","run","push","length","index","hostname","dsn","replaysSessionSampleRate","isProductionEnvironment","replaysOnErrorSampleRate","integrations","beforeSend","event","extra","featureFlags"],"sourceRoot":""}