From 3f8f86b2a7b071da387499c8d59370f24f22ec48 Mon Sep 17 00:00:00 2001 From: codaimaster <55559010+codaimaster@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:31:46 +0100 Subject: [PATCH] Revert "Remove App Insights agent from client bundle (#3243)" This reverts commit 4a07811d5d3397bfd68f4b74c989ae4dc6b21fba. --- .gitignore | 1 - .../xui-webapp/values.preview.template.yaml | 2 +- package.json | 2 + src/app/app.module.ts | 9 +- src/app/services/logger/appInsightsWrapper.ts | 100 ++++++++++++++++ .../services/logger/logger.service.spec.ts | 30 +++-- src/app/services/logger/logger.service.ts | 25 +++- .../logger/monitoring.service.spec.ts | 60 ++++++++++ src/app/services/logger/monitoring.service.ts | 107 ++++++++++++++++++ yarn.lock | 16 +++ 10 files changed, 333 insertions(+), 19 deletions(-) create mode 100644 src/app/services/logger/appInsightsWrapper.ts create mode 100644 src/app/services/logger/monitoring.service.spec.ts create mode 100644 src/app/services/logger/monitoring.service.ts diff --git a/.gitignore b/.gitignore index c64a1ab51d..795a0ab2f8 100644 --- a/.gitignore +++ b/.gitignore @@ -92,4 +92,3 @@ ignore/ !.yarn/versions /infrastructure/.terraform/ -/.angular/cache/ diff --git a/charts/xui-webapp/values.preview.template.yaml b/charts/xui-webapp/values.preview.template.yaml index 98dd82e508..130e2808c7 100644 --- a/charts/xui-webapp/values.preview.template.yaml +++ b/charts/xui-webapp/values.preview.template.yaml @@ -23,7 +23,7 @@ nodejs: SERVICES_CASE_JUDICIAL_API: http://rd-judicial-api-aat.service.core-compute-aat.internal SERVICES_LOCATION_REF_API_URL: http://rd-location-ref-api-aat.service.core-compute-aat.internal FEATURE_ACCESS_MANAGEMENT_ENABLED: true - PREVIEW_DEPLOYMENT_ID: exui-preview-deployment-3243 + PREVIEW_DEPLOYMENT_ID: exui-preview-deployment-3230 keyVaults: rpx: secrets: diff --git a/package.json b/package.json index 513b198965..41a3b94c1a 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "@nicky-lenaers/ngx-scroll-to": "^1.1.1", "accessibility-checker": "^3.0.6", "applicationinsights": "1.7.2", + "applicationinsights-js": "^1.0.20", "axios": "^0.21.1", "axios-mock-adapter": "^1.18.2", "class-transformer": "^0.3.2", @@ -174,6 +175,7 @@ "@stryker-mutator/karma-runner": "^3.0.1", "@stryker-mutator/mocha-runner": "^3.0.1", "@stryker-mutator/typescript": "^3.0.1", + "@types/applicationinsights-js": "^1.0.9", "@types/config": "^0.0.36", "@types/cookie-parser": "^1.4.2", "@types/crypto-js": "^3.1.43", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f363579565..24c3757af5 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -55,8 +55,10 @@ import { AcceptTermsService } from './services/acceptTerms/acceptTerms.service'; import { CaseShareService } from './services/case/share-case.service'; import { DefaultErrorHandler } from './services/errorHandler/defaultErrorHandler'; import { JurisdictionService } from './services/jurisdiction/jurisdiction.service'; +import { AbstractAppInsights, AppInsightsWrapper } from './services/logger/appInsightsWrapper'; import { CryptoWrapper } from './services/logger/cryptoWrapper'; import { LoggerService } from './services/logger/logger.service'; +import { MonitoringService } from './services/logger/monitoring.service'; import { SharedModule } from './shared/shared.module'; import { effects } from './store/effects'; // ngrx modules - END @@ -123,7 +125,12 @@ export function launchDarklyClientIdFactory( multi: true }, CryptoWrapper, + MonitoringService, LoggerService, + { + provide: AbstractAppInsights, + useClass: AppInsightsWrapper + }, { provide: ErrorHandler, useClass: DefaultErrorHandler @@ -143,4 +150,4 @@ export function launchDarklyClientIdFactory( bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) -export class AppModule { } +export class AppModule {} diff --git a/src/app/services/logger/appInsightsWrapper.ts b/src/app/services/logger/appInsightsWrapper.ts new file mode 100644 index 0000000000..dbea39ddbc --- /dev/null +++ b/src/app/services/logger/appInsightsWrapper.ts @@ -0,0 +1,100 @@ +import { AppInsights } from 'applicationinsights-js'; + +export abstract class AbstractAppInsights implements Microsoft.ApplicationInsights.IAppInsights { + public config: Microsoft.ApplicationInsights.IConfig; public context: Microsoft.ApplicationInsights.ITelemetryContext; + public queue: (() => void)[]; + public abstract startTrackPage(name?: string); + public abstract stopTrackPage(name?: string, url?: string, properties?: { [name: string]: string; }, + measurements?: { [name: string]: number; }); + + public abstract trackPageView(name?: string, url?: string, properties?: { [name: string]: string; }, + measurements?: { [name: string]: number; }, duration?: number); + + public abstract startTrackEvent(name: string); + public abstract stopTrackEvent(name: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }); + public abstract trackEvent(name: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }); + public abstract trackDependency(id: string, method: string, absoluteUrl: string, pathName: string, totalTime: number, + success: boolean, resultCode: number, + properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }); + + public abstract trackException(exception: Error, handledAt?: string, + properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }, + severityLevel?: AI.SeverityLevel); + + public abstract trackMetric(name: string, average: number, sampleCount?: number, min?: number, max?: number, + properties?: { [name: string]: string; }); + + public abstract trackTrace(message: string, properties?: { [name: string]: string; }, severityLevel?: AI.SeverityLevel) ; + public abstract flush(); + public abstract setAuthenticatedUserContext(authenticatedUserId: string, accountId?: string, storeInCookie?: boolean); + public abstract clearAuthenticatedUserContext(); + public abstract downloadAndSetup?(config: Microsoft.ApplicationInsights.IConfig); + public abstract _onerror(message: string, url: string, lineNumber: number, columnNumber: number, error: Error); +} + +export class AppInsightsWrapper implements AbstractAppInsights { + public config: Microsoft.ApplicationInsights.IConfig; public context: Microsoft.ApplicationInsights.ITelemetryContext; + public queue: (() => void)[]; + public startTrackPage(name?: string) { + AppInsights.startTrackPage(name); + } + + public stopTrackPage(name?: string, url?: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }) { + AppInsights.stopTrackPage(name, url, properties, measurements); + } + + public trackPageView(name?: string, url?: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }, + duration?: number) { + AppInsights.trackPageView(name, url, properties, measurements, duration); + } + + public startTrackEvent(name: string) { + AppInsights.startTrackEvent(name); + } + + public stopTrackEvent(name: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }) { + AppInsights.stopTrackEvent(name, properties, measurements); + } + + public trackEvent(name: string, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }) { + AppInsights.trackEvent(name, properties, measurements); + } + + public trackDependency(id: string, method: string, absoluteUrl: string, pathName: string, totalTime: number, success: boolean, + resultCode: number, properties?: { [name: string]: string; }, measurements?: { [name: string]: number; }) { + AppInsights.trackDependency(id, method, absoluteUrl, pathName, totalTime, success, resultCode, properties, measurements); + } + + public trackException(exception: Error, handledAt?: string, properties?: { [name: string]: string; }, + measurements?: { [name: string]: number; }, severityLevel?: AI.SeverityLevel) { + AppInsights.trackException(exception, handledAt, properties, measurements, severityLevel); + } + + public trackMetric(name: string, average: number, sampleCount?: number, min?: number, max?: number, properties?: { [name: string]: string; }) { + AppInsights.trackMetric(name, average, sampleCount, min, max, properties); + } + + public trackTrace(message: string, properties?: { [name: string]: string; }, severityLevel?: AI.SeverityLevel) { + AppInsights.trackTrace(message, properties, severityLevel); + } + + public flush() { + AppInsights.flush(); + } + + public setAuthenticatedUserContext(authenticatedUserId: string, accountId?: string, storeInCookie?: boolean) { + AppInsights.setAuthenticatedUserContext(authenticatedUserId, accountId, storeInCookie); + } + + public clearAuthenticatedUserContext() { + AppInsights.clearAuthenticatedUserContext(); + } + + public downloadAndSetup(config: Microsoft.ApplicationInsights.IConfig) { + AppInsights.downloadAndSetup(config); + } + + public _onerror(message: string, url: string, lineNumber: number, columnNumber: number, error: Error) { + AppInsights._onerror(message, url, lineNumber, columnNumber, error); + } +} diff --git a/src/app/services/logger/logger.service.spec.ts b/src/app/services/logger/logger.service.spec.ts index 1264f75129..198e86fdba 100644 --- a/src/app/services/logger/logger.service.spec.ts +++ b/src/app/services/logger/logger.service.spec.ts @@ -1,6 +1,7 @@ import { LoggerService } from './logger.service'; describe('Logger service', () => { + const mockedMonitoringService = jasmine.createSpyObj('mockedMonitoringService', ['logEvent', 'logException', 'enableCookies']); const mockedNgxLogger = jasmine.createSpyObj('mockedNgxLogger', ['trace', 'debug', 'info', 'log', 'warn', 'error', 'fatal']); const mockedSessionStorageService = jasmine.createSpyObj('mockedCookieService', ['getItem']); @@ -11,74 +12,83 @@ describe('Logger service', () => { mockEnvironmentService.config$ = mockConfig; it('should be Truthy', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); expect(service).toBeTruthy(); }); it('should be able to call info', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.info('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); expect(mockedNgxLogger.info).toHaveBeenCalled(); }); it('should be able to call log', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.log('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); expect(mockedNgxLogger.log).toHaveBeenCalled(); }); it('should be able to call warn', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.warn('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); expect(mockedNgxLogger.warn).toHaveBeenCalled(); }); it('should be able to call error', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.error('message'); + expect(mockedMonitoringService.logException).toHaveBeenCalled(); expect(mockedNgxLogger.error).toHaveBeenCalled(); }); it('should be able to call fatal', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.fatal('message'); + expect(mockedMonitoringService.logException).toHaveBeenCalled(); expect(mockedNgxLogger.fatal).toHaveBeenCalled(); }); it('should be able to call debug', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.debug('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); }); it('should be able to call trace', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.trace('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); expect(mockedNgxLogger.trace).toHaveBeenCalled(); }); it('should be able to get a message', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); // slice off the last two characters of string to ensure no accidental discrepancies const expectedMessage = `Message - message, Timestamp - ${Date.now()}`.slice(0, -2); const returnedMessage = service.getMessage('message'); + expect(mockedMonitoringService.logEvent).toHaveBeenCalled(); expect(returnedMessage).not.toBeNull(); expect(returnedMessage.slice(0, -2)).toBe(expectedMessage); }); describe('enableCookies()', () => { it('should make a call to monitoringService', () => { - const service = new LoggerService(mockedNgxLogger, mockedSessionStorageService, + const service = new LoggerService(mockedMonitoringService, mockedNgxLogger, mockedSessionStorageService, mockedCryptoWrapper, mockEnvironmentService); service.enableCookies(); + expect(mockedMonitoringService.enableCookies).toHaveBeenCalled(); }); }); diff --git a/src/app/services/logger/logger.service.ts b/src/app/services/logger/logger.service.ts index 4bacdfcf9e..ccb1a85085 100644 --- a/src/app/services/logger/logger.service.ts +++ b/src/app/services/logger/logger.service.ts @@ -4,6 +4,7 @@ import { environment as config } from '../../../environments/environment'; import { UserInfo } from '../../models/user-details.model'; import { SessionStorageService } from '../session-storage/session-storage.service'; import { CryptoWrapper } from './cryptoWrapper'; +import { MonitoringService } from './monitoring.service'; import { EnvironmentService } from '../../shared/services/environment.service'; export interface ILoggerService { @@ -25,10 +26,11 @@ export class LoggerService implements ILoggerService { // Do nothing. }; - constructor(private readonly ngxLogger: NGXLogger, - private readonly sessionStorageService: SessionStorageService, - private readonly cryptoWrapper: CryptoWrapper, - private readonly environmentService: EnvironmentService) { + constructor(private readonly monitoringService: MonitoringService, + private readonly ngxLogger: NGXLogger, + private readonly sessionStorageService: SessionStorageService, + private readonly cryptoWrapper: CryptoWrapper, + private readonly environmentService: EnvironmentService) { this.COOKIE_KEYS = { TOKEN: config.cookies.token, USER: config.cookies.userId @@ -44,43 +46,54 @@ export class LoggerService implements ILoggerService { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - public trace(message: any, ...additional: any[]): void { + public trace(message: any, ... additional: any[]): void { const formattedMessage = this.getMessage(message); this.ngxLogger.trace(formattedMessage); + this.monitoringService.logEvent(message); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public debug(message: any, ...additional: any[]): void { const formattedMessage = this.getMessage(message); this.ngxLogger.debug(formattedMessage); + this.monitoringService.logEvent(message); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public info(message: any, ...additional: any[]): void { const formattedMessage = this.getMessage(message); this.ngxLogger.info(formattedMessage); + this.monitoringService.logEvent(message); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public log(message: any, ...additional: any[]): void { const formattedMessage = this.getMessage(message); this.ngxLogger.log(formattedMessage, ...additional); + this.monitoringService.logEvent(message); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public warn(message: any, ...additional: any[]): void { const formattedMessage = this.getMessage(message); this.ngxLogger.warn(formattedMessage); + this.monitoringService.logEvent(message); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public error(message: any, ...additional: any[]): void { this.ngxLogger.error(message); + const formattedMessage = this.getMessage(message); + const error = new Error(formattedMessage); + this.monitoringService.logException(error); } // eslint-disable-next-line @typescript-eslint/no-unused-vars public fatal(message: any, ...additional: any[]): void { this.ngxLogger.fatal(message); + const formattedMessage = this.getMessage(message); + const error = new Error(formattedMessage); + this.monitoringService.logException(error); } public getMessage(message: any): string { @@ -96,7 +109,7 @@ export class LoggerService implements ILoggerService { } public enableCookies(): void { - // do nothing. + this.monitoringService.enableCookies(); } public static switchConsoleLogs(consoleConfig: any): void { diff --git a/src/app/services/logger/monitoring.service.spec.ts b/src/app/services/logger/monitoring.service.spec.ts new file mode 100644 index 0000000000..0281bf17b4 --- /dev/null +++ b/src/app/services/logger/monitoring.service.spec.ts @@ -0,0 +1,60 @@ +import { of } from 'rxjs'; +import { MonitorConfig, MonitoringService } from './monitoring.service'; + +describe('Monitoring service', () => { + const mockedHttpClient = jasmine.createSpyObj('mockedHttpClient', { get: of({ key: 'Some Value' }) }); + const mockedAppInsights = jasmine.createSpyObj('mockedAppInsights', ['downloadAndSetup', 'trackException', 'trackEvent', + 'trackPageView']); + const mockedConfig = new MonitorConfig(); + + it('should be Truthy', () => { + const service = new MonitoringService(mockedHttpClient); + expect(service).toBeTruthy(); + }); + + it('should be able to LogException and Should not call the http service', () => { + mockedConfig.instrumentationKey = 'somevalue'; + const service = new MonitoringService(mockedHttpClient, mockedConfig, mockedAppInsights); + expect(service).toBeTruthy(); + service.logException(new Error('Some ErrorMesssage')); + expect(mockedHttpClient.get).not.toHaveBeenCalled(); + expect(mockedAppInsights.downloadAndSetup).not.toHaveBeenCalled(); + expect(mockedAppInsights.trackException).toHaveBeenCalled(); + }); + + it('should be able to LogEvent', () => { + mockedConfig.instrumentationKey = 'somevalue'; + const service = new MonitoringService(mockedHttpClient, mockedConfig, mockedAppInsights); + expect(service).toBeTruthy(); + service.logEvent('name', [], []); + expect(mockedHttpClient.get).not.toHaveBeenCalled(); + expect(mockedAppInsights.downloadAndSetup).not.toHaveBeenCalled(); + expect(mockedAppInsights.trackEvent).toHaveBeenCalled(); + }); + + it('should be able to LogPageview', () => { + mockedConfig.instrumentationKey = 'somevalue'; + const service = new MonitoringService(mockedHttpClient, mockedConfig, mockedAppInsights); + expect(service).toBeTruthy(); + service.logPageView('name', null, [], [], 1); + expect(mockedHttpClient.get).not.toHaveBeenCalled(); + expect(mockedAppInsights.downloadAndSetup).not.toHaveBeenCalled(); + expect(mockedAppInsights.trackPageView).toHaveBeenCalled(); + }); + + it('should be able to LogPageview', () => { + mockedConfig.instrumentationKey = null; + const service = new MonitoringService(mockedHttpClient, mockedConfig, mockedAppInsights); + expect(service).toBeTruthy(); + service.logPageView('name', null, [], [], 1); + expect(mockedHttpClient.get).toHaveBeenCalled(); + }); + + describe('enableCookies()', () => { + it('should set areCookiesEnabled to true', () => { + const service = new MonitoringService(mockedHttpClient, mockedConfig, mockedAppInsights); + service.enableCookies(); + expect(service.areCookiesEnabled).toBeTruthy(); + }); + }); +}); diff --git a/src/app/services/logger/monitoring.service.ts b/src/app/services/logger/monitoring.service.ts new file mode 100644 index 0000000000..b4b1ce9305 --- /dev/null +++ b/src/app/services/logger/monitoring.service.ts @@ -0,0 +1,107 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable, Optional } from '@angular/core'; +import { AppInsights } from 'applicationinsights-js'; +import { AbstractAppInsights } from './appInsightsWrapper'; + +export interface IMonitoringService { + logPageView(name?: string, url?: string, properties?: any, + measurements?: any, duration?: number); + logEvent(name: string, properties?: any, measurements?: any); + logException(exception: Error); +} + +export class MonitorConfig implements Microsoft.ApplicationInsights.IConfig { + public instrumentationKey?: string; + public endpointUrl?: string; + public emitLineDelimitedJson?: boolean; + public accountId?: string; + public sessionRenewalMs?: number; + public sessionExpirationMs?: number; + public maxBatchSizeInBytes?: number; + public maxBatchInterval?: number; + public enableDebug?: boolean; + public disableExceptionTracking?: boolean; + public disableTelemetry?: boolean; + public verboseLogging?: boolean; + public diagnosticLogInterval?: number; + public samplingPercentage?: number; + public autoTrackPageVisitTime?: boolean; + public disableAjaxTracking?: boolean; + public overridePageViewDuration?: boolean; + public maxAjaxCallsPerView?: number; + public disableDataLossAnalysis?: boolean; + public disableCorrelationHeaders?: boolean; + public correlationHeaderExcludedDomains?: string[]; + public disableFlushOnBeforeUnload?: boolean; + public enableSessionStorageBuffer?: boolean; + public isCookieUseDisabled?: boolean; + public cookieDomain?: string; + public isRetryDisabled?: boolean; + public url?: string; + public isStorageUseDisabled?: boolean; + public isBeaconApiDisabled?: boolean; + public sdkExtension?: string; + public isBrowserLinkTrackingEnabled?: boolean; + public appId?: string; + public enableCorsCorrelation?: boolean; +} + +@Injectable() +export class MonitoringService implements IMonitoringService { + public areCookiesEnabled: boolean = false; + + constructor(private readonly http: HttpClient, @Optional() private config?: MonitorConfig, + @Optional() private readonly appInsights?: AbstractAppInsights) { + if (!appInsights) { + appInsights = AppInsights; + } + } + + public logPageView(name?: string, url?: string, properties?: any, + measurements?: any, duration?: number) { + this.send(() => { + this.appInsights.trackPageView(name, url, properties, measurements, duration); + }); + } + + public logEvent(name: string, properties?: any, measurements?: any) { + this.send(() => { + this.appInsights.trackEvent(name, properties, measurements); + }); + } + + public logException(exception: Error) { + this.send(() => { + this.appInsights.trackException(exception); + }); + } + + public enableCookies() { + this.areCookiesEnabled = true; + } + + private send(func: () => any): void { + if (this.config && this.config.instrumentationKey) { + func(); + } else { + this.http.get('/api/monitoring-tools').subscribe((it) => { + this.config = { + // eslint-disable-next-line dot-notation + instrumentationKey: it['key'] + }; + if (!this.areCookiesEnabled) { + this.config = { + ...this.config, + isCookieUseDisabled: true, + isStorageUseDisabled: true, + enableSessionStorageBuffer: true + }; + } + if (!this.appInsights.config) { + this.appInsights.downloadAndSetup(this.config); + } + func(); + }); + } + } +} diff --git a/yarn.lock b/yarn.lock index a8709c90a7..4e118b3f78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3579,6 +3579,13 @@ __metadata: languageName: node linkType: hard +"@types/applicationinsights-js@npm:^1.0.9": + version: 1.0.9 + resolution: "@types/applicationinsights-js@npm:1.0.9" + checksum: 642b3ba588253a3fa3cd32452e8eb99258057b8f7c99014f0006a707c858053f0d465dec1c727d47c646649343a88bab615d031e571a175aa6ccf743f8681b88 + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.1.19 resolution: "@types/babel__core@npm:7.1.19" @@ -5053,6 +5060,13 @@ __metadata: languageName: node linkType: hard +"applicationinsights-js@npm:^1.0.20": + version: 1.0.21 + resolution: "applicationinsights-js@npm:1.0.21" + checksum: a9c50f469f75d6aa571012c7d7bf4161a60da8f6e8c81bf2f6e575486455d0711762cfca788102e08f2c168968c96c93d3a8fe13d63bfd6cf09584d0e8310439 + languageName: node + linkType: hard + "applicationinsights@npm:1.7.2": version: 1.7.2 resolution: "applicationinsights@npm:1.7.2" @@ -19281,6 +19295,7 @@ __metadata: "@stryker-mutator/karma-runner": ^3.0.1 "@stryker-mutator/mocha-runner": ^3.0.1 "@stryker-mutator/typescript": ^3.0.1 + "@types/applicationinsights-js": ^1.0.9 "@types/config": ^0.0.36 "@types/cookie-parser": ^1.4.2 "@types/crypto-js": ^3.1.43 @@ -19300,6 +19315,7 @@ __metadata: "@typescript-eslint/parser": ^5.57.0 accessibility-checker: ^3.0.6 applicationinsights: 1.7.2 + applicationinsights-js: ^1.0.20 axios: ^0.21.1 axios-mock-adapter: ^1.18.2 base-64: ^0.1.0