From 812b4ee6cbc1926edf2a14dd5c05cdeccd4d1e19 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Thu, 2 May 2024 15:46:28 -0700 Subject: [PATCH 01/16] add init with promise --- .aiAutoMinify.json | 1 + AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 8 +- .../Unit/src/applicationinsights.e2e.tests.ts | 111 ++- AISKU/src/AISku.ts | 47 +- .../src/Sender.ts | 28 +- common/config/rush/npm-shrinkwrap.json | 599 +++++++++------ .../Unit/src/AppInsightsCoreSize.Tests.ts | 4 +- .../Unit/src/ApplicationInsightsCore.Tests.ts | 719 +++++++++++++++++- .../InitActiveStatusEnum.ts | 30 + .../IAppInsightsCore.ts | 19 + .../IConfiguration.ts | 22 +- .../src/JavaScriptSDK/AppInsightsCore.ts | 163 +++- .../src/applicationinsights-core-js.ts | 1 + 13 files changed, 1454 insertions(+), 298 deletions(-) create mode 100644 shared/AppInsightsCore/src/JavaScriptSDK.Enums/InitActiveStatusEnum.ts diff --git a/.aiAutoMinify.json b/.aiAutoMinify.json index aa6199cf1..cca95219e 100644 --- a/.aiAutoMinify.json +++ b/.aiAutoMinify.json @@ -8,6 +8,7 @@ "eBatchDiscardedReason", "FeatureOptInMode", "CdnFeatureMode", + "eActiveStatus", "eLoggingSeverity", "_eInternalMessageId", "SendRequestReason", diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index 2cebc91b2..1b5e96817 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -5,10 +5,10 @@ import { Snippet } from "../../../src/Snippet"; import { utlRemoveSessionStorage } from "@microsoft/applicationinsights-common"; export class AISKUSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 140; - private readonly MAX_BUNDLE_SIZE = 140; - private readonly MAX_RAW_DEFLATE_SIZE = 56; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 56; + private readonly MAX_RAW_SIZE = 142; + private readonly MAX_BUNDLE_SIZE = 142; + private readonly MAX_RAW_DEFLATE_SIZE = 57; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 57; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; // Automatically updated by version scripts private readonly currentVer = "3.1.2"; diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index f724bbab7..aabf7a302 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -3,8 +3,9 @@ import { SinonSpy } from 'sinon'; import { ApplicationInsights } from '../../../src/applicationinsights-web' import { Sender } from '@microsoft/applicationinsights-channel-js'; import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig } from '@microsoft/applicationinsights-common'; -import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration } from "@microsoft/applicationinsights-core-js"; +import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus } from "@microsoft/applicationinsights-core-js"; import { TelemetryContext } from '@microsoft/applicationinsights-properties-js'; +import { createAsyncResolvedPromise, createResolvedPromise } from '@nevware21/ts-async'; export class ApplicationInsightsTests extends AITestClass { @@ -43,6 +44,7 @@ export class ApplicationInsightsTests extends AITestClass { private tagKeys = new ContextTagKeys(); private _config; private _appId: string; + private ctx: any; constructor(testName?: string) { super(testName || "ApplicationInsightsTests"); @@ -73,6 +75,7 @@ export class ApplicationInsightsTests extends AITestClass { this.isFetchPolyfill = fetch["polyfill"]; this.useFakeServer = false; this._config = this._getTestConfig(this._sessionPrefix); + this.ctx = {}; const init = new ApplicationInsights({ config: this._config @@ -129,18 +132,19 @@ export class ApplicationInsightsTests extends AITestClass { if (this._ai && this._ai["dependencies"]) { this._ai["dependencies"].teardown(); } + this.ctx = {}; console.log("* testCleanup(" + (AITestClass.currentTestInfo ? AITestClass.currentTestInfo.name : "") + ")"); } public registerTests() { this.addDynamicConfigTests() - this.addGenericE2ETests(); - this.addAnalyticsApiTests(); - this.addAsyncTests(); - this.addDependencyPluginTests(); - this.addPropertiesPluginTests(); - this.addCDNOverrideTests(); + // this.addGenericE2ETests(); + // this.addAnalyticsApiTests(); + // this.addAsyncTests(); + // this.addDependencyPluginTests(); + // this.addPropertiesPluginTests(); + // this.addCDNOverrideTests(); } public addGenericE2ETests(): void { @@ -240,6 +244,99 @@ export class ApplicationInsightsTests extends AITestClass { handler.rm(); } }); + + this.testCaseAsync({ + name: "Init: init with cs promise, change with cs string", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + + // unload previous one first + let oriInst = this._ai; + if (oriInst && oriInst.unload) { + // force unload + oriInst.unload(false); + } + + if (oriInst && oriInst["dependencies"]) { + oriInst["dependencies"].teardown(); + } + + this._config = this._getTestConfig(this._sessionPrefix); + let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); + this._config.connectionString = csPromise; + + + let init = new ApplicationInsights({ + config: this._config + }); + init.loadAppInsights(); + this._ai = init; + let config = this._ai.config; + let core = this._ai.core; + let status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); + + + config.connectionString = "InstrumentationKey=testIkey1;ingestionendpoint=testUrl1" + this.clock.tick(1); + status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending test1"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._ai.core + let activeStatus = core.activeStatus && core.activeStatus(); + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey"; + core.config.endpointUrl = "testUrl"; + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + + + this.testCaseAsync({ + name: "Init: init with cs string, change with cs promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let config = this._ai.config; + let expectedIkey = ApplicationInsightsTests._instrumentationKey; + let expectedConnectionString = ApplicationInsightsTests._connectionString; + let expectedEndpointUrl = "https://dc.services.visualstudio.com/v2/track"; + Assert.ok(config, "ApplicationInsights config exists"); + Assert.equal(expectedConnectionString, config.connectionString, "connection string is set"); + Assert.equal(expectedIkey, config.instrumentationKey, "ikey is set"); + Assert.equal(expectedEndpointUrl, config.endpointUrl, "endpoint url is set from connection string"); + let core = this._ai.core; + let status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.ACTIVE, "status should be set to active"); + + let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); + + config.connectionString = csPromise; + this.clock.tick(1); + status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._ai.core + let activeStatus = core.activeStatus && core.activeStatus(); + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey"; + core.config.endpointUrl = "testUrl"; + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + } public addCDNOverrideTests(): void { diff --git a/AISKU/src/AISku.ts b/AISKU/src/AISku.ts index 58646a1f0..69af45080 100644 --- a/AISKU/src/AISku.ts +++ b/AISKU/src/AISku.ts @@ -26,8 +26,8 @@ import { IDependencyListenerHandler } from "@microsoft/applicationinsights-dependencies-js"; import { PropertiesPlugin } from "@microsoft/applicationinsights-properties-js"; -import { IPromise, createPromise } from "@nevware21/ts-async"; -import { arrForEach, arrIndexOf, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils"; +import { IPromise, createAsyncPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async"; +import { arrForEach, arrIndexOf, isPromiseLike, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils"; import { IApplicationInsights } from "./IApplicationInsights"; import { STR_ADD_TELEMETRY_INITIALIZER, STR_CLEAR_AUTHENTICATED_USER_CONTEXT, STR_EVT_NAMESPACE, STR_GET_COOKIE_MGR, STR_GET_PLUGIN, @@ -194,8 +194,47 @@ export class AppInsightsSku implements IApplicationInsights { // Will get recalled if any referenced values are changed _addUnloadHook(onConfigChange(cfgHandler, () => { - if (_config.connectionString) { - const cs = parseConnectionString(_config.connectionString); + let configCs = _config.connectionString; + + if (isPromiseLike(configCs)) { + let ikeyPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(configCs, (res) => { + let curCs = res.value; + let ikey = _config.instrumentationKey; + if (!res.rejected && curCs) { + // replace cs with resolved values in case of circular promises + _config.connectionString = curCs; + let resolvedCs = parseConnectionString(curCs); + ikey = resolvedCs.instrumentationkey || ikey; + } + resolve(ikey); + }); + + }); + + let urlPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(configCs, (res) => { + let curCs = res.value; + let url = _config.endpointUrl; + if (!res.rejected && curCs) { + let resolvedCs = parseConnectionString(curCs); + let ingest = resolvedCs.ingestionendpoint; + url = ingest? ingest + DEFAULT_BREEZE_PATH : url; + } + resolve(url); + }); + + }); + + _config.instrumentationKey = ikeyPromise; + _config.endpointUrl = _config.userOverrideEndpointUrl || urlPromise; + + } + if (isString(configCs)) { + // confirm if promiselike function present + // handle cs promise here + // add cases to oneNote + const cs = parseConnectionString(configCs); const ingest = cs.ingestionendpoint; _config.endpointUrl = _config.userOverrideEndpointUrl ? _config.userOverrideEndpointUrl : ingest + DEFAULT_BREEZE_PATH; // add /v2/track _config.instrumentationKey = cs.instrumentationkey || _config.instrumentationKey; diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 310237a78..cd7dc07d6 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -5,16 +5,17 @@ import { createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, utlCanUseSessionStorage, utlSetStoragePrefix } from "@microsoft/applicationinsights-common"; import { - BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, - IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext, - ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, - SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, - _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, - eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, getExceptionName, getIEVersion, isArray, isBeaconsSupported, - isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload + ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, + IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, + IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride, + OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, + _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, + createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, getExceptionName, getIEVersion, + isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, + prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; -import { ITimerHandler, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils"; +import { ITimerHandler, isString, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils"; import { DependencyEnvelopeCreator, EventEnvelopeCreator, ExceptionEnvelopeCreator, MetricEnvelopeCreator, PageViewEnvelopeCreator, PageViewPerformanceEnvelopeCreator, TraceEnvelopeCreator @@ -240,7 +241,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (_self.isInitialized()) { _throwInternal(_self.diagLog(), eLoggingSeverity.CRITICAL, _eInternalMessageId.SenderNotInitialized, "Sender is already initialized"); } - + + _base.initialize(config, core, extensions, pluginChain); let identifier = _self.identifier; _serializer = new Serializer(core.logger); @@ -268,6 +270,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } }); + if (core.activeStatus() === ActiveStatus.PENDING) { + // waiting for core promises to be resolved + return; + } + + // Only update the endpoint if the original config !== the current config // This is so any redirect endpointUrl is not overwritten if (_orgEndpointUrl !== senderConfig.endpointUrl) { @@ -346,7 +354,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } _customHeaders = senderConfig.customHeaders; - if (!isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) { + if (isString(_endpointUrl) && !isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) { arrForEach(_customHeaders, customHeader => { this.addHeader(customHeader.header, customHeader.value); }); diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 8b0587d0f..4c642994e 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -87,15 +87,6 @@ "uglify-js": "3.16.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -105,19 +96,19 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -286,9 +277,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "peer": true }, "node_modules/@jridgewell/sourcemap-codec": { @@ -297,17 +288,17 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@microsoft/api-extractor": { - "version": "7.43.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", - "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", + "version": "7.43.1", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.1.tgz", + "integrity": "sha512-ohg40SsvFFgzHFAtYq5wKJc8ZDyY46bphjtnSvhSSlXpPTG7GHwyyXkn48UZiUCBwr2WC7TRC1Jfwz7nreuiyQ==", "dependencies": { - "@microsoft/api-extractor-model": "7.28.13", + "@microsoft/api-extractor-model": "7.28.14", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2", + "@rushstack/node-core-library": "4.1.0", "@rushstack/rig-package": "0.5.2", - "@rushstack/terminal": "0.10.0", - "@rushstack/ts-command-line": "4.19.1", + "@rushstack/terminal": "0.10.1", + "@rushstack/ts-command-line": "4.19.2", "lodash": "~4.17.15", "minimatch": "~3.0.3", "resolve": "~1.22.1", @@ -320,13 +311,13 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.13", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", - "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "version": "7.28.14", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.14.tgz", + "integrity": "sha512-Bery/c8A8SsKPSvA82cTTuy/+OcxZbLRmKhPkk91/AJOQzxZsShcrmHFAGeiEqSIrv1nPZ3tKq9kfMLdCHmsqg==", "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2" + "@rushstack/node-core-library": "4.1.0" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { @@ -409,17 +400,17 @@ } }, "node_modules/@nevware21/ts-async": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.4.0.tgz", - "integrity": "sha512-dbV826TTehQIBIJjh8GDSbwn1Z6+cnkyNbRlpcpdBPH8mROD2zabIUKqWcw9WRdTjjUIm21K+OR4DXWlAyOVTQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.1.tgz", + "integrity": "sha512-O2kN8n2HpDWJ7Oji+oTMnhITrCndmrNvrHbGDwAIBydx+FWvLE/vrw4QwnRRMvSCa2AJrcP59Ryklxv30KfkWQ==", "dependencies": { - "@nevware21/ts-utils": ">= 0.10.0 < 2.x" + "@nevware21/ts-utils": ">= 0.11.2 < 2.x" } }, "node_modules/@nevware21/ts-utils": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.0.tgz", - "integrity": "sha512-3yrohCSKYBLKrW41fYkZorN2rf9GYr/4Cb4Xu9fWCyXgVDyt1uLgMaCinhx0kEkEUfME3Smqs+2itJRhXgCo8Q==" + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.2.tgz", + "integrity": "sha512-80W8BkS09kkGuUHJX50Fqq+QqAslxUaOQytH+3JhRacXs1EpEt2JOOkYKytqFZAYir3SeH9fahniEaDzIBxlUw==" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -533,14 +524,11 @@ } }, "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/@rollup/pluginutils": { @@ -1281,9 +1269,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", - "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.1.0.tgz", + "integrity": "sha512-qz4JFBZJCf1YN5cAXa1dP6Mki/HrsQxc/oYGAGx29dF2cwF2YMxHoly0FBhMw3IEnxo5fMj0boVfoHVBkpkx/w==", "dependencies": { "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", @@ -1311,11 +1299,11 @@ } }, "node_modules/@rushstack/terminal": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", - "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.1.tgz", + "integrity": "sha512-C6Vi/m/84IYJTkfzmXr1+W8Wi3MmBjVF/q3za91Gb3VYjKbpALHVxY6FgH625AnDe5Z0Kh4MHKWA3Z7bqgAezA==", "dependencies": { - "@rushstack/node-core-library": "4.0.2", + "@rushstack/node-core-library": "4.1.0", "supports-color": "~8.1.1" }, "peerDependencies": { @@ -1328,11 +1316,11 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", - "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.2.tgz", + "integrity": "sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==", "dependencies": { - "@rushstack/terminal": "0.10.0", + "@rushstack/terminal": "0.10.1", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -1568,22 +1556,22 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", - "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", "peer": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/type-utils": "7.4.0", - "@typescript-eslint/utils": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1602,16 +1590,31 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", - "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "engines": { @@ -1631,13 +1634,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", - "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1648,15 +1651,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", - "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1675,9 +1678,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", - "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1688,19 +1691,19 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", - "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1725,9 +1728,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "peer": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -1739,19 +1742,34 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", - "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "semver": "^7.6.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1764,14 +1782,29 @@ "eslint": "^8.56.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", - "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.4.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.8.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2203,9 +2236,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001600", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", - "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "version": "1.0.30001614", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", + "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==", "funding": [ { "type": "opencollective", @@ -2599,9 +2632,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.717", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", - "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==" + "version": "1.4.751", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz", + "integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -2720,12 +2753,15 @@ } }, "node_modules/eslint-plugin-security": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.1.tgz", - "integrity": "sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.0.tgz", + "integrity": "sha512-2Ij7PkmXIF2cKwoVkEgemwoXbOnxg5UfdhdcpNxZwJxC/10dbsdhHISrTyJ/n8DUkt3yiN6P1ywEgcMGjIwHIw==", "peer": true, "dependencies": { "safe-regex": "^2.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/eslint-scope": { @@ -3194,6 +3230,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3523,7 +3572,7 @@ "version": "9.1.1", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz", "integrity": "sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==", - "deprecated": "< 21.8.0 is no longer supported", + "deprecated": "< 21.9.0 is no longer supported", "hasInstallScript": true, "dependencies": { "debug": "^4.1.0", @@ -4558,17 +4607,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "peer": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -4945,7 +4994,7 @@ "version": "19.2.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.2.0.tgz", "integrity": "sha512-rhr5ery8htpOTikmm/wrDU707wtmJ7ccX2WLkBf0A8eYYpscck5/iz04/fHOiIRWMFfnYOvaO9wNb4jcO3Mjyg==", - "deprecated": "< 21.8.0 is no longer supported", + "deprecated": "< 21.9.0 is no longer supported", "hasInstallScript": true, "dependencies": { "cosmiconfig": "7.0.1", @@ -5937,9 +5986,9 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6143,6 +6192,15 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6295,12 +6353,6 @@ } }, "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "peer": true - }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -6310,16 +6362,16 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==" }, "@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "requires": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -6443,9 +6495,9 @@ "peer": true }, "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "peer": true }, "@jridgewell/sourcemap-codec": { @@ -6454,17 +6506,17 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@microsoft/api-extractor": { - "version": "7.43.0", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", - "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", + "version": "7.43.1", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.1.tgz", + "integrity": "sha512-ohg40SsvFFgzHFAtYq5wKJc8ZDyY46bphjtnSvhSSlXpPTG7GHwyyXkn48UZiUCBwr2WC7TRC1Jfwz7nreuiyQ==", "requires": { - "@microsoft/api-extractor-model": "7.28.13", + "@microsoft/api-extractor-model": "7.28.14", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2", + "@rushstack/node-core-library": "4.1.0", "@rushstack/rig-package": "0.5.2", - "@rushstack/terminal": "0.10.0", - "@rushstack/ts-command-line": "4.19.1", + "@rushstack/terminal": "0.10.1", + "@rushstack/ts-command-line": "4.19.2", "lodash": "~4.17.15", "minimatch": "~3.0.3", "resolve": "~1.22.1", @@ -6481,13 +6533,13 @@ } }, "@microsoft/api-extractor-model": { - "version": "7.28.13", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.13.tgz", - "integrity": "sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==", + "version": "7.28.14", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.14.tgz", + "integrity": "sha512-Bery/c8A8SsKPSvA82cTTuy/+OcxZbLRmKhPkk91/AJOQzxZsShcrmHFAGeiEqSIrv1nPZ3tKq9kfMLdCHmsqg==", "requires": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2" + "@rushstack/node-core-library": "4.1.0" } }, "@microsoft/dynamicproto-js": { @@ -6540,17 +6592,17 @@ "requires": {} }, "@nevware21/ts-async": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.4.0.tgz", - "integrity": "sha512-dbV826TTehQIBIJjh8GDSbwn1Z6+cnkyNbRlpcpdBPH8mROD2zabIUKqWcw9WRdTjjUIm21K+OR4DXWlAyOVTQ==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.1.tgz", + "integrity": "sha512-O2kN8n2HpDWJ7Oji+oTMnhITrCndmrNvrHbGDwAIBydx+FWvLE/vrw4QwnRRMvSCa2AJrcP59Ryklxv30KfkWQ==", "requires": { - "@nevware21/ts-utils": ">= 0.10.0 < 2.x" + "@nevware21/ts-utils": ">= 0.11.2 < 2.x" } }, "@nevware21/ts-utils": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.0.tgz", - "integrity": "sha512-3yrohCSKYBLKrW41fYkZorN2rf9GYr/4Cb4Xu9fWCyXgVDyt1uLgMaCinhx0kEkEUfME3Smqs+2itJRhXgCo8Q==" + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.2.tgz", + "integrity": "sha512-80W8BkS09kkGuUHJX50Fqq+QqAslxUaOQytH+3JhRacXs1EpEt2JOOkYKytqFZAYir3SeH9fahniEaDzIBxlUw==" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -6621,9 +6673,9 @@ }, "dependencies": { "magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "requires": { "@jridgewell/sourcemap-codec": "^1.4.15" } @@ -7327,9 +7379,9 @@ } }, "@rushstack/node-core-library": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", - "integrity": "sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.1.0.tgz", + "integrity": "sha512-qz4JFBZJCf1YN5cAXa1dP6Mki/HrsQxc/oYGAGx29dF2cwF2YMxHoly0FBhMw3IEnxo5fMj0boVfoHVBkpkx/w==", "requires": { "fs-extra": "~7.0.1", "import-lazy": "~4.0.0", @@ -7349,20 +7401,20 @@ } }, "@rushstack/terminal": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.0.tgz", - "integrity": "sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.10.1.tgz", + "integrity": "sha512-C6Vi/m/84IYJTkfzmXr1+W8Wi3MmBjVF/q3za91Gb3VYjKbpALHVxY6FgH625AnDe5Z0Kh4MHKWA3Z7bqgAezA==", "requires": { - "@rushstack/node-core-library": "4.0.2", + "@rushstack/node-core-library": "4.1.0", "supports-color": "~8.1.1" } }, "@rushstack/ts-command-line": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.1.tgz", - "integrity": "sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.19.2.tgz", + "integrity": "sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==", "requires": { - "@rushstack/terminal": "0.10.0", + "@rushstack/terminal": "0.10.1", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -7589,79 +7641,90 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", - "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", "peer": true, "requires": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/type-utils": "7.4.0", - "@typescript-eslint/utils": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "@typescript-eslint/parser": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", - "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", "peer": true, "requires": { - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", - "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", "peer": true, "requires": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" } }, "@typescript-eslint/type-utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", - "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", "peer": true, "requires": { - "@typescript-eslint/typescript-estree": "7.4.0", - "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", - "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", "peer": true }, "@typescript-eslint/typescript-estree": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", - "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", "peer": true, "requires": { - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/visitor-keys": "7.4.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "dependencies": { "brace-expansion": { @@ -7674,39 +7737,59 @@ } }, "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "peer": true, "requires": { "brace-expansion": "^2.0.1" } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, "@typescript-eslint/utils": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", - "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.4.0", - "@typescript-eslint/types": "7.4.0", - "@typescript-eslint/typescript-estree": "7.4.0", - "semver": "^7.5.4" + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "semver": "^7.6.0" + }, + "dependencies": { + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "@typescript-eslint/visitor-keys": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", - "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", "peer": true, "requires": { - "@typescript-eslint/types": "7.4.0", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.8.0", + "eslint-visitor-keys": "^3.4.3" } }, "@ungap/structured-clone": { @@ -8004,9 +8087,9 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "caniuse-lite": { - "version": "1.0.30001600", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", - "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==" + "version": "1.0.30001614", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", + "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==" }, "chalk": { "version": "4.1.2", @@ -8296,9 +8379,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.717", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz", - "integrity": "sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==" + "version": "1.4.751", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz", + "integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==" }, "encodeurl": { "version": "1.0.2", @@ -8404,9 +8487,9 @@ } }, "eslint-plugin-security": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.1.tgz", - "integrity": "sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.0.tgz", + "integrity": "sha512-2Ij7PkmXIF2cKwoVkEgemwoXbOnxg5UfdhdcpNxZwJxC/10dbsdhHISrTyJ/n8DUkt3yiN6P1ywEgcMGjIwHIw==", "peer": true, "requires": { "safe-regex": "^2.1.1" @@ -8765,6 +8848,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -9807,17 +9896,17 @@ } }, "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "peer": true, "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" } }, "os-homedir": { @@ -10819,9 +10908,9 @@ } }, "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "requires": { "brace-expansion": "^2.0.1" } @@ -10961,6 +11050,12 @@ "isexe": "^2.0.0" } }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "peer": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts index 27ee8b058..ef459f698 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts @@ -2,8 +2,8 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework"; import * as pako from "pako"; export class AppInsightsCoreSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 63; - private readonly MAX_BUNDLE_SIZE = 63; + private readonly MAX_RAW_SIZE = 64; + private readonly MAX_BUNDLE_SIZE = 64; private readonly MAX_RAW_DEFLATE_SIZE = 27; private readonly MAX_BUNDLE_DEFLATE_SIZE = 27; private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js"; diff --git a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts index 3ad74c4d4..a14ce761f 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts @@ -1,21 +1,27 @@ -import { Assert, AITestClass } from "@microsoft/ai-test-framework"; -import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj } from "../../../src/applicationinsights-core-js" +import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework"; +import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj, onConfigChange, createProcessTelemetryContext } from "../../../src/applicationinsights-core-js" import { AppInsightsCore } from "../../../src/JavaScriptSDK/AppInsightsCore"; import { IChannelControls } from "../../../src/JavaScriptSDK.Interfaces/IChannelControls"; import { _eInternalMessageId, LoggingSeverity } from "../../../src/JavaScriptSDK.Enums/LoggingEnums"; import { _InternalLogMessage, DiagnosticLogger } from "../../../src/JavaScriptSDK/DiagnosticLogger"; +import { ActiveStatus } from "../../../src/JavaScriptSDK.Enums/InitActiveStatusEnum"; +import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, doAwaitResponse } from "@nevware21/ts-async"; const AIInternalMessagePrefix = "AITR_"; const MaxInt32 = 0xFFFFFFFF; export class ApplicationInsightsCoreTests extends AITestClass { + private ctx: any; public testInitialize() { super.testInitialize(); + this.ctx = {}; } public testCleanup() { super.testCleanup(); + this.ctx = {}; + } public registerTests() { @@ -805,6 +811,714 @@ export class ApplicationInsightsCoreTests extends AITestClass { } }); + // init with ikey: null + this.testCase({ + name: "ApplicationInsightsCore Init: init with ikey null, will throw error message", + useFakeTimers: true, + test: () => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status"); + + let config = { + instrumentationKey: undefined, + endpointUrl: "testUrl" + } as IConfiguration; + + let errorisCalled = false; + + try { + core.initialize( + config, + [trackPlugin, channelPlugin]); + + } catch (e) { + errorisCalled = true; + Assert.ok(JSON.stringify(e.message).indexOf("Please provide instrumentation key") > -1, "should send provide ikey error message"); + } + + Assert.ok(errorisCalled, "ikey error should be called"); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.equal(core.config.instrumentationKey, null, "channel testIkey should be null"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1"); + + core.track({name: "test1"}); + Assert.ok(core.eventCnt() == 0, "Event should not be queued"); + + let isInit = core.isInitialized(); + Assert.ok(!isInit, "core is not initialized"); + + // Test re-init with valid ikey + config.instrumentationKey = "testIkey"; + + core.initialize( + config, + [trackPlugin, channelPlugin]); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status again"); + isInit = core.isInitialized(); + Assert.ok(isInit, "core is initialized"); + + } + }); + + // init with ikey: string, endpoint null + this.testCase({ + name: "ApplicationInsightsCore Init: init with ikey string, endpoint null", + useFakeTimers: true, + test: () => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status"); + + let config = { + instrumentationKey: "testIkey", + endpointUrl: undefined + } as IConfiguration; + + let errorisCalled = false; + + try { + core.initialize( + config, + [trackPlugin, channelPlugin]); + + } catch (e) { + errorisCalled = true; + } + + Assert.ok(!errorisCalled, "ikey error should not be called"); + + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should not be queued"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be null"); + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test"); + + } + }); + + // init with ikey: string, endpointUrl: string + this.testCase({ + name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changes with string", + useFakeTimers: true, + test: () => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.NONE, "default should be pending status"); + + let config = { + instrumentationKey: "testIkey", + endpointUrl: "testUrl" + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should not be queued"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be set"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status"); + + + + core.config.instrumentationKey = "testIkey1"; + core.config.endpointUrl = "testUrl1"; + this.clock.tick(1); + core.track({name: "test1"}); + Assert.equal(channelSpy.callCount, 2, "channel should be called twice"); + Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); + evt = channelSpy.args[1][0]; + Assert.equal(evt.name, "test1", "event name should be set"); + Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test1"); + + + // change the ikey to null again, inactive + core.config.instrumentationKey = undefined; + this.clock.tick(1); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1"); + + } + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let urlPromise = createAsyncResolvedPromise("testUrl"); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url rejected promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let urlPromise = createAsyncRejectedPromise(new Error("endpoint error")); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey rejected promise, endpoint url rejected promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let ikeyPromise = createAsyncRejectedPromise(new Error("ikey error")); + let urlPromise = createAsyncRejectedPromise(new Error("endpoint error")); + + this.ctx.ikeyPromise = ikeyPromise; + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + + core.initialize( + config, + [trackPlugin, channelPlugin]); + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + let ikeyPromise = this.ctx.ikeyPromise; + + if (activeStatus === ActiveStatus.INACTIVE) { + Assert.deepEqual(core.config.instrumentationKey, ikeyPromise, "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed"); + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should not be released"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey promise chain, endpoint url promise chain", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl"); + let ikeyPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(csPromise, (res) => { + if (!res.rejected) { + resolve("testIkey"); + return; + } + reject(new Error("ikey error")); + }) + }); + let urlPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(csPromise, (res) => { + if (!res.rejected) { + resolve("testUrl"); + return; + } + reject(new Error("url error")); + }) + }); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey mutiple layer promise chain, endpoint url mutiple layer promise chain", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl"); + let ikeyPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(csPromise, (res) => { + if (!res.rejected) { + resolve(createAsyncResolvedPromise("testIkey")); + return; + } + reject(createAsyncRejectedPromise(new Error("ikey error"))); + return; + }) + }); + let urlPromise = createAsyncPromise((resolve, reject) => { + doAwaitResponse(csPromise, (res) => { + if (!res.rejected) { + resolve(createAsyncResolvedPromise("testUrl")); + return; + } + reject(createAsyncRejectedPromise(new Error("url error"))); + return; + }) + }); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changed with resolved promises", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + + let config = { + instrumentationKey: "testIkey", + endpointUrl: "testUrl" + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + Assert.ok(channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 0, "Event should not be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status"); + + let ikeyPromise = createAsyncResolvedPromise("testIkey1"); + let urlPromise = createAsyncResolvedPromise("testUrl1"); + core.config.instrumentationKey = ikeyPromise; + core.config.endpointUrl = urlPromise; + this.clock.tick(1); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey1"; + core.config.endpointUrl = "testUrl1"; + core.track({name: "test2"}); + Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); + let evt = channelSpy.args[1][0]; + Assert.equal(evt.name, "test2", "event name should be set test2"); + Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise, dynamic change with promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let urlPromise = createAsyncResolvedPromise("testUrl"); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy; + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active"); + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); + Assert.ok(channelSpy.calledOnce, "channel should be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + let evt = channelSpy.args[0][0]; + Assert.equal(evt.iKey, "testIkey", "event ikey should be set"); + + let ikeyPromise = createAsyncResolvedPromise("testIkey1"); + let urlPromise = createAsyncResolvedPromise("testUrl1"); + core.config.instrumentationKey = ikeyPromise; + core.config.endpointUrl = urlPromise; + this.ctx.secondCall = true; + //Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending test1"); + return true; + } + return false; + }, "Wait for promise first response" + new Date().toISOString(), 60, 1000) as any).concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy; + + if (this.ctx.secondCall && activeStatus === ActiveStatus.ACTIVE) { + Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active test1"); + Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed test1"); + Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed test1"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + core.track({name: "test1"}); + let evt = channelSpy.args[1][0]; + Assert.equal(evt.name, "test1", "event name should be set test2"); + Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1"); + + return true; + } + return false; + }, "Wait for promise second response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let urlPromise = createAsyncResolvedPromise("testUrl"); + + let unresolveIkeyPromise = createAsyncPromise((resolve, reject) => { + //do nothing, + }) // init with it, it should be pending + + let newIkeyPromise = createAsyncPromise((resolve, reject) => { + resolve("ikey") + }) // init with it, pending, no changes or string + // resolve first one, active + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status"); + + // status is pending, following changes should not be applied + core.config.instrumentationKey = "testIkey1"; + core.config.endpointUrl = "testUrl1"; + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey"; + core.config.endpointUrl = "testUrl"; + Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); + let evt1 = channelSpy.args[0][0]; + Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1"); + this.clock.tick(1); + core.track({name: "test2"}); + let evt2 = channelSpy.args[1][0]; + Assert.equal(evt2.name, "test2", "event name should be set test2"); + Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings while waiting promises", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + + let urlPromise = createAsyncResolvedPromise("testUrl"); + + let resolveFunc; + + let ikeyPromise = createAsyncPromise((resolve, reject) => { + resolveFunc = resolve; + //do nothing, mock unresolve + }); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status"); + + // status is pending, following changes should not be applied + core.config.instrumentationKey = "testIkey1"; + this.clock.tick(1); + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status"); + + resolveFunc("testIkey"); + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey"; + core.config.endpointUrl = "testUrl"; + Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); + let evt1 = channelSpy.args[0][0]; + Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1"); + this.clock.tick(1); + core.track({name: "test2"}); + let evt2 = channelSpy.args[1][0]; + Assert.equal(evt2.name, "test2", "event name should be set test2"); + Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + + this.testCase({ name: 'newId tests length', @@ -1143,6 +1857,7 @@ class ChannelPlugin implements IChannelControls { } public initialize = (config: IConfiguration) => { + } public _processTelemetry(env: ITelemetryItem) { diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Enums/InitActiveStatusEnum.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/InitActiveStatusEnum.ts new file mode 100644 index 000000000..856fdd83f --- /dev/null +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/InitActiveStatusEnum.ts @@ -0,0 +1,30 @@ +import { createEnumStyle } from "./EnumHelperFuncs"; + +export const enum eActiveStatus { + + // None + NONE = 0, + /** + * inactive status means there might be rejected ikey/endpoint promises or ikey/endpoint resolved is not valid + */ + INACTIVE = 1, + + /** + * active mean ikey/endpoint promises is resolved and initializing with ikey/endpoint is successful + */ + ACTIVE = 2, + + /** + * Waiting for promises to be resolved + * NOTE: if status is set to be pending, incoming changes will be dropped until pending status is removed + */ + PENDING = 3, +} + +export const ActiveStatus = createEnumStyle({ + NONE: eActiveStatus.NONE, + PENDING: eActiveStatus.PENDING, + INACTIVE: eActiveStatus.INACTIVE, + ACTIVE: eActiveStatus.ACTIVE +}); +export type ActiveStatus = number | eActiveStatus; \ No newline at end of file diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts index c90b3e9d4..1fd19e0ee 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts @@ -4,6 +4,7 @@ import { IPromise } from "@nevware21/ts-async"; import { ITimerHandler } from "@nevware21/ts-utils"; import { WatcherFunction } from "../Config/IDynamicWatcher"; +import { eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum"; import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason"; import { UnloadHandler } from "../JavaScriptSDK/UnloadHandlerContainer"; import { IChannelControls } from "./IChannelControls"; @@ -225,4 +226,22 @@ export interface IAppInsightsCore number; + + /** + * Watches and tracks status of initialization process + * @returns ActiveStatus + * @since 3.3.0 + * If returned status is active, it means initialization process is completed. + * If returned status is pending, it means the initialization process is waiting for promieses to be resolved. + * If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises. + */ + activeStatus?: () => eActiveStatus | number; + + /** + * Set Active Status to pending, which will block the incoming changes until internal promises are resolved + * @internal Internal use + * @since 3.3.0 + */ + _setPendingStatus?: () => void; + } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts index 3ff6ebc8e..224533c9a 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { IPromise } from "@nevware21/ts-async"; import { IAppInsightsCore } from "./IAppInsightsCore"; import { IChannelControls } from "./IChannelControls"; import { ICookieMgrConfig } from "./ICookieMgr"; @@ -17,12 +18,12 @@ export interface IConfiguration { /** * Instrumentation key of resource. Either this or connectionString must be specified. */ - instrumentationKey?: string; + instrumentationKey?: string| IPromise; /** * Connection string of resource. Either this or instrumentationKey must be specified. */ - connectionString?: string; + connectionString?: string | IPromise ; /** * Set the timer interval (in ms) for internal logging queue, this is the @@ -72,7 +73,7 @@ export interface IConfiguration { /** * Endpoint where telemetry data is sent */ - endpointUrl?: string; + endpointUrl?: string | IPromise; /** * Extension configs loaded in SDK @@ -190,4 +191,19 @@ export interface IConfiguration { * @defaultValue undefined */ featureOptIn?: IFeatureOptIn; + + /** + * If your connection string, instrumentation key and endpoint url are promises, + * this config is to manually set timeout for those promises. + * Default: undefined, initialization process will wait all promises to be finished. + */ + initTimeOut?: number; + + /** + * If your connection string, instrumentation key and endpoint url are promises, + * this config is to manually set in memory proxy track calls size limit before promises finished. + * Default: undefined + */ + initInMemoMaxSize?: number; + } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index c0ef2bc4d..29e3c2354 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -3,16 +3,17 @@ "use strict"; import dynamicProto from "@microsoft/dynamicproto-js"; -import { IPromise, createPromise } from "@nevware21/ts-async"; +import { IPromise, createAllSettledPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async"; import { ITimerHandler, arrAppend, arrForEach, arrIndexOf, createTimeout, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject, - objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError + isPromiseLike, objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError } from "@nevware21/ts-utils"; import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig"; import { IConfigDefaults } from "../Config/IConfigDefaults"; import { IDynamicConfigHandler, _IInternalDynamicConfigHandler } from "../Config/IDynamicConfigHandler"; import { IWatchDetails, WatcherFunction } from "../Config/IDynamicWatcher"; import { eEventsDiscardedReason } from "../JavaScriptSDK.Enums/EventsDiscardedReason"; +import { ActiveStatus, eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum"; import { _eInternalMessageId, eLoggingSeverity } from "../JavaScriptSDK.Enums/LoggingEnums"; import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason"; import { TelemetryUnloadReason } from "../JavaScriptSDK.Enums/TelemetryUnloadReason"; @@ -59,6 +60,7 @@ const strValidationError = "Plugins must provide initialize method"; const strNotificationManager = "_notificationManager"; const strSdkUnloadingError = "SDK is still unloading..."; const strSdkNotInitialized = "SDK is not initialized"; +const maxQueueSize = 500; // const strPluginUnloadFailed = "Failed to unload plugin"; /** @@ -292,6 +294,8 @@ export class AppInsightsCore im let _extensions: IPlugin[]; let _pluginVersionStringArr: string[]; let _pluginVersionString: string; + let _activeStatus: eActiveStatus; // to indicate if ikey or endpoint url promised is resolved or not + let _endpoint: string; /** * Internal log poller @@ -307,11 +311,20 @@ export class AppInsightsCore im // Special internal method to allow the unit tests and DebugPlugin to hook embedded objects _self["_getDbgPlgTargets"] = () => { - return [_extensions]; + return [_extensions, _eventQueue]; }; _self.isInitialized = () => _isInitialized; + // version 3.3.0 + _self.activeStatus = () => _activeStatus; + + // version 3.3.0 + // internal + _self._setPendingStatus = () => { + _activeStatus = eActiveStatus.PENDING; // allow set pending under NONE? + }; + // Creating the self.initialize = () _self.initialize = (config: CfgType, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager): void => { if (_isUnloading) { @@ -330,8 +343,95 @@ export class AppInsightsCore im // This will be "re-run" if the referenced config properties are changed _addUnloadHook(_configHandler.watch((details) => { - _instrumentationKey = details.cfg.instrumentationKey; + + + + + // app Insights core only handle ikey and endpointurl + + let ikey = details.cfg.instrumentationKey; + let endpointUrl = details.cfg.endpointUrl; // do not need to validate endpoint url + let isPending = _activeStatus === eActiveStatus.PENDING; + + if (isPending){ + // mean waiting for previous promises to be resolved, won't apply new changes + return; + } + + if (isNullOrUndefined(ikey)) { + _activeStatus = ActiveStatus.INACTIVE; + if (!_isInitialized) { + _throwIKeyErrMsg(); + } + return; + + } + + let promises: IPromise[] = []; + if (isPromiseLike(ikey)) { + promises.push(ikey); + } else { + _instrumentationKey = ikey; + } + + if (isPromiseLike(endpointUrl)) { + promises.push(endpointUrl); + } else { + _endpoint = endpointUrl; + } + + // have at least one promise + if (promises.length) { + _activeStatus = eActiveStatus.PENDING; + let allPromises = createAllSettledPromise(promises); + // ask a question to osvaldo, cs promise timeout? what happened? + doAwaitResponse(allPromises, (response) => { + try { + _instrumentationKey = null; // set current local ikey variable + if (!response.rejected) { + let values = response.value; + if (values && values.length) { + let ikeyRes = values[0]; + let ikeyVal = ikeyRes.value; + if (ikeyVal) { + _instrumentationKey = ikeyVal; + config.instrumentationKey = _instrumentationKey; // should not be set to null + } + + if (values.length > 1) { + let endpointRes = values[1]; + _endpoint = endpointRes.value; + config.endpointUrl = _endpoint; + } + + } + + } + + if (isNullOrUndefined(_instrumentationKey)) { + _activeStatus = ActiveStatus.INACTIVE; + } else { + _activeStatus = ActiveStatus.ACTIVE; + _self.releaseQueue(); + _self.pollInternalLogs(); + } + + } catch (e) { + // eslint-disable-next-line + _activeStatus = ActiveStatus.INACTIVE; + } + }); + } else { + // means no promises + _activeStatus = ActiveStatus.ACTIVE; + _self.releaseQueue(); + _self.pollInternalLogs(); + + + } + + //_instrumentationKey = details.cfg.instrumentationKey; // Mark the extensionConfig and all first level keys as referenced // This is so that calls to getExtCfg() will always return the same object // Even when a user may "re-assign" the plugin properties (or it's unloaded/reloaded) @@ -339,10 +439,8 @@ export class AppInsightsCore im objForEachKey(extCfg, (key) => { details.ref(extCfg, key); }); - - if (isNullOrUndefined(_instrumentationKey)) { - throwError("Please provide instrumentation key"); - } + + })); _notificationManager = notificationManager; @@ -377,9 +475,11 @@ export class AppInsightsCore im _cfgListeners = null; _isInitialized = true; - _self.releaseQueue(); - - _self.pollInternalLogs(); + if (_activeStatus === ActiveStatus.ACTIVE) { + _self.releaseQueue(); + _self.pollInternalLogs(); + } + }; _self.getChannels = (): IChannelControls[] => { @@ -416,12 +516,16 @@ export class AppInsightsCore im // Common Schema 4.0 telemetryItem.ver = telemetryItem.ver || "4.0"; - if (!_isUnloading && _self.isInitialized()) { + if (!_isUnloading && _self.isInitialized() && _activeStatus === ActiveStatus.ACTIVE) { // Process the telemetry plugin chain _createTelCtx().processNext(telemetryItem); - } else { + } else if (_activeStatus !== ActiveStatus.INACTIVE){ // Queue events until all extensions are initialized - _eventQueue.push(telemetryItem); + if (_eventQueue.length <= maxQueueSize) { + // set limit, 500, if full, stop adding new events + _eventQueue.push(telemetryItem); + } + } }, () => ({ item: telemetryItem }), !((telemetryItem as any).sync)); }; @@ -492,6 +596,7 @@ export class AppInsightsCore im _eventQueue = []; arrForEach(eventQueue, (event: ITelemetryItem) => { + event.iKey = event.iKey || _instrumentationKey; _createTelCtx().processNext(event); }); } @@ -505,6 +610,10 @@ export class AppInsightsCore im return _startLogPoller(true); }; + function _throwIKeyErrMsg() { + throwError("Please provide instrumentation key"); + } + function _startLogPoller(alwaysStart?: boolean): ITimerHandler { if ((!_internalLogPoller || !_internalLogPoller.enabled) && !_forceStopInternalLogPoller) { let shouldStart = alwaysStart || (_logger && _logger.queue.length > 0); @@ -872,6 +981,8 @@ export class AppInsightsCore im _forceStopInternalLogPoller = false; _internalLogPoller = null; _internalLogPollerListening = false; + _activeStatus = eActiveStatus.NONE; // default is None + _endpoint = null; } function _createTelCtx(): IProcessTelemetryContext { @@ -1403,6 +1514,30 @@ export class AppInsightsCore im return null; } + /** + * Watches and tracks status of initialization process + * @returns ActiveStatus + * @since 3.3.0 + * If returned status is active, it means initialization process is completed. + * If returned status is pending, it means the initialization process is waiting for promieses to be resolved. + * If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises. + */ + public activeStatus(): eActiveStatus | number { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + return null; + } + + /** + * Set Active Status to pending, which will block the incoming changes until internal promises are resolved + * @internal Internal use + * @since 3.3.0 + */ + public _setPendingStatus(): void { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + return null; + } + + protected releaseQueue() { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } diff --git a/shared/AppInsightsCore/src/applicationinsights-core-js.ts b/shared/AppInsightsCore/src/applicationinsights-core-js.ts index 2d02f8d1b..9eaf98bde 100644 --- a/shared/AppInsightsCore/src/applicationinsights-core-js.ts +++ b/shared/AppInsightsCore/src/applicationinsights-core-js.ts @@ -18,6 +18,7 @@ export { eEventsDiscardedReason, EventsDiscardedReason, eBatchDiscardedReason, B export { SendRequestReason, TransportType } from "./JavaScriptSDK.Enums/SendRequestReason"; export { TelemetryUpdateReason } from "./JavaScriptSDK.Enums/TelemetryUpdateReason"; export { TelemetryUnloadReason } from "./JavaScriptSDK.Enums/TelemetryUnloadReason"; +export { eActiveStatus, ActiveStatus } from "./JavaScriptSDK.Enums/InitActiveStatusEnum" export { throwAggregationError } from "./JavaScriptSDK/AggregationError"; export { AppInsightsCore } from "./JavaScriptSDK/AppInsightsCore"; export { BaseTelemetryPlugin } from "./JavaScriptSDK/BaseTelemetryPlugin"; From 3a052e951ffe8ff9e1bd064ac78998a8783fb0b3 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Thu, 9 May 2024 14:22:54 -0700 Subject: [PATCH 02/16] update --- .../Unit/src/applicationinsights.e2e.tests.ts | 53 +++++++++++++++++++ .../src/JavaScriptSDK/AppInsightsCore.ts | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index aabf7a302..606879391 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -337,6 +337,59 @@ export class ApplicationInsightsTests extends AITestClass { }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) }); + this.testCaseAsync({ + name: "Init: init with cs null, ikey promise, endpoint promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + + // unload previous one first + let oriInst = this._ai; + if (oriInst && oriInst.unload) { + // force unload + oriInst.unload(false); + } + + if (oriInst && oriInst["dependencies"]) { + oriInst["dependencies"].teardown(); + } + + this._config = this._getTestConfig(this._sessionPrefix); + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let endpointPromise = createAsyncResolvedPromise("testUrl"); + //let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); + //this._config.connectionString = csPromise; + this._config.connectionString = null; + this._config.instrumentationKey = ikeyPromise; + this._config.endpointUrl = endpointPromise; + + + + let init = new ApplicationInsights({ + config: this._config + }); + init.loadAppInsights(); + this._ai = init; + let config = this._ai.config; + let core = this._ai.core; + let status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); + Assert.equal(config.connectionString,null, "connection string shoule be null"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._ai.core + let activeStatus = core.activeStatus && core.activeStatus(); + + if (activeStatus === ActiveStatus.ACTIVE) { + core.config.instrumentationKey = "testIkey"; + core.config.endpointUrl = "testUrl"; + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + } public addCDNOverrideTests(): void { diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 29e3c2354..56ef51af0 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -384,7 +384,6 @@ export class AppInsightsCore im if (promises.length) { _activeStatus = eActiveStatus.PENDING; let allPromises = createAllSettledPromise(promises); - // ask a question to osvaldo, cs promise timeout? what happened? doAwaitResponse(allPromises, (response) => { try { _instrumentationKey = null; // set current local ikey variable @@ -410,6 +409,7 @@ export class AppInsightsCore im if (isNullOrUndefined(_instrumentationKey)) { _activeStatus = ActiveStatus.INACTIVE; + _throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, "ikey can't be resolved from promises"); } else { _activeStatus = ActiveStatus.ACTIVE; _self.releaseQueue(); From 8be7779a7b1991b36ea7b142b4cd1797a27692c0 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 24 May 2024 15:39:30 -0700 Subject: [PATCH 03/16] udpate --- AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts | 4 ++-- AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts | 4 ++-- shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index 6f71e4cf1..ca1370302 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -3,9 +3,9 @@ import { SinonSpy } from 'sinon'; import { ApplicationInsights } from '../../../src/applicationinsights-web' import { Sender } from '@microsoft/applicationinsights-channel-js'; import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig } from '@microsoft/applicationinsights-common'; -import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus } from "@microsoft/applicationinsights-core-js"; +import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus, FeatureOptInMode } from "@microsoft/applicationinsights-core-js"; import { TelemetryContext } from '@microsoft/applicationinsights-properties-js'; -import { createAsyncResolvedPromise, createResolvedPromise } from '@nevware21/ts-async'; +import { createAsyncResolvedPromise } from '@nevware21/ts-async'; import { CONFIG_ENDPOINT_URL } from '../../../src/InternalConstants'; diff --git a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts index 689aa37bd..4074d6aa0 100644 --- a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts +++ b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts @@ -4,8 +4,8 @@ import * as pako from "pako"; export class AISKULightSizeCheck extends AITestClass { private readonly MAX_RAW_SIZE = 88; private readonly MAX_BUNDLE_SIZE = 88; - private readonly MAX_RAW_DEFLATE_SIZE = 36; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 36; + private readonly MAX_RAW_DEFLATE_SIZE = 37; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 37; private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js"; private readonly currentVer = "3.2.1"; private readonly prodFilePath = `../browser/es5/aib.${this.currentVer[0]}.min.js`; diff --git a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts index 2e1f35752..21da21f9d 100644 --- a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts +++ b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts @@ -2,7 +2,7 @@ import { AITestClass } from "@microsoft/ai-test-framework"; import * as pako from 'pako'; export class FileSizeCheckTest extends AITestClass { - private readonly MAX_BUNDLE_SIZE = 66; + private readonly MAX_BUNDLE_SIZE = 67; private readonly MAX_DEFLATE_SIZE = 28; private readonly bundleFilePath = "../bundle/es5/ms.core.min.js"; From 3d7a5f87cbc228425a50e06803ea735b36757f45 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 24 May 2024 15:41:54 -0700 Subject: [PATCH 04/16] udpate --- .../Tests/Unit/src/applicationinsights.e2e.tests.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index ca1370302..1f9b39a53 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -145,12 +145,12 @@ export class ApplicationInsightsTests extends AITestClass { public registerTests() { this.addDynamicConfigTests() - // this.addGenericE2ETests(); - // this.addAnalyticsApiTests(); - // this.addAsyncTests(); - // this.addDependencyPluginTests(); - // this.addPropertiesPluginTests(); - // this.addCDNOverrideTests(); + this.addGenericE2ETests(); + this.addAnalyticsApiTests(); + this.addAsyncTests(); + this.addDependencyPluginTests(); + this.addPropertiesPluginTests(); + this.addCDNOverrideTests(); } public addGenericE2ETests(): void { From 3de3e51dbff3273acb83db655544526c69373524 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 24 May 2024 16:04:33 -0700 Subject: [PATCH 05/16] update --- AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts index 4074d6aa0..82866cc06 100644 --- a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts +++ b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts @@ -2,8 +2,8 @@ import { AITestClass, Assert } from "@microsoft/ai-test-framework"; import * as pako from "pako"; export class AISKULightSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 88; - private readonly MAX_BUNDLE_SIZE = 88; + private readonly MAX_RAW_SIZE = 89; + private readonly MAX_BUNDLE_SIZE = 89; private readonly MAX_RAW_DEFLATE_SIZE = 37; private readonly MAX_BUNDLE_DEFLATE_SIZE = 37; private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js"; From 81c53c4107e43fa793fba0cb9fb30459becd1478 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Thu, 6 Jun 2024 12:50:01 -0700 Subject: [PATCH 06/16] update --- .../Unit/src/applicationinsights.e2e.tests.ts | 12 ++-- .../src/Sender.ts | 9 +++ .../offline-channel-js/src/OfflineChannel.ts | 7 ++- .../Tests/Unit/src/ajax.tests.ts | 58 ++++++++++++++++++- .../src/ajax.ts | 1 + .../Unit/src/AppInsightsCoreSize.Tests.ts | 4 +- 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index 1f9b39a53..d6abe6e96 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -295,8 +295,8 @@ export class ApplicationInsightsTests extends AITestClass { let activeStatus = core.activeStatus && core.activeStatus(); if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey"; - core.config.endpointUrl = "testUrl"; + Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set"); return true; } return false; @@ -335,8 +335,8 @@ export class ApplicationInsightsTests extends AITestClass { let activeStatus = core.activeStatus && core.activeStatus(); if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey"; - core.config.endpointUrl = "testUrl"; + Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set"); return true; } return false; @@ -388,8 +388,8 @@ export class ApplicationInsightsTests extends AITestClass { let activeStatus = core.activeStatus && core.activeStatus(); if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey"; - core.config.endpointUrl = "testUrl"; + Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + Assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set"); return true; } return false; diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index f163fa6c4..c4d9bac84 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -272,10 +272,19 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } }); + // or is not string if (core.activeStatus() === ActiveStatus.PENDING) { // waiting for core promises to be resolved + // NOTE: if active status is set to pending, stop sending, clear timer here + _self.pause(); return; } + + // core status changed from pending to other status + if (_paused) { + _self.resume(); + } + // Only update the endpoint if the original config !== the current config diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index fb50782c8..db9b83a78 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -6,6 +6,7 @@ import { BreezeChannelIdentifier, EventPersistence, IConfig, IOfflineListener, createOfflineListener } from "@microsoft/applicationinsights-common"; import { + ActiveStatus, BaseTelemetryPlugin, EventsDiscardedReason, IAppInsightsCore, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationListener, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXHROverride, SendRequestReason, @@ -553,10 +554,14 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr function _createUrlConfig(coreConfig: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?: ITelemetryPluginChain) { _self._addHook(onConfigChange(coreConfig, (details) => { - if (!isString(coreConfig.instrumentationKey)) { + if (!isString(coreConfig.instrumentationKey) || (core.activeStatus && core.activeStatus() === ActiveStatus.PENDING )) { // if ikey is promise, delay initialization + _self.pause(); return; } + if (_paused) { + _self.resume(); + } let storageConfig: IOfflineChannelConfiguration = null; let theConfig = details.cfg; diff --git a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts index 31a8e5b9a..18fd5b559 100644 --- a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts +++ b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts @@ -1,11 +1,12 @@ import { SinonStub } from "sinon"; import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework"; -import { createSyncPromise } from "@nevware21/ts-async"; +import { createAsyncResolvedPromise, createSyncPromise } from "@nevware21/ts-async"; import { AjaxMonitor } from "../../../src/ajax"; import { DisabledPropertyName, IConfig, DistributedTracingModes, RequestHeaders, IDependencyTelemetry, IRequestContext, formatTraceParent, createTraceParent, PropertiesPluginIdentifier } from "@microsoft/applicationinsights-common"; import { AppInsightsCore, IConfiguration, ITelemetryItem, ITelemetryPlugin, IChannelControls, _eInternalMessageId, - getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach + getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach, + ActiveStatus } from "@microsoft/applicationinsights-core-js"; import { IDependencyListenerDetails } from "../../../src/DependencyListener"; import { FakeXMLHttpRequest } from "@microsoft/ai-test-framework"; @@ -208,6 +209,59 @@ export class AjaxTests extends AITestClass { } }); + this.testCaseAsync({ + name: "Dependencies Configuration: init with cs promise ikey promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + this._ajax = new AjaxMonitor(); + let csPromise = createAsyncResolvedPromise("testIkey"); + let appInsightsCore = new AppInsightsCore(); + let coreConfig = { + instrumentationKey: csPromise + + }; + appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]); + + let trackStub = this.sandbox.stub(appInsightsCore, "track"); + let throwSpy = this.sandbox.spy(appInsightsCore.logger, "throwInternal"); + Assert.equal(false, trackStub.called, "Track should not be called"); + Assert.equal(false, throwSpy.called, "We should not have thrown an internal error"); + + this._context.core = appInsightsCore; + this._context.trackStub = trackStub; + this._context.throwSpy = throwSpy; + + let xhr = new XMLHttpRequest(); + xhr.open("GET", "http://microsoft.com"); + xhr.setRequestHeader("Content-type", "application/json"); + xhr.send(); + // Emulate response + (xhr).respond(200, {"Content-Type": "application/json; charset=utf-8", "Access-Control-Allow-Origin": "*"}, ""); + Assert.ok((xhr)[AJAX_DATA_CONTAINER], "should have xhr hooks"); + + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._context.core + let activeStatus = core.activeStatus && core.activeStatus(); + let trackStub = this._context.trackStub; + let throwSpy = this._context.throwSpy; + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + Assert.equal(1, trackStub.callCount, "Track should be called once"); + Assert.equal(false, throwSpy.called, "We should not have thrown an internal error test1"); + let data = trackStub.args[0][0].baseData; + Assert.equal(data.type, "Ajax", "request type should be ajax"); + Assert.ok(data.properties, "properties should be added"); + console.log(JSON.stringify(data)) + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + this.testCase({ name: "Dependencies Configuration: Make sure we don't fail for invalid arguments", test: () => { diff --git a/extensions/applicationinsights-dependencies-js/src/ajax.ts b/extensions/applicationinsights-dependencies-js/src/ajax.ts index b4469aeeb..2586c995f 100644 --- a/extensions/applicationinsights-dependencies-js/src/ajax.ts +++ b/extensions/applicationinsights-dependencies-js/src/ajax.ts @@ -598,6 +598,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu if (_enableAjaxPerfTracking) { let iKey = config.instrumentationKey || "unkwn"; + // only change the ikey if it is string if (isString(iKey)) { if (iKey.length > 5) { _markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + "."; diff --git a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts index ef459f698..1cdcf9337 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts @@ -2,8 +2,8 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework"; import * as pako from "pako"; export class AppInsightsCoreSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 64; - private readonly MAX_BUNDLE_SIZE = 64; + private readonly MAX_RAW_SIZE = 65; + private readonly MAX_BUNDLE_SIZE = 65; private readonly MAX_RAW_DEFLATE_SIZE = 27; private readonly MAX_BUNDLE_DEFLATE_SIZE = 27; private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js"; From 6156a2ffcfa2a8c27a18e85a2d6097ba4de214c7 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 11 Jun 2024 16:08:44 -0700 Subject: [PATCH 07/16] update --- .../Tests/Unit/src/Sender.tests.ts | 38 ++++++++++++++++++- .../src/Sender.ts | 10 ++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts index 9cf6d2c13..3d0dc88ee 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts @@ -1,11 +1,12 @@ -import { AITestClass } from "@microsoft/ai-test-framework"; +import { AITestClass, PollingAssert } from "@microsoft/ai-test-framework"; import { Sender } from "../../../src/Sender"; import { IOfflineListener, createOfflineListener, utlGetSessionStorageKeys, utlRemoveSessionStorage } from "@microsoft/applicationinsights-common"; import { EnvelopeCreator } from '../../../src/EnvelopeCreator'; import { Exception, CtxTagKeys, isBeaconApiSupported, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, utlCanUseSessionStorage, utlGetSessionStorage, utlSetSessionStorage } from "@microsoft/applicationinsights-common"; -import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow } from "@microsoft/applicationinsights-core-js"; +import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow, ActiveStatus } from "@microsoft/applicationinsights-core-js"; import { ArraySendBuffer, SessionStorageSendBuffer } from "../../../src/SendBuffer"; import { IInternalStorageItem, ISenderConfig } from "../../../src/Interfaces"; +import { createAsyncResolvedPromise } from "@nevware21/ts-async"; @@ -163,6 +164,39 @@ export class SenderTests extends AITestClass { } }); + this.testCaseAsync({ + name: "Channel Init: init with promise", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + + let core = new AppInsightsCore(); + let ikeyPromise = createAsyncResolvedPromise("testIkey"); + let urlPromise = createAsyncResolvedPromise("testUrl"); + let coreConfig = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise, + extensionConfig: {} + } + core.initialize(coreConfig, [this._sender]); + + let status = core.activeStatus && core.activeStatus(); + QUnit.assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._sender.core; + let activeStatus = core.activeStatus && core.activeStatus(); + + if (activeStatus === ActiveStatus.ACTIVE) { + QUnit.assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + QUnit.assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + this.testCase({ name: "Channel Config: Sender override can be handled correctly", useFakeTimers: true, diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index c4d9bac84..4e29a92af 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -277,14 +277,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // waiting for core promises to be resolved // NOTE: if active status is set to pending, stop sending, clear timer here _self.pause(); - return; - } - - // core status changed from pending to other status - if (_paused) { + } else if (core.activeStatus() === ActiveStatus.ACTIVE) { + // core status changed from pending to other status _self.resume(); + } - + // Only update the endpoint if the original config !== the current config From b0b69b53fa4a54922d38e21de332d5a5912faa5a Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 21 Jun 2024 13:42:15 -0700 Subject: [PATCH 08/16] update --- .../Unit/src/applicationinsights.e2e.tests.ts | 65 +++++ .../offline-channel-js/src/OfflineChannel.ts | 11 +- common/config/rush/npm-shrinkwrap.json | 235 +++++++++--------- .../Unit/src/ApplicationInsightsCore.Tests.ts | 136 ++++++++-- .../src/JavaScriptSDK.Enums/LoggingEnums.ts | 3 +- .../IConfiguration.ts | 8 +- .../src/JavaScriptSDK/AppInsightsCore.ts | 153 ++++++++---- 7 files changed, 414 insertions(+), 197 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index 905a5f1fd..27c1e4004 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -272,6 +272,63 @@ export class ApplicationInsightsTests extends AITestClass { this._config = this._getTestConfig(this._sessionPrefix); let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); this._config.connectionString = csPromise; + this._config.initTimeOut= 80000; + + + let init = new ApplicationInsights({ + config: this._config + }); + init.loadAppInsights(); + this._ai = init; + let config = this._ai.config; + let core = this._ai.core; + let status = core.activeStatus && core.activeStatus(); + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); + + + config.connectionString = "InstrumentationKey=testIkey1;ingestionendpoint=testUrl1"; + this.clock.tick(1); + status = core.activeStatus && core.activeStatus(); + // promise is not resolved, no new changes applied + Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending test1"); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this._ai.core + let activeStatus = core.activeStatus && core.activeStatus(); + + if (activeStatus === ActiveStatus.ACTIVE) { + Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); + Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "Init: init with cs promise and offline channel", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + + // unload previous one first + let oriInst = this._ai; + if (oriInst && oriInst.unload) { + // force unload + oriInst.unload(false); + } + + if (oriInst && oriInst["dependencies"]) { + oriInst["dependencies"].teardown(); + } + + this._config = this._getTestConfig(this._sessionPrefix); + let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); + this._config.connectionString = csPromise; + let offlineChannel = new OfflineChannel(); + this._config.channels = [[offlineChannel]]; + this._config.initTimeOut= 80000; let init = new ApplicationInsights({ @@ -298,6 +355,12 @@ export class ApplicationInsightsTests extends AITestClass { if (activeStatus === ActiveStatus.ACTIVE) { Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set"); Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set"); + let sendChannel = this._ai.getPlugin(BreezeChannelIdentifier); + let offlineChannelPlugin = this._ai.getPlugin("OfflineChannel").plugin; + Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized"); + Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized"); + let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0]; + Assert.ok(urlConfig, "offline url config is initialized"); return true; } return false; @@ -326,6 +389,7 @@ export class ApplicationInsightsTests extends AITestClass { let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl"); config.connectionString = csPromise; + config.initTimeOut = 80000; this.clock.tick(1); status = core.activeStatus && core.activeStatus(); Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending"); @@ -369,6 +433,7 @@ export class ApplicationInsightsTests extends AITestClass { this._config.connectionString = null; this._config.instrumentationKey = ikeyPromise; this._config.endpointUrl = endpointPromise; + this._config.initTimeOut= 80000; diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index 061c338f3..ef3d7f236 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -6,7 +6,6 @@ import { BreezeChannelIdentifier, EventPersistence, IConfig, IOfflineListener, createOfflineListener } from "@microsoft/applicationinsights-common"; import { - ActiveStatus, BaseTelemetryPlugin, EventsDiscardedReason, IAppInsightsCore, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationListener, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXHROverride, SendRequestReason, @@ -402,12 +401,12 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _storeNotification(sentItems); } }; - if (payloadData) { + if (payloadData && _urlCfg && _urlCfg.batchHandler) { let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload); _queueStorageEvent("storeBatch", promise); } - if (!_inMemoBatch.count()) { + if (_inMemoBatch && !_inMemoBatch.count()) { _inMemoFlushTimer && _inMemoFlushTimer.cancel(); } @@ -571,8 +570,8 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr function _createUrlConfig(coreConfig: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?: ITelemetryPluginChain) { _self._addHook(onConfigChange(coreConfig, (details) => { - if (!isString(coreConfig.instrumentationKey) || (core.activeStatus && core.activeStatus() === ActiveStatus.PENDING )) { - // if ikey is promise, delay initialization + if (!isString(coreConfig.instrumentationKey) || !isString(coreConfig.endpointUrl)) { + // if ikey or endpointUrl is promise, delay initialization _self.pause(); return; } @@ -623,7 +622,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr handler.initialize(providerContext); urlConfig = { - iKey: coreConfig.instrumentationKey, + iKey: coreConfig.instrumentationKey as string, url: curUrl, minPersistenceCacheLevel: storageConfig.minPersistenceLevel, coreRootCtx: coreRootCtx, diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index f50036dd3..53efba211 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -1573,16 +1573,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", + "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/type-utils": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1606,15 +1606,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", + "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4" }, "engines": { @@ -1634,13 +1634,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1651,13 +1651,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", + "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/utils": "7.13.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1678,9 +1678,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1691,13 +1691,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1755,15 +1755,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1777,12 +1777,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1805,9 +1805,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "peer": true, "bin": { "acorn": "bin/acorn" @@ -2245,9 +2245,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001632", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz", - "integrity": "sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==", + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "funding": [ { "type": "opencollective", @@ -2641,9 +2641,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.799", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.799.tgz", - "integrity": "sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q==" + "version": "1.4.806", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", + "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -2762,15 +2762,18 @@ } }, "node_modules/eslint-plugin-security": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.0.tgz", - "integrity": "sha512-2Ij7PkmXIF2cKwoVkEgemwoXbOnxg5UfdhdcpNxZwJxC/10dbsdhHISrTyJ/n8DUkt3yiN6P1ywEgcMGjIwHIw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz", + "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==", "peer": true, "dependencies": { "safe-regex": "^2.1.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-scope": { @@ -3608,7 +3611,7 @@ "version": "9.1.1", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz", "integrity": "sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==", - "deprecated": "< 22.5.0 is no longer supported", + "deprecated": "< 22.6.4 is no longer supported", "hasInstallScript": true, "dependencies": { "debug": "^4.1.0", @@ -3644,9 +3647,9 @@ } }, "node_modules/grunt-contrib-qunit/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "engines": { "node": ">=8.3.0" }, @@ -5024,7 +5027,7 @@ "version": "19.2.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.2.0.tgz", "integrity": "sha512-rhr5ery8htpOTikmm/wrDU707wtmJ7ccX2WLkBf0A8eYYpscck5/iz04/fHOiIRWMFfnYOvaO9wNb4jcO3Mjyg==", - "deprecated": "< 22.5.0 is no longer supported", + "deprecated": "< 22.6.4 is no longer supported", "hasInstallScript": true, "dependencies": { "cosmiconfig": "7.0.1", @@ -7675,16 +7678,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", + "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", "peer": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/type-utils": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7692,54 +7695,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", + "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", "peer": true, "requires": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" } }, "@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", + "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", "peer": true, "requires": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/utils": "7.13.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "peer": true }, "@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7775,24 +7778,24 @@ } }, "@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" } }, "@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.13.1", "eslint-visitor-keys": "^3.4.3" } }, @@ -7808,9 +7811,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "peer": true }, "acorn-jsx": { @@ -8105,9 +8108,9 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "caniuse-lite": { - "version": "1.0.30001632", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz", - "integrity": "sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==" + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==" }, "chalk": { "version": "4.1.2", @@ -8397,9 +8400,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.799", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.799.tgz", - "integrity": "sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q==" + "version": "1.4.806", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", + "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==" }, "encodeurl": { "version": "1.0.2", @@ -8523,9 +8526,9 @@ } }, "eslint-plugin-security": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.0.tgz", - "integrity": "sha512-2Ij7PkmXIF2cKwoVkEgemwoXbOnxg5UfdhdcpNxZwJxC/10dbsdhHISrTyJ/n8DUkt3yiN6P1ywEgcMGjIwHIw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz", + "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==", "peer": true, "requires": { "safe-regex": "^2.1.1" @@ -9188,9 +9191,9 @@ } }, "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "requires": {} } } diff --git a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts index 1a14619b8..5b117d087 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts @@ -5,7 +5,7 @@ import { IChannelControls } from "../../../src/JavaScriptSDK.Interfaces/IChannel import { _eInternalMessageId, LoggingSeverity } from "../../../src/JavaScriptSDK.Enums/LoggingEnums"; import { _InternalLogMessage, DiagnosticLogger } from "../../../src/JavaScriptSDK/DiagnosticLogger"; import { ActiveStatus } from "../../../src/JavaScriptSDK.Enums/InitActiveStatusEnum"; -import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, doAwaitResponse } from "@nevware21/ts-async"; +import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTimeoutPromise, doAwaitResponse } from "@nevware21/ts-async"; const AIInternalMessagePrefix = "AITR_"; const MaxInt32 = 0xFFFFFFFF; @@ -1031,7 +1031,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1079,7 +1080,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1126,10 +1128,12 @@ export class ApplicationInsightsCoreTests extends AITestClass { let urlPromise = createAsyncRejectedPromise(new Error("endpoint error")); this.ctx.ikeyPromise = ikeyPromise; + this.ctx.urlPromise = urlPromise; let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( @@ -1146,12 +1150,13 @@ export class ApplicationInsightsCoreTests extends AITestClass { let activeStatus = core.activeStatus(); let channelSpy = this.ctx.channelSpy let ikeyPromise = this.ctx.ikeyPromise; + let urlPromise = this.ctx.urlPromise; if (activeStatus === ActiveStatus.INACTIVE) { Assert.deepEqual(core.config.instrumentationKey, ikeyPromise, "channel testIkey should not be changed"); - Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed"); + Assert.deepEqual(core.config.endpointUrl, urlPromise, "channel endpoint should not be changed"); Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); - Assert.ok(core.eventCnt() == 1, "Event should not be released"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); return true; } return false; @@ -1193,7 +1198,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1261,7 +1267,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1307,7 +1314,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: "testIkey", - endpointUrl: "testUrl" + endpointUrl: "testUrl", + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1340,8 +1348,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let channelSpy = this.ctx.channelSpy if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey1"; - core.config.endpointUrl = "testUrl1"; + Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed"); core.track({name: "test2"}); Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); let evt = channelSpy.args[1][0]; @@ -1371,7 +1379,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1452,7 +1461,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1476,8 +1486,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let channelSpy = this.ctx.channelSpy if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey"; - core.config.endpointUrl = "testUrl"; + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); let evt1 = channelSpy.args[0][0]; Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1"); @@ -1515,7 +1525,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let config = { instrumentationKey: ikeyPromise, - endpointUrl: urlPromise + endpointUrl: urlPromise, + initTimeOut: 80000 } as IConfiguration; core.initialize( config, @@ -1544,8 +1555,8 @@ export class ApplicationInsightsCoreTests extends AITestClass { let channelSpy = this.ctx.channelSpy if (activeStatus === ActiveStatus.ACTIVE) { - core.config.instrumentationKey = "testIkey"; - core.config.endpointUrl = "testUrl"; + Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed"); + Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed"); Assert.ok(core.eventCnt() == 0, "Event should not be queued test1"); let evt1 = channelSpy.args[0][0]; Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1"); @@ -1560,6 +1571,93 @@ export class ApplicationInsightsCoreTests extends AITestClass { }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) }); + // this.testCaseAsync({ + // name: "ApplicationInsightsCore Init: init with ikey and endpoint timeout promises", + // stepDelay: 100, + // useFakeTimers: true, + // steps: [() => { + // let trackPlugin = new TrackPlugin(); + // let channelPlugin = new ChannelPlugin(); + // channelPlugin.priority = 1001; + // let core = new AppInsightsCore(); + // let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + // this.ctx.core = core; + // this.ctx.channelSpy = channelSpy; + + // let ikeyPromise = createTimeoutPromise(60, true,"testIkey"); + // let urlPromise = createTimeoutPromise(60, true, "testUrl"); + + // let config = { + // instrumentationKey: ikeyPromise, + // endpointUrl: urlPromise, + // initTimeOut: 1 + // } as IConfiguration; + // core.initialize( + // config, + // [trackPlugin, channelPlugin]); + + + // Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + // Assert.ok(core.eventCnt() == 1, "Event should be queued"); + // let activeStatus = core.activeStatus(); + // Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + // }].concat(PollingAssert.createPollingAssert(() => { + // let core = this.ctx.core; + // let activeStatus = core.activeStatus(); + // let channelSpy = this.ctx.channelSpy; + + // if (activeStatus === ActiveStatus.INACTIVE) { + // Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + // Assert.ok(core.eventCnt() == 0, "Event should be released"); + // return true; + // } + // return false; + // }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + // }); + + // this.testCaseAsync({ + // name: "ApplicationInsightsCore Init: init with ikey promises and endpoint timeout promises", + // stepDelay: 100, + // useFakeTimers: true, + // steps: [() => { + // let channelPlugin = new ChannelPlugin(); + // channelPlugin.priority = 1001; + // let core = new AppInsightsCore(); + // let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + + // let ikeyPromise = createAsyncResolvedPromise("testIkey1"); + // let urlPromise = createTimeoutPromise(20, false, "testUrl1"); + + // let config = { + // instrumentationKey: ikeyPromise, + // endpointUrl: urlPromise, + // initTimeOut: 2 + // } as IConfiguration; + // core.initialize( + // config, + // [channelPlugin]); + // this.ctx.core = core; + // this.ctx.channelSpy = channelSpy; + + // this.clock.tick(1); + // let activeStatus = core.activeStatus(); + // Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + + // }].concat(PollingAssert.createPollingAssert(() => { + // let core = this.ctx.core; + // let activeStatus = core.activeStatus(); + // let channelSpy = this.ctx.channelSpy + + // if (activeStatus === ActiveStatus.INACTIVE) { + // //Assert.equal(activeStatus, ActiveStatus.INACTIVE,"should be set to inactive status"); + // //Assert.equal(!channelSpy.called, "channel should not be called"); + // return true; + // } + // return false; + // }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + // }); + @@ -1904,6 +2002,7 @@ class ChannelPlugin implements IChannelControls { } public _processTelemetry(env: ITelemetryItem) { + console.log(JSON.stringify(env)) } } @@ -2010,7 +2109,6 @@ class TestOfflineChannelPlugin implements IChannelControls { this.events.push(env); // Just calling processTelemetry as this is the original design of the Plugins (as opposed to the newer processNext()) - this._nextPlugin?.processTelemetry(env); } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts index abe98b4c0..257afa082 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts @@ -126,7 +126,8 @@ export const enum _eInternalMessageId { DynamicConfigException = 108, DefaultThrottleMsgKey = 109, CdnDeprecation = 110, - SdkLdrUpdate = 111 + SdkLdrUpdate = 111, + InitPromiseException = 112 } export type _InternalMessageId = number | _eInternalMessageId; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts index 224533c9a..e6eb408a3 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts @@ -195,14 +195,16 @@ export interface IConfiguration { /** * If your connection string, instrumentation key and endpoint url are promises, * this config is to manually set timeout for those promises. - * Default: undefined, initialization process will wait all promises to be finished. + * Default: 50000ms + * @since 3.3.0 */ initTimeOut?: number; /** * If your connection string, instrumentation key and endpoint url are promises, - * this config is to manually set in memory proxy track calls size limit before promises finished. - * Default: undefined + * this config is to manually set in memory proxy track calls count limit before promises finished. + * Default: 100 + * @since 3.3.0 */ initInMemoMaxSize?: number; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index b13b7a1a3..0c41178b0 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -60,7 +60,8 @@ const strValidationError = "Plugins must provide initialize method"; const strNotificationManager = "_notificationManager"; const strSdkUnloadingError = "SDK is still unloading..."; const strSdkNotInitialized = "SDK is not initialized"; -const maxQueueSize = 500; +const maxInitQueueSize = 100; +const maxInitTimeout = 50000; // const strPluginUnloadFailed = "Failed to unload plugin"; /** @@ -296,6 +297,9 @@ export class AppInsightsCore im let _pluginVersionString: string; let _activeStatus: eActiveStatus; // to indicate if ikey or endpoint url promised is resolved or not let _endpoint: string; + let _initInMemoMaxSize: number; // max event count limit during wait for init promises to be resolved + let _isStatusSet: boolean; // track if active status is set in case of init timeout and init promises setting the status twice + let _initTimer: ITimerHandler; /** * Internal log poller @@ -316,13 +320,13 @@ export class AppInsightsCore im _self.isInitialized = () => _isInitialized; - // version 3.3.0 + // since version 3.3.0 _self.activeStatus = () => _activeStatus; - // version 3.3.0 + // since version 3.3.0 // internal _self._setPendingStatus = () => { - _activeStatus = eActiveStatus.PENDING; // allow set pending under NONE? + _activeStatus = eActiveStatus.PENDING; }; // Creating the self.initialize = () @@ -343,32 +347,33 @@ export class AppInsightsCore im // This will be "re-run" if the referenced config properties are changed _addUnloadHook(_configHandler.watch((details) => { - - + let rootCfg = details.cfg; - - // app Insights core only handle ikey and endpointurl - - let ikey = details.cfg.instrumentationKey; - let endpointUrl = details.cfg.endpointUrl; // do not need to validate endpoint url let isPending = _activeStatus === eActiveStatus.PENDING; if (isPending){ - // mean waiting for previous promises to be resolved, won't apply new changes + // means waiting for previous promises to be resolved, won't apply new changes return; } + _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; + // app Insights core only handle ikey and endpointurl, aisku will handle cs + let ikey = rootCfg.instrumentationKey; + let endpointUrl = rootCfg.endpointUrl; // do not need to validate endpoint url, if it is null, default one will be set by sender + if (isNullOrUndefined(ikey)) { + _instrumentationKey = null; + // if new ikey is null, set status to be inactive, all new events will be saved in memory or dropped _activeStatus = ActiveStatus.INACTIVE; + let msg = "Please provide instrumentation key"; + if (!_isInitialized) { - // only throw error during initial initialization - _throwIKeyErrMsg(); + // only throw error during initialization + throwError(msg); } else { - _throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, "ikey can't be null"); + _throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, msg); + _releaseQueues(); } - - // if ikey is null, should we release queue? - _eventQueue = []; return; } @@ -376,64 +381,84 @@ export class AppInsightsCore im let promises: IPromise[] = []; if (isPromiseLike(ikey)) { promises.push(ikey); + _instrumentationKey = null; // reset current local ikey variable (otherwise it will always be the previous ikeys if timeout is called before promise cb) } else { + // string _instrumentationKey = ikey; } if (isPromiseLike(endpointUrl)) { promises.push(endpointUrl); + _endpoint = null; // reset current local endpoint variable (otherwise it will always be the previous urls if timeout is called before promise cb) } else { + // string or null _endpoint = endpointUrl; } - // have at least one promise + // at least have one promise if (promises.length) { + // reset to false for new dynamic changes + _isStatusSet = false; _activeStatus = eActiveStatus.PENDING; + let initTimeout = isNullOrUndefined(rootCfg.initTimeOut)? rootCfg.initTimeOut : maxInitTimeout; // rootCfg.initTimeOut could be 0 let allPromises = createAllSettledPromise(promises); + _initTimer = scheduleTimeout(() => { + // set _isStatusSet to true + // set active status + // release queues + _initTimer = null; + if (!_isStatusSet) { + _setStatus(); + } + + }, initTimeout); + doAwaitResponse(allPromises, (response) => { try { - _instrumentationKey = null; // set current local ikey variable + if (_isStatusSet) { + // promises take too long to resolve, ignore them + // active status should be set by timeout already + return; + } + if (!response.rejected) { let values = response.value; if (values && values.length) { + // ikey let ikeyRes = values[0]; - let ikeyVal = ikeyRes.value; - if (ikeyVal) { - _instrumentationKey = ikeyVal; - config.instrumentationKey = _instrumentationKey; // should not be set to null - } - + _instrumentationKey = ikeyRes && ikeyRes.value; + + // endpoint if (values.length > 1) { let endpointRes = values[1]; - _endpoint = endpointRes.value; - config.endpointUrl = _endpoint; + _endpoint = endpointRes && endpointRes.value; + } } + if (_instrumentationKey) { + // if ikey is null, no need to trigger extra dynamic changes for extensions + config.instrumentationKey = _instrumentationKey; // set config.instrumentationKey for extensions to consume + config.endpointUrl = _endpoint; // set config.endpointUrl for extensions to consume + } } - if (isNullOrUndefined(_instrumentationKey)) { - _activeStatus = ActiveStatus.INACTIVE; - _throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, "ikey can't be resolved from promises"); - } else { - _activeStatus = ActiveStatus.ACTIVE; - _self.releaseQueue(); - _self.pollInternalLogs(); - } + // set _isStatusSet to true + // set active status + // release queues + _setStatus(); } catch (e) { - // eslint-disable-next-line - _activeStatus = ActiveStatus.INACTIVE; + if (!_isStatusSet){ + _setStatus(); + } } }); } else { // means no promises - _activeStatus = ActiveStatus.ACTIVE; - _self.releaseQueue(); - _self.pollInternalLogs(); - + _setStatus(); } @@ -482,8 +507,7 @@ export class AppInsightsCore im _isInitialized = true; if (_activeStatus === ActiveStatus.ACTIVE) { - _self.releaseQueue(); - _self.pollInternalLogs(); + _releaseQueues(); } }; @@ -527,8 +551,8 @@ export class AppInsightsCore im _createTelCtx().processNext(telemetryItem); } else if (_activeStatus !== ActiveStatus.INACTIVE){ // Queue events until all extensions are initialized - if (_eventQueue.length <= maxQueueSize) { - // set limit, 500, if full, stop adding new events + if (_eventQueue.length <= _initInMemoMaxSize) { + // set limit, if full, stop adding new events _eventQueue.push(telemetryItem); } @@ -600,11 +624,18 @@ export class AppInsightsCore im if (_isInitialized && _eventQueue.length > 0) { let eventQueue = _eventQueue; _eventQueue = []; + if (_activeStatus === eActiveStatus.ACTIVE) { + arrForEach(eventQueue, (event: ITelemetryItem) => { + event.iKey = event.iKey || _instrumentationKey; + _createTelCtx().processNext(event); + }); - arrForEach(eventQueue, (event: ITelemetryItem) => { - event.iKey = event.iKey || _instrumentationKey; - _createTelCtx().processNext(event); - }); + } else { + // new one for msg ikey + _throwInternal(_logger, eLoggingSeverity.WARNING, _eInternalMessageId.FailedToSendQueuedTelemetry, "core init status is not active"); + } + + } }; @@ -616,8 +647,23 @@ export class AppInsightsCore im return _startLogPoller(true); }; - function _throwIKeyErrMsg() { - throwError("Please provide instrumentation key"); + function _setStatus() { + _isStatusSet = true; + if (isNullOrUndefined(_instrumentationKey)) { + _activeStatus = ActiveStatus.INACTIVE; + _throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InitPromiseException, "ikey can't be resolved from promises"); + } else { + _activeStatus = ActiveStatus.ACTIVE; + } + _releaseQueues(); + + } + + function _releaseQueues() { + if (_isInitialized) { + _self.releaseQueue(); + _self.pollInternalLogs(); + } } function _startLogPoller(alwaysStart?: boolean): ITimerHandler { @@ -989,6 +1035,9 @@ export class AppInsightsCore im _internalLogPollerListening = false; _activeStatus = eActiveStatus.NONE; // default is None _endpoint = null; + _initInMemoMaxSize = null; + _isStatusSet = false; + _initTimer = null; } function _createTelCtx(): IProcessTelemetryContext { From 2bed091016ab2437adfda5778a4983b1e060a89d Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 21 Jun 2024 14:53:33 -0700 Subject: [PATCH 09/16] update --- .../Tests/Unit/src/ajax.tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts index 18fd5b559..56ce1572c 100644 --- a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts +++ b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts @@ -218,7 +218,8 @@ export class AjaxTests extends AITestClass { let csPromise = createAsyncResolvedPromise("testIkey"); let appInsightsCore = new AppInsightsCore(); let coreConfig = { - instrumentationKey: csPromise + instrumentationKey: csPromise, + initTimeOut: 80000 }; appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]); @@ -255,7 +256,6 @@ export class AjaxTests extends AITestClass { let data = trackStub.args[0][0].baseData; Assert.equal(data.type, "Ajax", "request type should be ajax"); Assert.ok(data.properties, "properties should be added"); - console.log(JSON.stringify(data)) return true; } return false; From 30b2197f828aff36a8a07177a27f1d096bd6c455 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Fri, 21 Jun 2024 15:38:02 -0700 Subject: [PATCH 10/16] update --- .../Tests/Unit/src/Sender.tests.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts index 3d0dc88ee..4cf71a8b6 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/Sender.tests.ts @@ -176,6 +176,7 @@ export class SenderTests extends AITestClass { let coreConfig = { instrumentationKey: ikeyPromise, endpointUrl: urlPromise, + initTimeOut: 80000, extensionConfig: {} } core.initialize(coreConfig, [this._sender]); From 7cab4e0958c76c51026f1d5ed2657f3c487bee24 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Sun, 23 Jun 2024 10:28:39 -0700 Subject: [PATCH 11/16] update --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 8 ++++---- shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index 5d8e30c6c..1748db697 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -5,10 +5,10 @@ import { Snippet } from "../../../src/Snippet"; import { utlRemoveSessionStorage } from "@microsoft/applicationinsights-common"; export class AISKUSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 142; - private readonly MAX_BUNDLE_SIZE = 142; - private readonly MAX_RAW_DEFLATE_SIZE = 57; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 57; + private readonly MAX_RAW_SIZE = 143; + private readonly MAX_BUNDLE_SIZE = 143; + private readonly MAX_RAW_DEFLATE_SIZE = 58; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 58; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; // Automatically updated by version scripts private readonly currentVer = "3.2.2"; diff --git a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts index 21da21f9d..a5a37f460 100644 --- a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts +++ b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts @@ -2,8 +2,8 @@ import { AITestClass } from "@microsoft/ai-test-framework"; import * as pako from 'pako'; export class FileSizeCheckTest extends AITestClass { - private readonly MAX_BUNDLE_SIZE = 67; - private readonly MAX_DEFLATE_SIZE = 28; + private readonly MAX_BUNDLE_SIZE = 68; + private readonly MAX_DEFLATE_SIZE = 29; private readonly bundleFilePath = "../bundle/es5/ms.core.min.js"; public testInitialize() { From 1d84dd08344118f6ad3db85971bf7b1801f29e2f Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Sun, 23 Jun 2024 11:27:10 -0700 Subject: [PATCH 12/16] update --- .../Tests/Unit/src/applicationinsights.e2e.tests.ts | 12 ++++++------ channels/offline-channel-js/src/OfflineChannel.ts | 7 +++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index 27c1e4004..6055b0c41 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -508,7 +508,7 @@ export class ApplicationInsightsTests extends AITestClass { }); this.testCase({ - name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with endpoint url", + name: "Init Promise: Offline Support can be added and initialized with endpoint url", useFakeTimers: true, test: () => { this.clock.tick(1); @@ -540,13 +540,13 @@ export class ApplicationInsightsTests extends AITestClass { if (ai && ai["dependencies"]) { ai["dependencies"].teardown(); } - offlineChannel.teardown(); + //offlineChannel.teardown(); } }); this.testCase({ - name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with channels", + name: "Init Promise: Offline Support can be added and initialized with channels", useFakeTimers: true, test: () => { this.clock.tick(1); @@ -578,7 +578,6 @@ export class ApplicationInsightsTests extends AITestClass { if (ai && ai["dependencies"]) { ai["dependencies"].teardown(); } - offlineChannel.teardown(); } }); @@ -590,7 +589,7 @@ export class ApplicationInsightsTests extends AITestClass { this.clock.tick(1); let offlineChannel = new OfflineChannel(); let config = { - instrumentationKey: "testIKey", + connectionString: "InstrumentationKey=testIKey", extensionConfig:{ ["AppInsightsCfgSyncPlugin"]: { cfgUrl: "" @@ -608,13 +607,14 @@ export class ApplicationInsightsTests extends AITestClass { Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized"); Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized"); let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0]; + + this.clock.tick(1); Assert.ok(urlConfig, "offline url config is initialized"); ai.unload(false); if (ai && ai["dependencies"]) { ai["dependencies"].teardown(); } - offlineChannel.teardown(); } }); diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index ef3d7f236..23562d893 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -448,8 +448,11 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr } } - let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst); - _queueStorageEvent("sendNextBatch", promise); + if (_urlCfg && _urlCfg.batchHandler) { + let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst); + _queueStorageEvent("sendNextBatch", promise); + } + } } else { From 60c658967b6af462317aad5614d0db37f9b428f0 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 25 Jun 2024 09:49:53 -0700 Subject: [PATCH 13/16] update --- AISKU/src/AISku.ts | 47 +++-- .../src/ajax.ts | 1 + .../src/applicationinsights-common.ts | 1 + .../Unit/src/ApplicationInsightsCore.Tests.ts | 164 +++++++++--------- .../src/JavaScriptSDK/AppInsightsCore.ts | 4 +- 5 files changed, 118 insertions(+), 99 deletions(-) diff --git a/AISKU/src/AISku.ts b/AISKU/src/AISku.ts index 5e24b3eb8..669620af2 100644 --- a/AISKU/src/AISku.ts +++ b/AISKU/src/AISku.ts @@ -7,8 +7,8 @@ import { AnalyticsPlugin, ApplicationInsights } from "@microsoft/applicationinsi import { CfgSyncPlugin, ICfgSyncConfig, ICfgSyncMode } from "@microsoft/applicationinsights-cfgsync-js"; import { Sender } from "@microsoft/applicationinsights-channel-js"; import { - AnalyticsPluginIdentifier, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry, IEventTelemetry, - IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders, + AnalyticsPluginIdentifier, ConnectionString, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry, + IEventTelemetry, IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders, ITelemetryContext as Common_ITelemetryContext, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig, ITraceTelemetry, PropertiesPluginIdentifier, ThrottleMgr, parseConnectionString } from "@microsoft/applicationinsights-common"; @@ -201,33 +201,48 @@ export class AppInsightsSku implements IApplicationInsights { // Will get recalled if any referenced values are changed _addUnloadHook(onConfigChange(cfgHandler, () => { let configCs = _config.connectionString; - - if (isPromiseLike(configCs)) { - let ikeyPromise = createAsyncPromise((resolve, reject) => { + + function _parseCs() { + return createAsyncPromise((resolve, reject) => { doAwaitResponse(configCs, (res) => { - let curCs = res.value; - let ikey = _config.instrumentationKey; + let curCs = res && res.value; + let parsedCs = null; if (!res.rejected && curCs) { // replace cs with resolved values in case of circular promises _config.connectionString = curCs; - let resolvedCs = parseConnectionString(curCs); - ikey = resolvedCs.instrumentationkey || ikey; + parsedCs = parseConnectionString(curCs); } + // if can't resolve cs promise, null will be returned + resolve(parsedCs); + }); + }); + + } + + if (isPromiseLike(configCs)) { + let ikeyPromise = createAsyncPromise((resolve, reject) => { + _parseCs().then((cs) => { + let ikey = _config.instrumentationKey; + ikey = cs && cs.instrumentationkey || ikey; resolve(ikey); + }).catch((e) => { + // parseCs will always resolve(unless timeout) + // return null in case any error happens + resolve(null); }); }); let urlPromise = createAsyncPromise((resolve, reject) => { - doAwaitResponse(configCs, (res) => { - let curCs = res.value; + _parseCs().then((cs) => { let url = _config.endpointUrl; - if (!res.rejected && curCs) { - let resolvedCs = parseConnectionString(curCs); - let ingest = resolvedCs.ingestionendpoint; - url = ingest? ingest + DEFAULT_BREEZE_PATH : url; - } + let ingest = cs && cs.ingestionendpoint; + url = ingest? ingest + DEFAULT_BREEZE_PATH : url; resolve(url); + }).catch((e) => { + // parseCs will always resolve(unless timeout) + // return null in case any error happens + resolve(null); }); }); diff --git a/extensions/applicationinsights-dependencies-js/src/ajax.ts b/extensions/applicationinsights-dependencies-js/src/ajax.ts index 2586c995f..6f15f9f46 100644 --- a/extensions/applicationinsights-dependencies-js/src/ajax.ts +++ b/extensions/applicationinsights-dependencies-js/src/ajax.ts @@ -599,6 +599,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu if (_enableAjaxPerfTracking) { let iKey = config.instrumentationKey || "unkwn"; // only change the ikey if it is string + // TODO: handle ikey promise if (isString(iKey)) { if (iKey.length > 5) { _markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + "."; diff --git a/shared/AppInsightsCommon/src/applicationinsights-common.ts b/shared/AppInsightsCommon/src/applicationinsights-common.ts index 293037127..32af7d137 100644 --- a/shared/AppInsightsCommon/src/applicationinsights-common.ts +++ b/shared/AppInsightsCommon/src/applicationinsights-common.ts @@ -7,6 +7,7 @@ export { } from "./Util"; export { ThrottleMgr } from "./ThrottleMgr"; export { parseConnectionString, ConnectionStringParser } from "./ConnectionStringParser"; +export { ConnectionString } from "./Interfaces/ConnectionString"; export { FieldType } from "./Enums"; export { IRequestHeaders, RequestHeaders, eRequestHeaders } from "./RequestResponseHeaders"; export { DisabledPropertyName, ProcessLegacy, SampleRate, HttpMethod, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, strNotSpecified } from "./Constants"; diff --git a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts index 5b117d087..75b018548 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts @@ -1571,92 +1571,94 @@ export class ApplicationInsightsCoreTests extends AITestClass { }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) }); - // this.testCaseAsync({ - // name: "ApplicationInsightsCore Init: init with ikey and endpoint timeout promises", - // stepDelay: 100, - // useFakeTimers: true, - // steps: [() => { - // let trackPlugin = new TrackPlugin(); - // let channelPlugin = new ChannelPlugin(); - // channelPlugin.priority = 1001; - // let core = new AppInsightsCore(); - // let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); - // this.ctx.core = core; - // this.ctx.channelSpy = channelSpy; - - // let ikeyPromise = createTimeoutPromise(60, true,"testIkey"); - // let urlPromise = createTimeoutPromise(60, true, "testUrl"); - - // let config = { - // instrumentationKey: ikeyPromise, - // endpointUrl: urlPromise, - // initTimeOut: 1 - // } as IConfiguration; - // core.initialize( - // config, - // [trackPlugin, channelPlugin]); + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey and endpoint timeout promises", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let trackPlugin = new TrackPlugin(); + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let ikeyPromise = createTimeoutPromise(60, true,"testIkey"); + let urlPromise = createTimeoutPromise(60, true, "testUrl"); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise, + initTimeOut: 1 + } as IConfiguration; + core.initialize( + config, + [trackPlugin, channelPlugin]); - // Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); - // Assert.ok(core.eventCnt() == 1, "Event should be queued"); - // let activeStatus = core.activeStatus(); - // Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 1, "Event should be queued"); + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); - // }].concat(PollingAssert.createPollingAssert(() => { - // let core = this.ctx.core; - // let activeStatus = core.activeStatus(); - // let channelSpy = this.ctx.channelSpy; + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy; - // if (activeStatus === ActiveStatus.INACTIVE) { - // Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); - // Assert.ok(core.eventCnt() == 0, "Event should be released"); - // return true; - // } - // return false; - // }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) - // }); - - // this.testCaseAsync({ - // name: "ApplicationInsightsCore Init: init with ikey promises and endpoint timeout promises", - // stepDelay: 100, - // useFakeTimers: true, - // steps: [() => { - // let channelPlugin = new ChannelPlugin(); - // channelPlugin.priority = 1001; - // let core = new AppInsightsCore(); - // let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); - - // let ikeyPromise = createAsyncResolvedPromise("testIkey1"); - // let urlPromise = createTimeoutPromise(20, false, "testUrl1"); - - // let config = { - // instrumentationKey: ikeyPromise, - // endpointUrl: urlPromise, - // initTimeOut: 2 - // } as IConfiguration; - // core.initialize( - // config, - // [channelPlugin]); - // this.ctx.core = core; - // this.ctx.channelSpy = channelSpy; - - // this.clock.tick(1); - // let activeStatus = core.activeStatus(); - // Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); - - // }].concat(PollingAssert.createPollingAssert(() => { - // let core = this.ctx.core; - // let activeStatus = core.activeStatus(); - // let channelSpy = this.ctx.channelSpy + if (activeStatus === ActiveStatus.INACTIVE) { + Assert.ok(!channelSpy.calledOnce, "channel should not be called once"); + Assert.ok(core.eventCnt() == 0, "Event should be released"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); + + this.testCaseAsync({ + name: "ApplicationInsightsCore Init: init with ikey timeout promises and endpoint promises", + stepDelay: 100, + useFakeTimers: true, + steps: [() => { + let channelPlugin = new ChannelPlugin(); + channelPlugin.priority = 1001; + let core = new AppInsightsCore(); + let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry"); + + let ikeyPromise = createTimeoutPromise(20, true, "testIkey1"); + let urlPromise = createTimeoutPromise(1, true, "testUrl1"); + + let config = { + instrumentationKey: ikeyPromise, + endpointUrl: urlPromise, + initTimeOut: 6 + } as IConfiguration; + core.initialize( + config, + [channelPlugin]); + this.ctx.core = core; + this.ctx.channelSpy = channelSpy; + + let activeStatus = core.activeStatus(); + Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending"); + Assert.ok(!channelSpy.calledOnce, "channel should not be called"); + core.track({name: "testEvent"}); + + + }].concat(PollingAssert.createPollingAssert(() => { + let core = this.ctx.core; + let activeStatus = core.activeStatus(); + let channelSpy = this.ctx.channelSpy - // if (activeStatus === ActiveStatus.INACTIVE) { - // //Assert.equal(activeStatus, ActiveStatus.INACTIVE,"should be set to inactive status"); - // //Assert.equal(!channelSpy.called, "channel should not be called"); - // return true; - // } - // return false; - // }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) - // }); + if (activeStatus === ActiveStatus.INACTIVE) { + Assert.ok(core.eventCnt() == 0, "Event should be released"); + Assert.ok(!channelSpy.called, "channel should not be called"); + return true; + } + return false; + }, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any) + }); diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 0c41178b0..b8686f885 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -42,7 +42,7 @@ import { createCookieMgr } from "./CookieMgr"; import { createUniqueNamespace } from "./DataCacheHelper"; import { getDebugListener } from "./DbgExtensionUtils"; import { DiagnosticLogger, _InternalLogMessage, _throwInternal, _warnToConsole } from "./DiagnosticLogger"; -import { getSetValue, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs"; +import { getSetValue, isNotNullOrUndefined, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs"; import { STR_CHANNELS, STR_CREATE_PERF_MGR, STR_DISABLED, STR_EMPTY, STR_EXTENSIONS, STR_EXTENSION_CONFIG, UNDEFINED_VALUE } from "./InternalConstants"; @@ -400,7 +400,7 @@ export class AppInsightsCore im // reset to false for new dynamic changes _isStatusSet = false; _activeStatus = eActiveStatus.PENDING; - let initTimeout = isNullOrUndefined(rootCfg.initTimeOut)? rootCfg.initTimeOut : maxInitTimeout; // rootCfg.initTimeOut could be 0 + let initTimeout = isNotNullOrUndefined(rootCfg.initTimeOut)? rootCfg.initTimeOut : maxInitTimeout; // rootCfg.initTimeOut could be 0 let allPromises = createAllSettledPromise(promises); _initTimer = scheduleTimeout(() => { // set _isStatusSet to true From 41a94c92e3209bd7f584dd83173309c7e86b6ba0 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 25 Jun 2024 09:54:54 -0700 Subject: [PATCH 14/16] update --- common/config/rush/npm-shrinkwrap.json | 192 ++++++++++++------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 9ed9b9001..4bfc03d9a 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -1573,16 +1573,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", - "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", + "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/type-utils": "7.13.1", - "@typescript-eslint/utils": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/type-utils": "7.14.1", + "@typescript-eslint/utils": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1606,15 +1606,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", - "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", + "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4" }, "engines": { @@ -1634,13 +1634,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1651,13 +1651,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", - "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", + "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/utils": "7.14.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1678,9 +1678,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1691,13 +1691,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1755,15 +1755,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1777,12 +1777,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2641,9 +2641,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.808", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.808.tgz", - "integrity": "sha512-0ItWyhPYnww2VOuCGF4s1LTfbrdAV2ajy/TN+ZTuhR23AHI6rWHCrBXJ/uxoXOvRRqw8qjYVrG81HFI7x/2wdQ==" + "version": "1.4.811", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz", + "integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -4142,9 +4142,9 @@ "peer": true }, "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" }, "node_modules/jsonfile": { "version": "4.0.0", @@ -7681,16 +7681,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", - "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", + "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", "peer": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/type-utils": "7.13.1", - "@typescript-eslint/utils": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/type-utils": "7.14.1", + "@typescript-eslint/utils": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7698,54 +7698,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", - "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", + "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", "peer": true, "requires": { - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", - "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" } }, "@typescript-eslint/type-utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", - "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", + "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", "peer": true, "requires": { - "@typescript-eslint/typescript-estree": "7.13.1", - "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/utils": "7.14.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", - "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "peer": true }, "@typescript-eslint/typescript-estree": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", - "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/visitor-keys": "7.13.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7781,24 +7781,24 @@ } }, "@typescript-eslint/utils": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", - "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.1", - "@typescript-eslint/types": "7.13.1", - "@typescript-eslint/typescript-estree": "7.13.1" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" } }, "@typescript-eslint/visitor-keys": { - "version": "7.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", - "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "peer": true, "requires": { - "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" } }, @@ -8403,9 +8403,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.808", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.808.tgz", - "integrity": "sha512-0ItWyhPYnww2VOuCGF4s1LTfbrdAV2ajy/TN+ZTuhR23AHI6rWHCrBXJ/uxoXOvRRqw8qjYVrG81HFI7x/2wdQ==" + "version": "1.4.811", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz", + "integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA==" }, "encodeurl": { "version": "1.0.2", @@ -9533,9 +9533,9 @@ "peer": true }, "jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" }, "jsonfile": { "version": "4.0.0", From bcf4a15242c36d6b2431cc3374611f7916e4a83e Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 25 Jun 2024 13:59:36 -0700 Subject: [PATCH 15/16] update --- AISKU/src/AISku.ts | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/AISKU/src/AISku.ts b/AISKU/src/AISku.ts index 669620af2..ad01ee30d 100644 --- a/AISKU/src/AISku.ts +++ b/AISKU/src/AISku.ts @@ -232,23 +232,26 @@ export class AppInsightsSku implements IApplicationInsights { }); }); - - let urlPromise = createAsyncPromise((resolve, reject) => { - _parseCs().then((cs) => { - let url = _config.endpointUrl; - let ingest = cs && cs.ingestionendpoint; - url = ingest? ingest + DEFAULT_BREEZE_PATH : url; - resolve(url); - }).catch((e) => { - // parseCs will always resolve(unless timeout) - // return null in case any error happens - resolve(null); + + let url: IPromise | string = _config.userOverrideEndpointUrl; + if (isNullOrUndefined(url)) { + url = createAsyncPromise((resolve, reject) => { + _parseCs().then((cs) => { + let url = _config.endpointUrl; + let ingest = cs && cs.ingestionendpoint; + url = ingest? ingest + DEFAULT_BREEZE_PATH : url; + resolve(url); + }).catch((e) => { + // parseCs will always resolve(unless timeout) + // return null in case any error happens + resolve(null); + }); + }); - - }); + } _config.instrumentationKey = ikeyPromise; - _config.endpointUrl = _config.userOverrideEndpointUrl || urlPromise; + _config.endpointUrl = url; } if (isString(configCs)) { From 65715f3334eef95df13f09dd43d7b4bc4661f1be Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 25 Jun 2024 14:59:07 -0700 Subject: [PATCH 16/16] update --- .../Tests/Unit/src/ajax.tests.ts | 2 +- .../applicationinsights-dependencies-js/src/ajax.ts | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts index 56ce1572c..cb2386453 100644 --- a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts +++ b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/ajax.tests.ts @@ -210,7 +210,7 @@ export class AjaxTests extends AITestClass { }); this.testCaseAsync({ - name: "Dependencies Configuration: init with cs promise ikey promise", + name: "Dependencies Configuration: init with cs promise ikey promise and default enableAjaxPerfTracking", stepDelay: 100, useFakeTimers: true, steps: [() => { diff --git a/extensions/applicationinsights-dependencies-js/src/ajax.ts b/extensions/applicationinsights-dependencies-js/src/ajax.ts index 6f15f9f46..576e4709c 100644 --- a/extensions/applicationinsights-dependencies-js/src/ajax.ts +++ b/extensions/applicationinsights-dependencies-js/src/ajax.ts @@ -597,15 +597,12 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu _isUsingW3CHeaders = _distributedTracingMode === eDistributedTracingModes.AI_AND_W3C || _distributedTracingMode === eDistributedTracingModes.W3C; if (_enableAjaxPerfTracking) { - let iKey = config.instrumentationKey || "unkwn"; - // only change the ikey if it is string + let iKey = (config.instrumentationKey as string) || "unkwn"; // TODO: handle ikey promise - if (isString(iKey)) { - if (iKey.length > 5) { - _markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + "."; - } else { - _markPrefix = AJAX_MONITOR_PREFIX + iKey + "."; - } + if (iKey.length > 5) { + _markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + "."; + } else { + _markPrefix = AJAX_MONITOR_PREFIX + iKey + "."; } }