{"version":3,"file":"app-d5402680.xxxxxxxx.bundle.js","mappings":"ipEAOO,SAASA,EAAiBC,G,MAAjC,OACEA,EAAQC,IACLC,wBACAC,OAAO,wBACPA,OAAO,wBACPA,OAAO,sBACPC,QAAQ,uCACRA,QAAQ,mBACRA,QAAQ,qCACRA,QAAQ,oBACRA,QAAQ,yCACRD,OAAO,4BACPA,OAAO,gCAAqD,SAACE,GAC5DA,EAAOC,KAAK,wCACZD,EAAOE,OAAO,CACZC,QAAS,CACPC,SAAS,GAEXC,cAAe,CACbD,SAAS,GAEXE,aAAc,CACZF,SAAS,GAEXG,cAAe,CACbH,SAAS,IAGf,IACCN,OAAO,gBAAqC,SAAOU,GAAc,qC,iCAUhE,OATMC,EAAU,CAAC,IAAK,QAEtB,EAAAC,iBAAA,iBAAkCD,GAGlCD,EAASG,QAAQf,IAAI,GAId,CAAP,EAAOY,EAASI,MAAM,CACpBC,QAAS,CAEPC,SAAU,iCAEZC,WAAYN,EACZO,IAAK,kBACLC,GAAI,CAAC,cAAe,eAAgB,SAAU,UAAW,cACzDC,UAAW,cACXC,YAAa,KACbC,OAAO,I,UAGVtB,OAAO,gBAAsC,CAC5CuB,aAAY,IACZC,oBAAoB,EACpBC,QAAS,CACPC,MAAO,KAGV1B,OAAO,wCAA8D,CACpE2B,cAAY,KACV,EAAC,gBAAwB,E,KAK3B,aACF9B,EAAQC,IAAIE,OAAO,kBAEvB,C,4gBCzEA,2B,8CAiBA,QAjBiC,OACrB,YAAA4B,aAAV,WACE,MAAO,WACT,EAEU,YAAAC,YAAV,WACE,IAAMC,EAAc,CAAC,oBAAqB,QAAS,WAAY,iBAC/DC,OAAOC,KAAKC,cAAcC,QAAO,SAACC,GAAM,OAACL,EAAYM,SAASD,EAAtB,IAA0BE,KAAI,SAACF,GAAM,OAAAF,aAAaK,WAAWH,EAAxB,IAC7EI,OAAOC,SAASC,KAAO,IAGvBR,aAAaS,QAAQ,QAASC,KAAKC,UAAU,CAAEC,WAAYC,KAAKC,gCAClE,EAEQ,YAAAA,4BAAR,WACE,OAAO,SAA4B,UACrC,EACF,EAjBA,ECAE,SAAsBC,GAAtB,WAAsB,KAAAA,GAAAA,EACpBF,KAAKE,GAAGC,UAAUH,KAAKlB,gBAAgB,SAACsB,GAAY,SAAKrB,YAAYqB,EAAjB,GACtD,ICFK,SAASC,EAAgBH,GAC9B,IAAII,EAAYJ,EAIlB,C,u+CCLO,SAAeK,EAAe,EAAD,G,yCAClCC,EACAC,EACAC,EACAC,G,oBADA,IAAAD,IAAAA,EAAA,QACA,IAAAC,IAAAA,EAAA,SAAWC,GAAoB,WAAIC,SAAQ,SAACC,GAAY,OAAAC,WAAWD,EAAmB,IAAVF,EAApB,GAAzB,G,2CAEtBA,EAAU,E,sBAAGA,GAAWF,GAAW,Y,iBAEvB,O,sBAAA,GAAMF,EAAKQ,MAAMP,I,OAClC,MAAO,CAAP,EADiB,U,OAGjB,G,WAAIG,IAAYF,EACd,MAAM,EAER,SAAMC,EAAQC,I,cAAd,S,oBAR0CA,I,y/CCAzC,SAASK,EAAoBT,EAAkBU,EAA4BhB,GAmEhF,OAlEAM,EAAKW,WAAU,SAAC/D,GACdA,EAAOgE,gBAAgB,CACfC,QAAO,SAACA,G,6EAaZ,OAZMC,EAAQJ,EAAaK,eAC3BF,EAAQG,QAAQC,OAAO,gBAAiB,UAAYH,GAChDJ,EAAaQ,eACfL,EAAQG,QAAQC,OAAO,cAAeP,EAAaQ,eAEjDJ,IACIK,GAAe,QAASL,GAAOM,KAC/BC,GAAc,OAAsBF,KAExCN,EAAQG,QAAQC,OAAO,iBAAkBI,IAGtC,CAAP,EAAOR,E,QAEHS,SAAQ,SAACA,EAAoBT,G,qGACT,MAApBS,EAASC,OAAT,Y,iBAII,O,sBAAA,IAAM,OAAab,I,cAAnB,SACiB,GAAMX,EAAeC,EAAMsB,EAASrB,MADrD,M,OAEF,MAAO,CAAP,EADmB,U,OAEVP,GACTA,EAAG8B,QAAQ,a,oDAGT9B,GACFA,EAAG8B,QAAQ,a,wCAGc,MAApBF,EAASC,OAAT,OAEL7B,GACFA,EAAG8B,QAAQ,a,kBAEgB,MAApBF,EAASC,OAAT,aAGHE,EAAgBH,EAASI,QAC3BC,EAAoB,K,mBAEP,O,yBAAA,GAAMF,EAAcG,Q,eAAnCD,EAAe,S,+BAEfA,EAAe,K,sBAGjB,OAAyBL,GAErBK,GAAgBA,EAAaE,YACR,CAAC,wBAAyB,iBAAkB,mBAChD/C,SAAS6C,EAAaE,aACvCnC,EAAG8B,QAAQ,a,eAGc,MAApBF,EAASC,SAClB,OAAyBD,G,mBAG3B,MAAO,CAAP,EAAOA,G,SAGb,IAEOtB,CACT,C,4BCnE2C8B,E,uBAIP7C,OAAOC,SAASC,KAXvCL,SAAS,eAepB,QAAK,CACHiD,IAJc,4EAMdC,0BAXuCF,EAWc7C,OAAOC,SAAS4C,SAflE,SAAiCA,GACtC,OAAQA,EAAShD,SAAS,IAC5B,CAGSmD,CAAwBH,GAAY,IAAO,GAWhDI,yBAA0B,EAC1BC,aAAc,CAAC,IAAI,KACnBC,WAAU,SAACC,GAGT,OAFAA,EAAMC,MAAQD,EAAMC,OAAS,CAAC,EAC9BD,EAAMC,MAAMC,aAAetD,OAAOsD,aAC3BF,CACT,G","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 { initialState } from 'store/state';\r\nimport { Aurelia, PLATFORM } from 'aurelia-framework';\r\nimport { I18N, TCustomAttribute } from 'aurelia-i18n';\r\nimport * as Backend from 'i18next-xhr-backend';\r\nimport { environment } from 'environment';\r\nimport { FeatureFlag } from 'feature-flags';\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('document-analyser/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', // <-- 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: {\r\n [FeatureFlag.christmas]: false,\r\n // Add other default flags as needed\r\n }\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 { 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 = ['ia_recent_clients', 'theme', 'deviceId', 'device_tokens'];\r\n Object.keys(localStorage).filter((x) => !itemsToKeep.includes(x)).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 { TokenService } from 'resources/services/token-service';\r\nimport { HttpClient } from 'aurelia-fetch-client';\r\nimport { fetchWithRetry } from './fetch-with-retry';\r\nimport { parseJwt } from 'resources/parse-jwt';\r\nimport { getDeviceTokenForUser } from 'resources/device-token-manager';\r\nimport { httpErrorResponseHandler } from 'resources/utilities/api-error-handler';\r\nimport { renewSession } from 'resources/services/sso-renewal';\r\n\r\nexport function configureHttpClient(http: HttpClient, tokenService: TokenService, ea: EventAggregator) {\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 if (response.status === 401) {\r\n try {\r\n // SSO sessions renew via MSAL silently (re-validating against Entra), password sessions via the\r\n // refresh token - renewSession picks the right path and only returns false when none worked\r\n if (await renewSession(tokenService)) {\r\n const retry: any = await fetchWithRetry(http, response.url);\r\n return retry;\r\n } else if (ea) {\r\n ea.publish('ia-logout');\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 let responseJSON: any = null;\r\n try {\r\n responseJSON = await responseClone.json();\r\n } catch {\r\n responseJSON = null;\r\n }\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","use","standardConfiguration","plugin","feature","config","init","attach","logging","enabled","logForwarding","pageTracking","clickTracking","instance","aliases","TCustomAttribute","i18next","setup","backend","loadPath","attributes","lng","ns","defaultNS","fallbackLng","debug","initialState","measurePerformance","history","limit","defaultFlags","getEventName","handleEvent","itemsToKeep","Object","keys","localStorage","filter","x","includes","map","removeItem","window","location","href","setItem","JSON","stringify","lastLogout","this","generateLastLogoutDebugInfo","ea","subscribe","data","configureEvents","LogoutEvent","fetchWithRetry","http","url","maxAttempts","delayFn","attempt","Promise","resolve","setTimeout","fetch","configureHttpClient","tokenService","configure","withInterceptor","request","token","getAuthToken","headers","append","getDeviceId","emailAddress","sub","deviceToken","response","status","publish","responseClone","clone","responseJSON","json","grant_type","hostname","dsn","replaysSessionSampleRate","isProductionEnvironment","replaysOnErrorSampleRate","integrations","beforeSend","event","extra","featureFlags"],"sourceRoot":""}