From d7fe4e3a94d79f94b3c748eb386a75a254bb6db1 Mon Sep 17 00:00:00 2001 From: Nev <54870357+MSNev@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:38:12 -0800 Subject: [PATCH 1/2] [Main] Merge 1ds-core-js into applicationinsights-core-ts (#2712) * [Main] Merge 1ds-core-js into applicationinsights-core-js Phase 1: Move files to keep history * Phase 2: Update imports, fix compile issues and delete unused * Phase 3: Move a few more files around * Phase 4: adjust imports from Phase 3 * Phase 5: Update 1ds-core-js README.md --- .aiAutoMinify.json | 10 +- rush.json | 4 +- .../otel-core/Tests/Unit/src/ext/CoreTest.ts | 231 ++++++ .../Tests/Unit/src/ext/DynamicProtoTests.ts | 539 ++++++++++++ .../Unit/src/ext/ESPromiseSchedulerTests.ts | 200 +++++ .../Tests/Unit/src/ext/ESPromiseTests.ts | 435 ++++++++++ .../Unit/src/ext/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/ext/SpanUtilsTests.ts | 765 ++++++++++++++++++ .../Tests/Unit/src/ext/TestHelper.ts | 93 +++ .../otel-core/Tests/Unit/src/ext/UtilsTest.ts | 228 ++++++ .../Tests/Unit/src/ext/ValueSanitizerTests.ts | 356 ++++++++ .../otel-core/Tests/Unit/src/index.tests.ts | 18 + .../src/constants/InternalConstants.ts | 6 +- .../otel-core/src/core/SenderPostManager.ts | 3 +- shared/otel-core/src/enums/ai/Enums.ts | 3 +- .../src/enums/ai/SendRequestReason.ts | 19 - shared/otel-core/src/enums/ext/Enums.ts | 369 +++++++++ .../otel-core/src/ext/AppInsightsExtCore.ts | 123 +++ shared/otel-core/src/ext/ValueSanitizer.ts | 366 +++++++++ shared/otel-core/src/ext/extSpanUtils.ts | 515 ++++++++++++ shared/otel-core/src/ext/extUtils.ts | 433 ++++++++++ shared/otel-core/src/index.ts | 45 +- .../src/interfaces/ai/ISenderPostManager.ts | 2 +- .../src/interfaces/ext/DataModels.ts | 286 +++++++ shared/otel-core/src/utils/HelperFuncs.ts | 2 +- 25 files changed, 5035 insertions(+), 29 deletions(-) create mode 100644 shared/otel-core/Tests/Unit/src/ext/CoreTest.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/DynamicProtoTests.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/ESPromiseTests.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/GlobalTestHooks.Test.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/SpanUtilsTests.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/TestHelper.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/UtilsTest.ts create mode 100644 shared/otel-core/Tests/Unit/src/ext/ValueSanitizerTests.ts create mode 100644 shared/otel-core/src/enums/ext/Enums.ts create mode 100644 shared/otel-core/src/ext/AppInsightsExtCore.ts create mode 100644 shared/otel-core/src/ext/ValueSanitizer.ts create mode 100644 shared/otel-core/src/ext/extSpanUtils.ts create mode 100644 shared/otel-core/src/ext/extUtils.ts create mode 100644 shared/otel-core/src/interfaces/ext/DataModels.ts diff --git a/.aiAutoMinify.json b/.aiAutoMinify.json index 0a1ebf362..575ef6218 100644 --- a/.aiAutoMinify.json +++ b/.aiAutoMinify.json @@ -58,11 +58,19 @@ "eLoggingSeverity", "_eInternalMessageId", "SendRequestReason", - "TransportType", "eStatsType", "TelemetryUnloadReason", "TelemetryUpdateReason", "eTraceHeadersMode", + "eValueKind", + "EventLatencyValue", + "eEventPropertyType", + "EventSendType", + "eTraceLevel", + "_eExtendedInternalMessageId", + "GuidStyle", + "FieldValueSanitizerType", + "TransportType", "eAttributeChangeOp", "eOTelSeverityNumber", "eOTelSamplingDecision", diff --git a/rush.json b/rush.json index 7c98ef9bb..1b1aadc99 100644 --- a/rush.json +++ b/rush.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", - "npmVersion": "9.9.3", - "rushVersion": "5.167.0", + "npmVersion": "9.9.4", + "rushVersion": "5.169.3", "projectFolderMaxDepth": 4, "projects": [ { diff --git a/shared/otel-core/Tests/Unit/src/ext/CoreTest.ts b/shared/otel-core/Tests/Unit/src/ext/CoreTest.ts new file mode 100644 index 000000000..21cb506f5 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/CoreTest.ts @@ -0,0 +1,231 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { AppInsightsCore as AIInternalCore, AppInsightsExtCore, EventLatency, FullVersionString, IChannelControls, IExtendedConfiguration, IExtendedTelemetryItem, IPropertyStorageOverride, blockDynamicConversion } from '../../../../src/index'; +import dynamicProto from "@microsoft/dynamicproto-js"; + +export class CoreTest extends AITestClass { + + private channelExtension: IChannelControls; + private channelExtensionWithVer: IChannelControls; + + public testInitialize() { + // As the class is using dynamicProto we need to construct at least 1 instance + // before we can override/replace any prototype method as they are not populated + // until the 1st instance is created. + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + // As we are now using the module as is we need to reach inside the current instance to get the correct instance of applicationinsights-core-js + QUnit.assert.notEqual(Object.getPrototypeOf(new AIInternalCore()).initialize, undefined, 'The prototype method must exist for the instance'); + QUnit.assert.notEqual(AIInternalCore.prototype.initialize, undefined, 'The prototype method must exist'); + + this.channelExtension = blockDynamicConversion({ + pause: () => { }, + resume: () => { }, + teardown: () => { }, + flush: (async: any, callBack: any) => { }, + processTelemetry: (env: any) => { }, + setNextPlugin: (next: any) => { }, + initialize: (config: any, core: any, extensions: any) => { }, + identifier: "testChannel", + priority: 501 + }); + + this.channelExtensionWithVer = blockDynamicConversion({ + pause: () => { }, + resume: () => { }, + teardown: () => { }, + flush: (async: any, callBack: any) => { }, + processTelemetry: (env: any) => { }, + setNextPlugin: (next: any) => { }, + initialize: (config: any, core: any, extensions: any) => { }, + identifier: "testChannel", + priority: 501, + version: "channelVer" + }); + } + + public registerTests() { + this.testCase({ + name: "initialize test", + test: () => { + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + + let coreTrackSpy = this.sandbox.spy(AIInternalCore.prototype, 'initialize'); + var core: AppInsightsExtCore = new AppInsightsExtCore(); + + // As we are now using the module as is we need to reach inside the current instance to get the correct instance of applicationinsights-core-js + QUnit.assert.notEqual(AIInternalCore.prototype.initialize, Object.getPrototypeOf(core).initialize, 'The prototype method must not be the same as the current instance'); + + var testPropertyStorageOverride: IPropertyStorageOverride = { + setProperty: (key: string, value: string) => { + + }, + getProperty: (key: string) => { + return 'test property'; + } + }; + var config: IExtendedConfiguration = { + instrumentationKey: 'testIkey', + propertyStorageOverride: testPropertyStorageOverride + }; + core.initialize(config, [this.channelExtension]); + QUnit.assert.equal(coreTrackSpy.called, true, "Expecting AI initialize was called"); + var actualConfig: IExtendedConfiguration = coreTrackSpy.getCall(0).args[0]; + QUnit.assert.equal(actualConfig.endpointUrl, "https://browser.events.data.microsoft.com/OneCollector/1.0/"); + QUnit.assert.equal(actualConfig.instrumentationKey, "testIkey"); + if (actualConfig.propertyStorageOverride) { + QUnit.assert.ok(actualConfig.propertyStorageOverride.getProperty('testKey') === 'test property'); + } + QUnit.assert.equal(core.getWParam(), 0); + } + }); + + this.testCase({ + name: "Dynamic Config Test", + useFakeTimers: true, + test: () => { + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + + let coreTrackSpy = this.sandbox.spy(AIInternalCore.prototype, 'initialize'); + let config: IExtendedConfiguration = {}; + let expectedIkey: string = "test"; + let expectedEndpointUrl: string = "https://browser.events.data.microsoft.com/OneCollector/1.0/"; + let expectedPropertyStorageOverride: IPropertyStorageOverride; + let core: AppInsightsExtCore = new AppInsightsExtCore(); + + let onChangeCalled = 0; + let handler = core.onCfgChange((details) => { + onChangeCalled ++; + QUnit.assert.equal(expectedIkey, details.cfg.instrumentationKey, `onChangeCalled ${onChangeCalled} times: Expect the iKey to be set`); + QUnit.assert.equal(expectedEndpointUrl, details.cfg.endpointUrl, `onChangeCalled ${onChangeCalled} times: Expect the endpoint to be set`); + QUnit.assert.deepEqual(expectedPropertyStorageOverride, details.cfg.propertyStorageOverride, `onChangeCalled ${onChangeCalled} times: Expect the propertyStorageOverride to be set`); + }); + + // Check defaults + config = {instrumentationKey: expectedIkey} + core.initialize(config, [this.channelExtension]); + QUnit.assert.equal(coreTrackSpy.called, true, "Expecting AI initialize was called"); + QUnit.assert.equal(1, onChangeCalled, "oncfgChange should be called 1 times"); + + // Check config changes + expectedPropertyStorageOverride = { + setProperty: (key: string, value: string) => { + }, + getProperty: (key: string) => { + return 'test property'; + } + }; + expectedEndpointUrl = "https://testendpoint.com"; + expectedIkey = "test1"; + core.config.instrumentationKey = expectedIkey; + core.config.endpointUrl = expectedEndpointUrl; + core.config.propertyStorageOverride = expectedPropertyStorageOverride; + this.clock.tick(1); + QUnit.assert.equal(onChangeCalled, 2, "onConfigChange Called 2 times"); + + } + }); + + + this.testCase({ + name: "track test", + test: () => { + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + let coreTrackSpy = this.sandbox.spy(AIInternalCore.prototype, 'track'); + var core: AppInsightsExtCore = new AppInsightsExtCore(); + + QUnit.assert.notEqual(AIInternalCore.prototype.track, Object.getPrototypeOf(core).track, 'The prototype method must not be the same as the current instance'); + + var config: IExtendedConfiguration = { + instrumentationKey: 'testIkey' + }; + core.initialize(config, [this.channelExtension]); + var telemetryItem: IExtendedTelemetryItem = { + name: 'testEvent', + baseType: 'testEventBaseType' + }; + core.track(telemetryItem); + QUnit.assert.equal(coreTrackSpy.called, true, "Expecting the AI Core was called"); + var actualEvent: IExtendedTelemetryItem = coreTrackSpy.getCall(0).args[0]; + QUnit.assert.equal(actualEvent.name, "testEvent"); + QUnit.assert.equal(actualEvent.latency, EventLatency.Normal); + QUnit.assert.ok(actualEvent.ext['sdk']['ver'].indexOf('1DS-Web-JS') > -1); + QUnit.assert.equal(actualEvent.ext['sdk']['ver'], FullVersionString, actualEvent.ext['sdk']['ver']); + QUnit.assert.equal(isNaN(actualEvent.timings.trackStart as number), false); + QUnit.assert.equal(actualEvent.baseData['properties']['version'], '', actualEvent.baseData['properties']['version']); + } + }); + + this.testCase({ + name: "track test with provided item properties version", + test: () => { + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + let coreTrackSpy = this.sandbox.spy(AIInternalCore.prototype, 'track'); + var core: AppInsightsExtCore = new AppInsightsExtCore(); + + QUnit.assert.notEqual(AIInternalCore.prototype.track, Object.getPrototypeOf(core).track, 'The prototype method must not be the same as the current instance'); + + var config: IExtendedConfiguration = { + instrumentationKey: 'testIkey' + }; + + core.initialize(config, [this.channelExtensionWithVer]); + var telemetryItem: IExtendedTelemetryItem = { + name: 'testEvent', + baseType: 'testEventBaseType', + baseData:{} + }; + telemetryItem.baseData['properties'] = {version:'version1'}; + core.track(telemetryItem); + QUnit.assert.equal(coreTrackSpy.called, true, "Expecting the AI Core was called"); + var actualEvent: IExtendedTelemetryItem = coreTrackSpy.getCall(0).args[0]; + QUnit.assert.equal(actualEvent.name, "testEvent"); + QUnit.assert.ok(actualEvent.ext['sdk']['ver'].indexOf('1DS-Web-JS') > -1); + QUnit.assert.equal(actualEvent.ext['sdk']['ver'], FullVersionString, actualEvent.ext['sdk']['ver']); + QUnit.assert.equal(actualEvent.baseData['properties']['version'], 'version1', actualEvent.baseData['properties']['version']); + } + }); + + this.testCase({ + name: "track test with provided plugin version and no item properties version", + test: () => { + this._disableDynProtoBaseFuncs(dynamicProto); // We need to disable the useBaseInst performance setting as the sinon spy fools the internal logic and the spy is bypassed + let coreTrackSpy = this.sandbox.spy(AIInternalCore.prototype, 'track'); + var core: AppInsightsExtCore = new AppInsightsExtCore(); + + QUnit.assert.notEqual(AIInternalCore.prototype.track, Object.getPrototypeOf(core).track, 'The prototype method must not be the same as the current instance'); + + var config: IExtendedConfiguration = { + instrumentationKey: 'testIkey' + }; + core.initialize(config, [this.channelExtensionWithVer]); + var telemetryItem: IExtendedTelemetryItem = { + name: 'testEvent', + baseType: 'testEventBaseType' + }; + core.track(telemetryItem); + QUnit.assert.equal(coreTrackSpy.called, true, "Expecting the AI Core was called"); + var actualEvent: IExtendedTelemetryItem = coreTrackSpy.getCall(0).args[0]; + QUnit.assert.equal(actualEvent.name, "testEvent"); + QUnit.assert.ok(actualEvent.ext['sdk']['ver'].indexOf('1DS-Web-JS') > -1); + QUnit.assert.equal(actualEvent.ext['sdk']['ver'], FullVersionString, actualEvent.ext['sdk']['ver']); + QUnit.assert.equal(actualEvent.baseData['properties']['version'], 'testChannel=channelVer', actualEvent.baseData['properties']['version']); + } + }); + + this.testCase({ + name: "Check inheritence implementation", + test: () => { + var core1: AppInsightsExtCore = new AppInsightsExtCore(); + var core2: AppInsightsExtCore = new AppInsightsExtCore(); + + // Make sure the 2 initialize methods are actually different function instances + QUnit.assert.ok(!core1.hasOwnProperty("initialize"), "initialize should not be an instance function"); + QUnit.assert.ok(!core2.hasOwnProperty("initialize"), "initialize should not be an instance function"); + QUnit.assert.equal(core1.initialize, core2.initialize, "initialize function should be the same (i.e. prototype based methods)"); + + QUnit.assert.ok(!core1.hasOwnProperty("track"), "track should not be an instance function"); + QUnit.assert.ok(!core2.hasOwnProperty("track"), "track should not be an instance function"); + QUnit.assert.equal(core1.track, core2.track, "track function should be the same (i.e. prototype based methods)"); + } + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/DynamicProtoTests.ts b/shared/otel-core/Tests/Unit/src/ext/DynamicProtoTests.ts new file mode 100644 index 000000000..a46cb7d4c --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/DynamicProtoTests.ts @@ -0,0 +1,539 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import dynamicProto from '@microsoft/dynamicproto-js'; + +interface IInheritTest { + executionOrder:string[]; + testFunction?(): void; +} + +class InheritTest1 implements IInheritTest { + public executionOrder:string[] = []; + + constructor() { + this.executionOrder.push("InheritTest1()"); + } + + public testFunction() { + this.executionOrder.push("InheritTest1.test()"); + } +} + +class InheritTest2 extends InheritTest1 { + constructor() { + super(); + this.executionOrder.push("InheritTest2()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest2.test()"); + } +} + +class InheritTest3 extends InheritTest2 { + constructor() { + super(); + this.executionOrder.push("InheritTest3()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest3.test()"); + } +} + +class DynInheritTest1 implements IInheritTest { + public executionOrder:string[] = []; + + public testFunction?(): void; + + constructor() { + this.executionOrder.push("DynInheritTest1()"); + dynamicProto(DynInheritTest1, this, (_self, base) => { + _self.testFunction = () => { + this.executionOrder.push("DynInheritTest1.test()"); + } + }); + } +} + +class InheritTest4 extends DynInheritTest1 { + constructor() { + super(); + this.executionOrder.push("InheritTest4()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest4.test()"); + } +} + +class InheritTest5 extends InheritTest4 { + constructor() { + super(); + this.executionOrder.push("InheritTest5()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest5.test()"); + } +} + +class DynInheritTest2 extends InheritTest1 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest2()"); + dynamicProto(DynInheritTest2, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest2.test()"); + } + }); + } +} + +class DynInheritTest3 extends DynInheritTest2 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest3()"); + dynamicProto(DynInheritTest3, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest3.test()"); + } + }); + } +} + +class InheritTest6 extends DynInheritTest2 { + constructor() { + super(); + this.executionOrder.push("InheritTest6()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest6.test()"); + } +} + +class DynInheritTest4 extends InheritTest6 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest4()"); + dynamicProto(DynInheritTest4, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest4.test()"); + } + }); + } +} + +class DynInheritTest5 extends DynInheritTest1 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest5()"); + dynamicProto(DynInheritTest5, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest5.test()"); + } + }); + } +} + +class DynInheritTest6 extends DynInheritTest5 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest6()"); + dynamicProto(DynInheritTest6, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest6.test()"); + } + }); + } +} + +class InstInherit1 implements IInheritTest { + public executionOrder:string[] = []; + + public testFunction?():void; + + constructor() { + this.executionOrder.push("InstInherit1()"); + + this.testFunction = () => { + this.executionOrder.push("InstInherit1.test()"); + } + } +} + +class InstInherit2 extends InheritTest2 { + constructor() { + super(); + this.executionOrder.push("InstInherit2()"); + + this.testFunction = () => { + super.testFunction(); + this.executionOrder.push("InstInherit2.test()"); + } + } +} + +class InheritTest7 extends InstInherit1 { + constructor() { + super(); + this.executionOrder.push("InheritTest7()"); + } + + public testFunction() { + super.testFunction(); + this.executionOrder.push("InheritTest7.test()"); + } +} + +class DynInheritTest7 extends InstInherit1 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest7()"); + dynamicProto(DynInheritTest7, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest7.test()"); + } + }); + } +} + +class InstInherit3 extends DynInheritTest7 { + constructor() { + super(); + this.executionOrder.push("InstInherit3()"); + + this.testFunction = () => { + super.testFunction(); + this.executionOrder.push("InstInherit3.test()"); + } + } +} + +class DynInheritTest8 extends InstInherit3 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest8()"); + dynamicProto(DynInheritTest8, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest8.test()"); + } + }); + } +} + +class BadInstInherit1 extends InstInherit1 { + constructor() { + super(); + this.executionOrder.push("BadInstInherit1()"); + + this.testFunction = () => { + try { + super.testFunction(); + } catch (e) { + this.executionOrder.push("BadInstInherit1.throw()"); + } + this.executionOrder.push("BadInstInherit1.test()"); + } + } +} + +class DynInheritTest9 extends BadInstInherit1 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest9()"); + dynamicProto(DynInheritTest9, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest9.test()"); + } + }); + } +} + +class GoodInstInherit1 extends InstInherit1 { + constructor() { + super(); + this.executionOrder.push("GoodInstInherit1()"); + + let prevTestFunc = this.testFunction; + this.testFunction = () => { + prevTestFunc.call(this); + this.executionOrder.push("GoodInstInherit1.test()"); + } + } +} + +class DynInheritTest10 extends GoodInstInherit1 { + constructor() { + super(); + this.executionOrder.push("DynInheritTest10()"); + dynamicProto(DynInheritTest10, this, (_self, base) => { + _self.testFunction = () => { + base.testFunction(); + this.executionOrder.push("DynInheritTest10.test()"); + } + }); + } +} + +class GoodInstInherit2 extends DynInheritTest10 { + constructor() { + super(); + this.executionOrder.push("GoodInstInherit2()"); + + let prevTestFunc = this.testFunction; + this.testFunction = () => { + prevTestFunc.call(this); + this.executionOrder.push("GoodInstInherit2.test()"); + } + } +} + +export class DynamicProtoTests extends AITestClass { + + public testInitialize() { + } + + private _validateOrder(message:string, actual:string[], expected:string[]) { + QUnit.assert.equal(actual.length, expected.length, message + ": Checking the length"); + + let passed = true; + let error = ""; + for (let lp = 0; lp < expected.length; lp++) { + if (lp < actual.length) { + if (actual[lp] !== expected[lp]) { + passed = false + error += " **[" + actual[lp] + "!=" + expected[lp] + "]**;" + } else { + error += " " + expected[lp] + ";"; + } + } else { + passed = false; + error += " --[" + expected[lp] + "]--;" + } + } + + // Fail test and log any extra unexpected calls + for (let lp = expected.length; lp < actual.length; lp++) { + passed = false; + error += " ++[" + actual[lp] + "]++;" + } + + QUnit.assert.ok(passed, message + ":" + error); + } + + private doTest(message:string, theTest:IInheritTest, expectedOrder:string[]) + { + theTest.testFunction(); + this._validateOrder(message, theTest.executionOrder, expectedOrder); + } + + public registerTests() { + this.testCase({ + name: "Inheritance tests", + test: () => { + this.doTest("InheritTest1", new InheritTest1(), [ + "InheritTest1()", + "InheritTest1.test()" + ]); + + this.doTest("InheritTest2", new InheritTest2(), [ + "InheritTest1()", + "InheritTest2()", + "InheritTest1.test()", + "InheritTest2.test()" + ]); + + this.doTest("InheritTest3", new InheritTest3(), [ + "InheritTest1()", + "InheritTest2()", + "InheritTest3()", + "InheritTest1.test()", + "InheritTest2.test()", + "InheritTest3.test()" + ]); + + this.doTest("InheritTest4", new InheritTest4(), [ + "DynInheritTest1()", + "InheritTest4()", + "DynInheritTest1.test()", + "InheritTest4.test()" + ]); + + this.doTest("InheritTest5", new InheritTest5(), [ + "DynInheritTest1()", + "InheritTest4()", + "InheritTest5()", + "DynInheritTest1.test()", + "InheritTest4.test()", + "InheritTest5.test()" + ]); + + this.doTest("DynInheritTest1", new DynInheritTest1(), [ + "DynInheritTest1()", + "DynInheritTest1.test()" + ]); + + this.doTest("DynInheritTest2", new DynInheritTest2(), [ + "InheritTest1()", + "DynInheritTest2()", + "InheritTest1.test()", + "DynInheritTest2.test()" + ]); + + this.doTest("DynInheritTest3", new DynInheritTest3(), [ + "InheritTest1()", + "DynInheritTest2()", + "DynInheritTest3()", + "InheritTest1.test()", + "DynInheritTest2.test()", + "DynInheritTest3.test()" + ]); + + this.doTest("InheritTest6", new InheritTest6(), [ + "InheritTest1()", + "DynInheritTest2()", + "InheritTest6()", + "InheritTest1.test()", + "DynInheritTest2.test()", + "InheritTest6.test()" + ]); + + this.doTest("DynInheritTest4", new DynInheritTest4(), [ + "InheritTest1()", + "DynInheritTest2()", + "InheritTest6()", + "DynInheritTest4()", + "InheritTest1.test()", + "DynInheritTest2.test()", + "InheritTest6.test()", + "DynInheritTest4.test()" + ]); + + this.doTest("DynInheritTest5", new DynInheritTest5(), [ + "DynInheritTest1()", + "DynInheritTest5()", + "DynInheritTest1.test()", + "DynInheritTest5.test()" + ]); + + this.doTest("DynInheritTest6", new DynInheritTest6(), [ + "DynInheritTest1()", + "DynInheritTest5()", + "DynInheritTest6()", + "DynInheritTest1.test()", + "DynInheritTest5.test()", + "DynInheritTest6.test()" + ]); + + + this.doTest("InstInherit1", new InstInherit1(), [ + "InstInherit1()", + "InstInherit1.test()" + ]); + + this.doTest("InstInherit2", new InstInherit2(), [ + "InheritTest1()", + "InheritTest2()", + "InstInherit2()", + "InheritTest1.test()", + "InheritTest2.test()", + "InstInherit2.test()" + ]); + + // NOTE: Notice that InheritTest7.test() was not called -- this is because TS doesn't handle this + this.doTest("InheritTest7", new InheritTest7(), [ + "InstInherit1()", + "InheritTest7()", + "InstInherit1.test()" + ]); + + // NOTE: Notice that DynInheritTest7.test() IS called -- this is because dynamicProto handles this scenario + this.doTest("DynInheritTest7", new DynInheritTest7(), [ + "InstInherit1()", + "DynInheritTest7()", + "InstInherit1.test()", + "DynInheritTest7.test()" + ]); + + this.doTest("InstInherit3", new InstInherit3(), [ + "InstInherit1()", + "DynInheritTest7()", + "InstInherit3()", + "InstInherit1.test()", + "DynInheritTest7.test()", + "InstInherit3.test()" + ]); + + this.doTest("DynInheritTest8", new DynInheritTest8(), [ + "InstInherit1()", + "DynInheritTest7()", + "InstInherit3()", + "DynInheritTest8()", + "InstInherit1.test()", + "DynInheritTest7.test()", + "InstInherit3.test()", + "DynInheritTest8.test()" + ]); + + // Note: Bad inherit as with InheritTest7 fails to call base instance and actually throws in this case + this.doTest("BadInstInherit1", new BadInstInherit1(), [ + "InstInherit1()", + "BadInstInherit1()", + "BadInstInherit1.throw()", + "BadInstInherit1.test()" + ]); + + // Note: dynamicProto doesn't fix broken base classes, but it still calls them in the correct order + this.doTest("DynInheritTest9", new DynInheritTest9(), [ + "InstInherit1()", + "BadInstInherit1()", + "DynInheritTest9()", + "BadInstInherit1.throw()", + "BadInstInherit1.test()", + "DynInheritTest9.test()" + ]); + + this.doTest("GoodInstInherit1", new GoodInstInherit1(), [ + "InstInherit1()", + "GoodInstInherit1()", + "InstInherit1.test()", + "GoodInstInherit1.test()" + ]); + + this.doTest("DynInheritTest10", new DynInheritTest10(), [ + "InstInherit1()", + "GoodInstInherit1()", + "DynInheritTest10()", + "InstInherit1.test()", + "GoodInstInherit1.test()", + "DynInheritTest10.test()" + ]); + + this.doTest("GoodInstInherit2", new GoodInstInherit2(), [ + "InstInherit1()", + "GoodInstInherit1()", + "DynInheritTest10()", + "GoodInstInherit2()", + "InstInherit1.test()", + "GoodInstInherit1.test()", + "DynInheritTest10.test()", + "GoodInstInherit2.test()", + ]); + } + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts b/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts new file mode 100644 index 000000000..3d0db7ab5 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts @@ -0,0 +1,200 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { DiagnosticLogger } from '../../../../src/index'; +import { strIndexOf } from '@nevware21/ts-utils'; +import { createAsyncPromise, createNativePromise, createNativeResolvedPromise, createTaskScheduler } from '@nevware21/ts-async'; + +export function makeRegex(value: string) { + if (value && value.length > 0) { + // Escape any slashes first! + value = value.replace(/\\/g, "\\\\"); + // eslint-disable-next-line security/detect-non-literal-regexp + value = value.replace(/([\+\?\|\{\}\[\]\(\)\^\$\#\.\=\!\:\/])/g, "\\$1"); + value = value.replace(/\*/g, ".*"); + return new RegExp("(" + value + ")"); + } + + return null; +} +export class ESPromiseSchedulerTests extends AITestClass { + private _traceLogger: DiagnosticLogger; + + public testInitialize() { + this._traceLogger = new DiagnosticLogger({ loggingLevelConsole: 1 }); + } + + public registerTests() { + this.testCase({ + name: "Test that the scheduler waits for the events correctly", + test: () => { + let scheduler = createTaskScheduler(createAsyncPromise, "test1"); + + let order:string[] = []; + let expectedOrder:string[] = []; + expectedOrder.push("sch1"); + expectedOrder.push("sch2"); + expectedOrder.push("sch3"); + expectedOrder.push("sch4"); + expectedOrder.push("wait"); + expectedOrder.push("test1"); + expectedOrder.push("finished1"); + expectedOrder.push("test2"); + expectedOrder.push("sch2.1"); + expectedOrder.push("wait2.1"); + expectedOrder.push("sch2.2"); + expectedOrder.push("finished2.1"); + expectedOrder.push("finished2"); + expectedOrder.push("test3"); + expectedOrder.push("sch3.1"); + expectedOrder.push("finished3"); + expectedOrder.push("test4"); + expectedOrder.push("sch4.1"); + expectedOrder.push("reject4-Timeout: Task [test1.0.3-(t4)] - Running: * ms"); + expectedOrder.push("test2.2"); + expectedOrder.push("sch2.3"); + expectedOrder.push("reject2.2-Timeout: Task [test1.0.4-(2.2)] - Running: * ms"); + expectedOrder.push("test3.1"); + expectedOrder.push("finished3.1"); + expectedOrder.push("test4.1"); + expectedOrder.push("wait4.2"); + expectedOrder.push("sch4.3"); + expectedOrder.push("finished4.2"); + expectedOrder.push("finished4.1"); + expectedOrder.push("wait2.3"); + expectedOrder.push("test2.3"); + expectedOrder.push("finished2.3"); + expectedOrder.push("test4.3"); + expectedOrder.push("finished4.3"); + + let testWait = createNativePromise((testComplete) => { + order.push("sch1"); + scheduler.queue(() => { + return createNativePromise((test1Complete) => { + setTimeout(() => { + order.push("test1"); + test1Complete("t1.complete"); + }, 20); + }); + }, "t1").then(() => { + order.push("finished1"); + }); + order.push("sch2"); + scheduler.queue(() => { + order.push("test2"); + order.push("sch2.1"); + return createNativePromise((t21Resolve) => { + order.push("wait2.1"); + setTimeout(() => { + order.push("sch2.2"); + scheduler.queue(() => { + order.push("test2.2"); + order.push("sch2.3"); + return scheduler.queue(() => { + return createNativePromise((t23Resolve) => { + order.push("wait2.3"); + setTimeout(() => { + order.push("test2.3"); + t23Resolve("2.3.complete"); + }, 1) + }); + }, "2.3").then(() => { + order.push("finished2.3"); + }, (reason) => { + order.push("reject2.3-" + reason); + }); + }, "2.2", 10).then(() => { + order.push("finished2.2"); + }, (reason) => { + order.push("reject2.2-" + reason); + }); + t21Resolve(); + }, 1); + }).then(() => { + order.push("finished2.1"); + }, (reason) => { + order.push("reject2.1-" + reason); + }); + }, "t2").then(() => { + order.push("finished2"); + }, (reason) => { + order.push("reject2-" + reason); + }); + order.push("sch3"); + scheduler.queue(() => { + order.push("test3"); + order.push("sch3.1"); + scheduler.queue(() => { + order.push("test3.1"); + return createNativeResolvedPromise("t3.1.complete"); + }, "3.1").then(() => { + order.push("finished3.1"); + }, (reason) => { + order.push("reject3.1-" + reason); + }); + return createNativeResolvedPromise("t3.complete"); + }, "t3", 10).then(() => { + order.push("finished3"); + }, (reason) => { + order.push("reject3-" + reason); + }); + + order.push("sch4"); + scheduler.queue(() => { + order.push("test4"); + order.push("sch4.1"); + // Note because this is returning the scheduling result (promise) it will actually run immediately (this avoids avoid deadlocking) as the test2 event is not complete yet + // which means there is actually no "waiting" scheduled event + return scheduler.queue(() => { + order.push("test4.1"); + return createNativePromise((t42Resolve) => { + order.push("wait4.2"); + setTimeout(() => { + order.push("sch4.3"); + scheduler.queue(() => { + order.push("test4.3"); + return createNativeResolvedPromise("resolved"); + }, "4.3").then(() => { + order.push("finished4.3"); + testComplete("t4.3.complete"); + }, (reason) => { + order.push("reject4.3-" + reason); + testComplete("t4.3.complete"); + }); + // Just resolve this one + t42Resolve(); + }, 1) + }).then(() => { + order.push("finished4.2") + }, (reason) => { + order.push("reject4.2-" + reason); + }); + }, "t4.1").then(() => { + order.push("finished4.1"); + }, (reason) => { + order.push("reject4.1-" + reason); + }); + }, "t4", 10).then(() => { + order.push("finished4"); + }, (reason) => { + order.push("reject4-" + reason); + }); + }); + + order.push("wait"); + return testWait.then(() => { + QUnit.assert.equal(order.length, expectedOrder.length, "Expecting all scheduled event have completed"); + for (let lp = 0; lp < expectedOrder.length; lp++) { + if (order.length > lp) { + if (strIndexOf(expectedOrder[lp], "*")) { + QUnit.assert.ok(makeRegex(expectedOrder[lp])!.test(order[lp]), "Checking - " + order[lp]); + } else { + QUnit.assert.equal(order[lp], expectedOrder[lp], expectedOrder[lp]); + } + } else { + QUnit.assert.ok(false, "Missing expected result - " + expectedOrder[lp]); + } + } + }) as PromiseLike; + } + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/ESPromiseTests.ts b/shared/otel-core/Tests/Unit/src/ext/ESPromiseTests.ts new file mode 100644 index 000000000..584ef0d49 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/ESPromiseTests.ts @@ -0,0 +1,435 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { createAsyncAllPromise, createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, IPromise } from '@nevware21/ts-async'; + +export class ESPromiseTests extends AITestClass { + + public testInitialize() { + } + + public registerTests() { + this.testCase({ + name: "Test promise with invalid resolver", + useFakeTimers: true, + test: () => { + try { + let promise = createAsyncPromise(undefined as any); + QUnit.assert.ok(false, "expected an exception to be thrown with undefined"); + } catch(e) { + QUnit.assert.ok(e.message.indexOf("is not a function") != -1, "Expected the exception message to include reason for failure - " + e.message); + } + + try { + let promise = createAsyncPromise(null as any); + QUnit.assert.ok(false, "expected an exception to be thrown with null"); + } catch(e) { + QUnit.assert.ok(e.message.indexOf("is not a function") != -1, "Expected the exception message to include reason for failure - " + e.message); + } + + try { + let promise = createAsyncPromise(42); + QUnit.assert.ok(false, "expected an exception to be thrown with null"); + } catch(e) { + QUnit.assert.ok(e.message.indexOf("is not a function") != -1, "Expected the exception message to include reason for failure - " + e.message); + } + } + }); + + this.testCase({ + name: "Test resolving promise", + useFakeTimers: true, + test: () => { + let promise: IPromise; + let resolvedValue = null; + let rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + resolvedValue = value; + return value; + }, (value) => { + rejectedValue = value; + return value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, 42, "Expected the promise to be resolved"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected"); + + resolvedValue = null; + rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + resolvedValue = value; + return value; + }).catch((value) => { + rejectedValue = value; + return value; + }) + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, 42, "Expected the promise to be resolved"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected"); + } + }); + + this.testCase({ + name: "Test rejecting promise", + useFakeTimers: true, + test: () => { + let promise: IPromise; + let resolvedValue: number | null = null; + let rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + reject(-42); + }).then((value) => { + resolvedValue = value; + return value; + }, (value) => { + rejectedValue = value; + return value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved"); + QUnit.assert.equal(rejectedValue, -42, "Expected the promise to be rejected"); + + resolvedValue = null; + rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + reject(-42); + }).then((value) => { + resolvedValue = value; + return value; + }).catch((value) => { + rejectedValue = value; + return value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved"); + QUnit.assert.equal(rejectedValue, -42, "Expected the promise to be rejected"); + } + }); + + this.testCase({ + name: "Test rejecting promise by throwing", + useFakeTimers: true, + test: () => { + let promise: IPromise = null; + let resolvedValue: number | null = null; + let rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + throw new Error("Simulated failure!"); + }).then((value) => { + resolvedValue = value; + return value; + }, (value) => { + rejectedValue = value; + return value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved"); + QUnit.assert.ok(rejectedValue != null, "Expected the promise to be rejected with a value"); + QUnit.assert.ok(rejectedValue.message.indexOf("Simulated failure!") != -1, "Expected the promise to be rejected with the contained exception"); + + resolvedValue = null; + rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + throw new Error("Simulated failure!"); + }).then((value) => { + resolvedValue = value; + return value; + }).catch((value) => { + rejectedValue = value; + return value; + }) + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved"); + QUnit.assert.ok(rejectedValue != null, "Expected the promise to be rejected with a value"); + QUnit.assert.ok(rejectedValue.message.indexOf("Simulated failure!") != -1, "Expected the promise to be rejected with the contained exception"); + } + }); + + this.testCase({ + name: "Test resolving promise with a returned value", + useFakeTimers: true, + test: () => { + let promise: IPromise = null; + let subPromise: IPromise = null; + let resolvedValue: any = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + return 53; + }).then((value) => { + resolvedValue = value; + return value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, 53, "Expected the promise to be resolved with the returned value not the initial resolved value"); + + resolvedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + // Don't return anything + }).then((value) => { + resolvedValue = value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + + // Cause the async promise execution to occur + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, undefined, "Expected the promise to be resolved with undefined from the Promise returned by the initial then"); + } + }); + + this.testCase({ + name: "Test resolving promise with a promise", + useFakeTimers: true, + test: () => { + let promise: IPromise = null; + let preResolved: IPromise = createAsyncResolvedPromise(53); + let preRejected: IPromise = createAsyncRejectedPromise(new Error("Simulated Pre Rejected Promise...")); + // Handle the rejected promise to avoid test failure + preRejected.catch(() => {}); + + let resolvedValue = null; + let rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + return preResolved; + }).then((value) => { + resolvedValue = value; + }, + (value) => { + rejectedValue = value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(10); + QUnit.assert.equal(resolvedValue, 53, "Expected the promise to be resolved"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + resolvedValue = null; + rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + return preRejected; + }).then((value) => { + resolvedValue = value; + }, + (value) => { + rejectedValue = value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur + this.clock.tick(10); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to be resolved"); + QUnit.assert.ok(rejectedValue != null, "Expected the promise to be rejected with a value"); + QUnit.assert.ok(rejectedValue.message.indexOf("Simulated Pre Rejected Promise") != -1, "Expected the promise to be rejected with the contained exception"); + + let unresolvedPromise = createAsyncPromise((resolve, reject) => { + setTimeout(() => { + resolve(68); + }, 2000); + }) + resolvedValue = null; + rejectedValue = null; + promise = createAsyncPromise((resolve, reject) => { + resolve(42); + }).then((value) => { + return unresolvedPromise; + }).then((value) => { + resolvedValue = value; + }, + (value) => { + rejectedValue = value; + }); + + // Should not be resolved or rejected yet as this should happen asynchronously + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Cause the async promise execution to occur, but not enough for the unresolved promise + this.clock.tick(100); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // let some more time pass but still not enough for the unresolved promise + this.clock.tick(1000); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Now lets trigger the unresolved promise + this.clock.tick(1000); + QUnit.assert.equal(resolvedValue, 68, "Expected the promise to be resolved"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + } + }); + + this.testCase({ + name: "Testing waiting for multiple promises", + useFakeTimers: true, + test: () => { + let workerPromises: IPromise[] = []; + let workerResolved: boolean[] = []; + let resolvedValue:any = null; + + // Create the promises + for (let lp = 0; lp < 10; lp++) { + workerResolved[lp] = false; + workerPromises[lp] = createAsyncPromise((resolve, reject) => { + setTimeout(() => { + // Wait to resolve this promise + workerResolved[lp] = true; + resolve(lp); + }, (lp + 1) * 1000); + }) + } + + // Create the uber waiting promise + let thePromise: IPromise = createAsyncAllPromise(workerPromises); + thePromise.then((value) => { + resolvedValue = value; + }); + + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + + for (let lp = 0; lp < 10; lp++) { + this.clock.tick(100); + QUnit.assert.equal(workerResolved[lp], false, "Worker not resolved yet"); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet - " + lp); + this.clock.tick(899); + QUnit.assert.equal(workerResolved[lp], false, "Worker not resolved yet"); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet - " + lp); + // This will cause the worker promise to get resolved + this.clock.tick(1); + QUnit.assert.equal(workerResolved[lp], true, "Worker now resolved"); + } + + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + this.clock.tick(50); + QUnit.assert.ok(resolvedValue != null, "Expected the promise to be resolved"); + for (let lp = 0; lp < 10; lp++) + { + QUnit.assert.equal(resolvedValue[lp], lp, "Value mismatch"); + } + } + }); + + this.testCase({ + name: "Testing waiting for multiple promises where one rejects", + useFakeTimers: true, + test: () => { + let workerPromises: IPromise[] = []; + let workerResolved: boolean[] = []; + let resolvedValue:any = null; + let rejectedValue:any = null; + + // Create the promises + for (let lp = 0; lp < 10; lp++) { + workerResolved[lp] = false; + workerPromises[lp] = createAsyncPromise((resolve, reject) => { + setTimeout(() => { + // Wait to resolve this promise + workerResolved[lp] = true; + if (lp == 5) + { + reject(new Error("Simulated Rejection")); + return; + } + + resolve(lp); + }, (lp + 1) * 1000); + }) + } + + // Create the uber waiting promise + let thePromise: IPromise = createAsyncAllPromise(workerPromises); + thePromise.then((value) => { + resolvedValue = value; + }, + (value) => { + rejectedValue = value; + }); + + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + for (let lp = 0; lp < 5; lp++) { + this.clock.tick(100); + QUnit.assert.equal(workerResolved[lp], false, "Worker not resolved yet"); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet - " + lp); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet - " + lp); + this.clock.tick(899); + QUnit.assert.equal(workerResolved[lp], false, "Worker not resolved yet"); + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet - " + lp); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet - " + lp); + // This will cause the worker promise to get resolved + this.clock.tick(1); + QUnit.assert.equal(workerResolved[lp], true, "Worker now resolved"); + } + + QUnit.assert.equal(resolvedValue, null, "Expected the promise to not be resolved yet"); + QUnit.assert.equal(rejectedValue, null, "Expected the promise to not be rejected yet"); + + // Now lets cause the rejected promise to run + this.clock.tick(1500); + QUnit.assert.ok(resolvedValue == null, "Expected the promise to not be resolved"); + QUnit.assert.ok(rejectedValue != null, "Expected the promise to be rejected"); + QUnit.assert.ok(rejectedValue.message.indexOf("Simulated Rejection") != -1, "Main promise should have rejected with the rejected error"); + } + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/GlobalTestHooks.Test.ts b/shared/otel-core/Tests/Unit/src/ext/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..1e31a24c8 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "../../../../src/index"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/SpanUtilsTests.ts b/shared/otel-core/Tests/Unit/src/ext/SpanUtilsTests.ts new file mode 100644 index 000000000..1056703ce --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/SpanUtilsTests.ts @@ -0,0 +1,765 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { Assert, AITestClass } from "@microsoft/ai-test-framework"; +import { getDeferred, ICachedValue, objDefine, strSubstr } from "@nevware21/ts-utils"; +import { + IAppInsightsCore, + IReadableSpan, + eOTelSpanKind, + eOTelSpanStatusCode, + IDistributedTraceContext, + createDistributedTraceContext, + generateW3CId, + SEMATTRS_HTTP_METHOD, + SEMATTRS_HTTP_URL, + SEMATTRS_HTTP_STATUS_CODE, + SEMATTRS_DB_SYSTEM, + SEMATTRS_DB_STATEMENT, + SEMATTRS_DB_NAME, + SEMATTRS_RPC_SYSTEM, + SEMATTRS_RPC_GRPC_STATUS_CODE, + SEMATTRS_NET_PEER_NAME, + SEMATTRS_NET_PEER_PORT, + ATTR_HTTP_REQUEST_METHOD, + ATTR_HTTP_RESPONSE_STATUS_CODE, + ATTR_URL_FULL, + ATTR_ENDUSER_ID, + ATTR_ENDUSER_PSEUDO_ID, + SEMATTRS_HTTP_ROUTE, + ATTR_CLIENT_ADDRESS, + AppInsightsCore, + IConfiguration, + ITraceProvider, + ITraceHost, + IOTelSpanOptions, + createSpan, + IOTelSpanCtx, + IOTelApi, + IOTelConfig +} from "../../../../src/index"; +import { createExtendedTelemetryItemFromSpan, IMsWebSpanTelemetry } from "../../../../src/ext/extSpanUtils"; +import { IExtendedTelemetryItem } from "../../../../src/interfaces/ext/DataModels"; + +export class SpanUtilsTests extends AITestClass { + private _core!: AppInsightsCore; + private _mockApi!: IOTelApi; + private _onEndCalls!: IReadableSpan[]; + + public testInitialize() { + super.testInitialize(); + + this._onEndCalls = []; + + // Create mock API + this._mockApi = { + cfg: { + errorHandlers: {} + } as IOTelConfig + } as IOTelApi; + } + + public testCleanup() { + super.testCleanup(); + this._onEndCalls = []; + + // Clean up AppInsightsCore instance if initialized + if (this._core && this._core.isInitialized()) { + this._core.unload(false); + } + this._core = undefined as any; + } + + /** + * Helper function to create a trace provider with onEnd callback + */ + private _createTestTraceProvider(host: ITraceHost, onEnd?: (span: IReadableSpan) => void): ICachedValue { + const actualOnEnd = onEnd || ((span) => this._onEndCalls.push(span)); + + return getDeferred(() => { + const provider: ITraceProvider = { + api: this._mockApi, + createSpan: (name: string, options?: IOTelSpanOptions, parent?: IDistributedTraceContext): IReadableSpan => { + // Create a new distributed trace context for this span + let newCtx: IDistributedTraceContext; + let parentCtx: IDistributedTraceContext | undefined; + + if (options && options.root) { + newCtx = createDistributedTraceContext(); + } else { + newCtx = createDistributedTraceContext(parent || host.getTraceCtx()); + if (newCtx.parentCtx) { + parentCtx = newCtx.parentCtx; + } + } + + // Always generate a new spanId + newCtx.spanId = strSubstr(generateW3CId(), 0, 16); + + // Get configuration from the core if available + let isRecording = options?.recording !== false; + if (this._core && this._core.config && this._core.config.traceCfg && this._core.config.traceCfg.suppressTracing) { + isRecording = false; + } + + // Create the span context + const spanCtx: IOTelSpanCtx = { + api: this._mockApi, + spanContext: newCtx, + attributes: options?.attributes, + startTime: options?.startTime, + isRecording: isRecording, + onEnd: actualOnEnd + }; + + if (parentCtx) { + objDefine(spanCtx, "parentSpanContext", { + v: parentCtx, + w: false + }); + } + + return createSpan(spanCtx, name, options?.kind || eOTelSpanKind.INTERNAL); + }, + getProviderId: (): string => "test-provider", + isAvailable: (): boolean => true + }; + + return provider; + }); + } + + /** + * Helper function to set up AppInsightsCore with trace provider + */ + private _setupCore(config?: Partial): AppInsightsCore { + this._core = new AppInsightsCore(); + + // Create a simple test channel + const testChannel = { + identifier: "TestChannel", + priority: 1001, + initialize: () => {}, + processTelemetry: () => {}, + teardown: () => {}, + isInitialized: () => true + }; + + const coreConfig: IConfiguration = { + instrumentationKey: "test-ikey-12345", + traceCfg: { + serviceName: "test-service" + }, + ...config + }; + + // Initialize the core with the test channel + this._core.initialize(coreConfig, [testChannel]); + + // Set up the trace provider + const traceProvider = this._createTestTraceProvider(this._core); + this._core.setTraceProvider(traceProvider); + + return this._core; + } + + /** + * Helper function to create a span for testing using the actual SDK functions + */ + private _createTestSpan( + name: string, + kind: eOTelSpanKind = eOTelSpanKind.INTERNAL, + attributes: { [key: string]: any } = {}, + statusCode: eOTelSpanStatusCode = eOTelSpanStatusCode.UNSET + ): IReadableSpan { + // Setup core if not already setup + if (!this._core) { + this._setupCore(); + } + + // Create span using the trace provider + const span = this._core.startSpan(name, { + kind: kind, + attributes: attributes + }); + + // Set status if provided + if (statusCode !== eOTelSpanStatusCode.UNSET) { + span.setStatus({ + code: statusCode, + message: statusCode === eOTelSpanStatusCode.ERROR ? "Error occurred" : undefined + }); + } + + // End the span to finalize it + span.end(); + + return span as IReadableSpan; + } + + public registerTests() { + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should create basic telemetry item from span", + test: () => { + // Setup core first + this._setupCore(); + + // Arrange - create parent span first + const parentSpan = this._core.startSpan("parent-operation", { + kind: eOTelSpanKind.SERVER + }); + + // Create child CLIENT span with parent context + const span = this._core.startSpan("test-operation", { + kind: eOTelSpanKind.CLIENT + }, parentSpan.spanContext()); + + span.end(); + parentSpan.end(); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span as IReadableSpan); + + // Assert + Assert.ok(result, "Should return a telemetry item"); + Assert.equal(result.name, "Ms.Web.Span", "Event name should be Ms.Web.Span"); + Assert.equal(result.baseType, "OTelSpan", "Base type should be OTelSpan"); + Assert.ok(result.baseData, "Should have baseData"); + + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.name, "test-operation", "Span name should match"); + Assert.equal(baseData.kind, eOTelSpanKind.CLIENT, "Span kind should match"); + Assert.ok(baseData.startTime, "Should have start time"); + Assert.equal(baseData.success, true, "Should be successful by default"); + Assert.equal(parentSpan.spanContext().spanId, baseData.parentId, "Parent ID should match parent span's ID"); + Assert.equal((span as IReadableSpan).parentSpanId, baseData.parentId, "Should match span's parent ID"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle span with error status", + test: () => { + // Arrange + const span = this._createTestSpan( + "failed-operation", + eOTelSpanKind.CLIENT, + {}, + eOTelSpanStatusCode.ERROR + ); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result, "Should return a telemetry item"); + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.success, false, "Should be marked as failed"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate HTTP properties for HTTP spans", + test: () => { + // Arrange + const attributes = { + [ATTR_HTTP_REQUEST_METHOD]: "GET", + [ATTR_URL_FULL]: "https://example.com:443/api/users", + [ATTR_HTTP_RESPONSE_STATUS_CODE]: 200 + }; + const span = this._createTestSpan("http-request", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result, "Should return a telemetry item"); + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.httpMethod, "GET", "Should have HTTP method"); + Assert.equal(baseData.httpUrl, "https://example.com/api/users", "Should remove default port 443"); + Assert.equal(baseData.httpStatusCode, 200, "Should have HTTP status code"); + Assert.equal(baseData.success, true, "Should be successful for 2xx status"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should remove default port 80 for HTTP", + test: () => { + // Arrange + const attributes = { + [ATTR_HTTP_REQUEST_METHOD]: "POST", + [ATTR_URL_FULL]: "http://example.com:80/api/data" + }; + const span = this._createTestSpan("http-post", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.httpUrl, "http://example.com/api/data", "Should remove default port 80"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should mark 4xx and 5xx as failures", + test: () => { + // Arrange + const attributes404 = { + [ATTR_HTTP_REQUEST_METHOD]: "GET", + [ATTR_HTTP_RESPONSE_STATUS_CODE]: 404 + }; + const attributes500 = { + [ATTR_HTTP_REQUEST_METHOD]: "GET", + [ATTR_HTTP_RESPONSE_STATUS_CODE]: 500 + }; + + const span404 = this._createTestSpan("not-found", eOTelSpanKind.CLIENT, attributes404); + const span500 = this._createTestSpan("server-error", eOTelSpanKind.CLIENT, attributes500); + + // Act + const result404 = createExtendedTelemetryItemFromSpan(this._core, span404); + const result500 = createExtendedTelemetryItemFromSpan(this._core, span500); + + // Assert + Assert.equal((result404.baseData as IMsWebSpanTelemetry).success, false, "404 should be marked as failure"); + Assert.equal((result500.baseData as IMsWebSpanTelemetry).success, false, "500 should be marked as failure"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate database properties for DB spans", + test: () => { + // Arrange + const attributes = { + [SEMATTRS_DB_SYSTEM]: "postgresql", + [SEMATTRS_DB_STATEMENT]: "SELECT * FROM users WHERE id = $1", + [SEMATTRS_DB_NAME]: "myapp_db" + }; + const span = this._createTestSpan("db-query", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.dbSystem, "postgresql", "Should have DB system"); + Assert.equal(baseData.dbStatement, "SELECT * FROM users WHERE id = $1", "Should have DB statement"); + Assert.equal(baseData.dbName, "myapp_db", "Should have DB name"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate RPC properties for RPC spans", + test: () => { + // Arrange + const attributes = { + [SEMATTRS_RPC_SYSTEM]: "grpc", + [SEMATTRS_RPC_GRPC_STATUS_CODE]: 0 + }; + const span = this._createTestSpan("rpc-call", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.rpcSystem, "grpc", "Should have RPC system"); + Assert.equal(baseData.rpcGrpcStatusCode, 0, "Should have gRPC status code"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate user extension from enduser attributes", + test: () => { + // Arrange + const attributes = { + [ATTR_ENDUSER_ID]: "user123", + [ATTR_ENDUSER_PSEUDO_ID]: "pseudo456" + }; + const span = this._createTestSpan("user-operation", eOTelSpanKind.SERVER, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.ext, "Should have extensions"); + Assert.ok(result.ext.user, "Should have user extension"); + Assert.equal(result.ext.user.authId, "user123", "Should have authenticated user ID"); + Assert.equal(result.ext.user.id, "pseudo456", "Should have pseudonymous user ID"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate Part C with custom attributes", + test: () => { + // Arrange + const attributes = { + "custom.property": "custom-value", + "app.version": "1.2.3", + "environment": "production" + }; + const span = this._createTestSpan("custom-operation", eOTelSpanKind.INTERNAL, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.data, "Should have Part C data"); + Assert.equal(result.data["custom.property"], "custom-value", "Should include custom property"); + Assert.equal(result.data["app.version"], "1.2.3", "Should include app version"); + Assert.equal(result.data["environment"], "production", "Should include environment"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should exclude known internal properties from Part C", + test: () => { + // Arrange + const attributes = { + [ATTR_HTTP_REQUEST_METHOD]: "GET", + [ATTR_HTTP_RESPONSE_STATUS_CODE]: 200, + "custom.property": "custom-value", + "_MS.ProcessedByMetricExtractors": "(Name: X, Ver:'1.1')" + }; + const span = this._createTestSpan("filtered-operation", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.data, "Should have Part C data"); + Assert.equal(result.data["custom.property"], "custom-value", "Should include custom property"); + Assert.ok(!result.data[ATTR_HTTP_REQUEST_METHOD], "Should not include known HTTP method attribute"); + Assert.ok(!result.data["_MS.ProcessedByMetricExtractors"], "Should not include MS internal attribute"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should exclude microsoft.* properties from Part C", + test: () => { + // Arrange + const attributes = { + "microsoft.internal": "value", + "microsoft.sample_rate": 100, + "custom.property": "custom-value" + }; + const span = this._createTestSpan("microsoft-filtered", eOTelSpanKind.INTERNAL, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.data, "Should have Part C data"); + Assert.equal(result.data["custom.property"], "custom-value", "Should include custom property"); + Assert.ok(!result.data["microsoft.internal"], "Should not include microsoft.internal property"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should include span context in dt extension", + test: () => { + // Arrange + const span = this._createTestSpan("traced-operation", eOTelSpanKind.SERVER); + const spanContext = span.spanContext(); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.ext, "Should have extensions"); + Assert.ok(result.ext.dt, "Should have dt extension"); + Assert.equal(result.ext.dt.spanId, spanContext.spanId, "Should have span ID"); + Assert.equal(result.ext.dt.traceId, spanContext.traceId, "Should have trace ID"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle Azure EventHub PRODUCER span", + test: () => { + // Arrange + const attributes = { + "az.namespace": "Microsoft.EventHub", + [SEMATTRS_NET_PEER_NAME]: "myeventhub.servicebus.windows.net", + "message_bus.destination": "myeventhub" + }; + const span = this._createTestSpan("eventhub-send", eOTelSpanKind.PRODUCER, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(eOTelSpanKind.PRODUCER, baseData.kind, "Should have PRODUCER kind"); + Assert.equal("Microsoft.EventHub", baseData.azureResourceProvider, "Should have azureResourceProvider in baseData"); + // Other attributes should be in Part C + Assert.ok(result.data, "Should have Part C data"); + Assert.equal("myeventhub.servicebus.windows.net", result.data.netPeerName, "Should have peer name in Part C"); + Assert.equal("myeventhub", result.data["message_bus.destination"], "Should have destination in Part C"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle Azure EventHub CONSUMER span with timeSinceEnqueued", + test: () => { + // Arrange + const attributes = { + "az.namespace": "Microsoft.EventHub", + [SEMATTRS_NET_PEER_NAME]: "myeventhub.servicebus.windows.net", + "message_bus.destination": "myeventhub", + "timeSinceEnqueued": 1500 + }; + const span = this._createTestSpan("eventhub-receive", eOTelSpanKind.CONSUMER, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(eOTelSpanKind.CONSUMER, baseData.kind, "Should have CONSUMER kind"); + Assert.equal("Microsoft.EventHub", baseData.azureResourceProvider, "Should have azureResourceProvider in baseData"); + // Other attributes should be in Part C + Assert.ok(result.data, "Should have Part C data"); + Assert.equal("myeventhub.servicebus.windows.net", result.data.netPeerName, "Should have peer name in Part C"); + Assert.equal("myeventhub", result.data["message_bus.destination"], "Should have destination in Part C"); + Assert.equal(1500, result.data["timeSinceEnqueued"], "Should have timeSinceEnqueued in Part C"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle Azure EventHub CLIENT span", + test: () => { + // Arrange + const attributes = { + "az.namespace": "Microsoft.EventHub", + [SEMATTRS_NET_PEER_NAME]: "myeventhub.servicebus.windows.net", + "message_bus.destination": "myeventhub" + }; + const span = this._createTestSpan("eventhub-operation", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(eOTelSpanKind.CLIENT, baseData.kind, "Should have CLIENT kind"); + Assert.equal("Microsoft.EventHub", baseData.azureResourceProvider, "Should have azureResourceProvider in baseData"); + // Other attributes should be in Part C + Assert.ok(result.data, "Should have Part C data"); + Assert.equal("myeventhub.servicebus.windows.net", result.data.netPeerName, "Should have peer name in Part C"); + Assert.equal("myeventhub", result.data["message_bus.destination"], "Should have destination in Part C"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle Azure SDK INTERNAL span with az.namespace", + test: () => { + // Arrange + const attributes = { + "az.namespace": "Microsoft.Storage" + }; + const span = this._createTestSpan("storage-operation", eOTelSpanKind.INTERNAL, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(eOTelSpanKind.INTERNAL, baseData.kind, "Should have INTERNAL kind"); + Assert.equal("Microsoft.Storage", baseData.azureResourceProvider, "Should have azureResourceProvider in baseData"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should populate Part C with network attributes", + test: () => { + // Arrange + const attributes = { + [SEMATTRS_NET_PEER_NAME]: "api.example.com", + [SEMATTRS_NET_PEER_PORT]: 8080, + [SEMATTRS_HTTP_ROUTE]: "/api/v1/users/:id", + "service.name": "api-gateway" + }; + const span = this._createTestSpan("network-call", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.data, "Should have Part C data"); + Assert.equal(result.data.netPeerName, "api.example.com", "Should have peer name"); + Assert.equal(result.data.netPeerPort, 8080, "Should have peer port"); + Assert.equal(result.data.httpRoute, "/api/v1/users/:id", "Should have HTTP route"); + Assert.equal(result.data.peerService, "api-gateway", "Should have peer service"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle span with duration", + test: () => { + // Arrange + const span = this._createTestSpan("timed-operation", eOTelSpanKind.CLIENT); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.ok(baseData.duration !== undefined, "Should have duration"); + Assert.ok(baseData.duration >= 0, "Duration should be non-negative"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle span with traceState", + test: () => { + // Arrange + const span = this._createTestSpan("traced-operation", eOTelSpanKind.SERVER); + const spanContext = span.spanContext(); + + // Add traceState to the span context + spanContext.traceState.set("vendor1", "value1"); + spanContext.traceState.set("vendor2", "value2"); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.ok(result, "Should create telemetry item"); + // TraceState should be included when present + Assert.ok(baseData.traceState, "Should include traceState when present in span context"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should use legacy HTTP semantic attributes", + test: () => { + // Arrange + const attributes = { + [SEMATTRS_HTTP_METHOD]: "POST", + [SEMATTRS_HTTP_URL]: "https://api.example.com/v1/data", + [SEMATTRS_HTTP_STATUS_CODE]: 201 + }; + const span = this._createTestSpan("legacy-http", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.httpMethod, "POST", "Should handle legacy HTTP method attribute"); + Assert.equal(baseData.httpUrl, "https://api.example.com/v1/data", "Should handle legacy HTTP URL attribute"); + Assert.equal(baseData.httpStatusCode, 201, "Should handle legacy HTTP status code attribute"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle span with parent context", + test: () => { + // Arrange + const span = this._createTestSpan("child-span", eOTelSpanKind.SERVER); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + // The span will have either parentSpanId or can fallback to parentSpanContext.spanId + // parentId may be empty string if there's no parent + Assert.ok(baseData.parentId !== undefined, "Should have parentId property"); + Assert.ok(result, "Should successfully create telemetry item"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle different span kinds", + test: () => { + // Arrange & Act + const internalSpan = this._createTestSpan("internal", eOTelSpanKind.INTERNAL); + const serverSpan = this._createTestSpan("server", eOTelSpanKind.SERVER); + const clientSpan = this._createTestSpan("client", eOTelSpanKind.CLIENT); + const producerSpan = this._createTestSpan("producer", eOTelSpanKind.PRODUCER); + const consumerSpan = this._createTestSpan("consumer", eOTelSpanKind.CONSUMER); + + const internalResult = createExtendedTelemetryItemFromSpan(this._core, internalSpan); + const serverResult = createExtendedTelemetryItemFromSpan(this._core, serverSpan); + const clientResult = createExtendedTelemetryItemFromSpan(this._core, clientSpan); + const producerResult = createExtendedTelemetryItemFromSpan(this._core, producerSpan); + const consumerResult = createExtendedTelemetryItemFromSpan(this._core, consumerSpan); + + // Assert + Assert.equal((internalResult.baseData as IMsWebSpanTelemetry).kind, eOTelSpanKind.INTERNAL, "Should have INTERNAL kind"); + Assert.equal((serverResult.baseData as IMsWebSpanTelemetry).kind, eOTelSpanKind.SERVER, "Should have SERVER kind"); + Assert.equal((clientResult.baseData as IMsWebSpanTelemetry).kind, eOTelSpanKind.CLIENT, "Should have CLIENT kind"); + Assert.equal((producerResult.baseData as IMsWebSpanTelemetry).kind, eOTelSpanKind.PRODUCER, "Should have PRODUCER kind"); + Assert.equal((consumerResult.baseData as IMsWebSpanTelemetry).kind, eOTelSpanKind.CONSUMER, "Should have CONSUMER kind"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should handle span with sample rate attribute", + test: () => { + // Arrange + const attributes = { + "microsoft.sample_rate": 50 + }; + const span = this._createTestSpan("sampled-operation", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.ok(result.data, "Should have Part C data"); + Assert.equal(50, result.data.sampleRate, "Should have sample rate in Part C"); + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should not overwrite existing extension values", + test: () => { + // Arrange + const attributes = { + [ATTR_ENDUSER_ID]: "user-new", + [ATTR_ENDUSER_PSEUDO_ID]: "pseudo-new" + }; + const span = this._createTestSpan("user-op", eOTelSpanKind.SERVER, attributes); + + // Pre-populate some extension values that should not be overwritten + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Manually set some values to test they don't get overwritten + if (result.ext && result.ext.user) { + const originalAuthId = result.ext.user.authId; + const originalId = result.ext.user.id; + + // Act - create again to verify overwrite behavior + const result2 = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + Assert.equal(result2.ext.user.authId, "user-new", "Should have new authId"); + Assert.equal(result2.ext.user.id, "pseudo-new", "Should have new pseudonymous ID"); + } + } + }); + + this.testCase({ + name: "createExtendedTelemetryItemFromSpan: should preserve non-standard port in URL", + test: () => { + // Arrange + const attributes = { + [ATTR_HTTP_REQUEST_METHOD]: "GET", + [ATTR_URL_FULL]: "https://example.com:8443/api/data" + }; + const span = this._createTestSpan("custom-port", eOTelSpanKind.CLIENT, attributes); + + // Act + const result = createExtendedTelemetryItemFromSpan(this._core, span); + + // Assert + const baseData = result.baseData as IMsWebSpanTelemetry; + Assert.equal(baseData.httpUrl, "https://example.com:8443/api/data", "Should preserve non-standard port"); + } + }); + } +} + diff --git a/shared/otel-core/Tests/Unit/src/ext/TestHelper.ts b/shared/otel-core/Tests/Unit/src/ext/TestHelper.ts new file mode 100644 index 000000000..63dbc5829 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/TestHelper.ts @@ -0,0 +1,93 @@ +import { IExtendedTelemetryItem } from '../../../../src/interfaces/ext/DataModels'; + +export class TestHelper { + private static _idCount = 0; + + static reset(key: string) { + this._idCount = 0; + localStorage.removeItem(key); + } + + static mockEvent(persistence: number): IExtendedTelemetryItem { + this._idCount++; + return { + name: 'test_event-' + this._idCount.toString(), + baseType: 'custom', + time: '', + persistence: persistence, + data: { + 'key': 'value', + empty: [], + value1: [1], + value2: ['Hello'], + value3: [['Hello']], + value4: true, + value5: 42, + value6: { + more: { + data: 'X' + } + }, + evValue1: { + value: 'event Property' + }, + evValue2: { + value: 'event Property2', + kind: 32 /* CustomerContent_GenericContent */, + propertyType: 1 /* String */ + } + } + }; + } + + static mockEvent2(persistence: number): IExtendedTelemetryItem { + this._idCount++; + return { + name: 'test_event-' + this._idCount.toString(), + time: ' 1970-01-01T00:00:00.000Z', + ver: '4.0', + iKey: 'o:12345-12345', + ext: { + sdk: { + ver: 'Hello version 1.0', + seq: 1, + epoch: '0', + installId: 'TestDeviceId' + }, + app: { sesId: '####' }, + user: { locale: 'en-US' }, + web: { domain: 'localhost' }, + intweb: { }, + utc: { popSample: 100 }, + loc: { tz: '-08:00' }, + metadata: { + f: { + value1: { a: { t: 6 } }, + value5: { t: 6 }, + evValue2: { t: 8193 } + } + } + }, + baseData: { + properties: { + version: '##currentPluginVersions##' + } + }, + data: { + baseType: 'testEventBaseType', + value1: [1], + value2: ['Hello'], + value3: [['Hello']], + value4: true, + value5: 42, + value6: { + more: { + data: 'X' + } + }, + evValue1: 'event Property', + evValue2: 'event Property2' + } + }; + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/UtilsTest.ts b/shared/otel-core/Tests/Unit/src/ext/UtilsTest.ts new file mode 100644 index 000000000..18db0d1a8 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/UtilsTest.ts @@ -0,0 +1,228 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { uaDisallowsSameSiteNone } from "../../../../src/index"; +import { EventPropertyType, ValueKind } from '../../../../src/enums/ext/Enums'; +import * as Utils from '../../../../src/ext/extUtils'; + +export class UtilsTest extends AITestClass { + public registerTests() { + this.testCase({ + name: 'getCommonSchemaMetaData returns correct value for specified data type', + test: () => { + let dataType = EventPropertyType.String; + while (dataType <= EventPropertyType.DateTime) { + QUnit.assert.equal(Utils.getCommonSchemaMetaData(123, undefined, dataType), dataType); + dataType++; + } + } + }); + + this.testCase({ + name: 'getCommonSchemaMetaData returns correct value for specified value kind', + test: () => { + let valueKind = ValueKind.NotSet; + while (valueKind <= ValueKind.Pii_IPV4AddressLegacy) { + QUnit.assert.equal(Utils.getCommonSchemaMetaData(123, valueKind), 6 | valueKind << 5, `${valueKind}`); + valueKind++; + } + } + }); + + this.testCase({ + name: 'extend', + test: () => { + let obj1 = { + prop1: "obj1prop1", + prop2: { + nestedprop1: "obj1nestedprop1", + nestedprop2: ["obj1nestedprop2"] + } + }; + let obj2 = { + prop1: "obj2prop1", + prop2: { + nestedprop1: "obj2nestedprop1", + nestedprop2: ["obj2nestedprop2"] + }, + prop3: [{ prop3_arrayObject1: "prop3_arrayObject1" }, { prop3_arrayObject2: "prop3_arrayObject2" }] + + }; + let newObject = Utils.extend(true, obj1, obj2); + QUnit.assert.equal(newObject["prop1"], "obj2prop1"); + QUnit.assert.equal(newObject["prop2"]["nestedprop1"], "obj2nestedprop1"); + QUnit.assert.equal(newObject["prop2"]["nestedprop2"][0], "obj2nestedprop2"); + QUnit.assert.equal(newObject["prop3"][0]["prop3_arrayObject1"], "prop3_arrayObject1"); + QUnit.assert.equal(newObject["prop3"][1]["prop3_arrayObject2"], "prop3_arrayObject2"); + } + }); + + // this.testCase({ + // name: 'getCommonSchemaMetaData returns correct value for specified value kind', + // test: () => { + // for (let dataType in ValueKind) { + // if (ValueKind[dataType] !== ValueKind.CustomerContent_GenericContent) { + // QUnit.assert.equal(Utils.getCommonSchemaMetaData(123, ValueKind[dataType]), 6 | ValueKind[dataType] << 5, `${dataType}`); + // } + // } + // } + // }); + + // this.testCase({ + // name: 'getCommonSchemaMetaData returns correct value if using Customer Content Types', + // test: () => { + // let encodedValue; + // encodedValue = Utils.getCommonSchemaMetaData(123, ValueKind.CustomerContent_GenericContent); + // QUnit.assert.equal(encodedValue, EventPropertyType.Double | 1 << 13, 'Generic number'); + + // encodedValue = Utils.getCommonSchemaMetaData('123', ValueKind.CustomerContent_GenericContent); + // QUnit.assert.equal(encodedValue, EventPropertyType.String | 1 << 13, 'Generic string'); + + // encodedValue = Utils.getCommonSchemaMetaData(true, ValueKind.CustomerContent_GenericContent); + // QUnit.assert.equal(encodedValue, EventPropertyType.Bool | 1 << 13, 'Generic bool (true)'); + + // encodedValue = Utils.getCommonSchemaMetaData(false, ValueKind.CustomerContent_GenericContent); + // QUnit.assert.equal(encodedValue, EventPropertyType.Bool | 1 << 13, 'Generic bool (false)'); + + // encodedValue = Utils.getCommonSchemaMetaData(123, ValueKind.CustomerContent_GenericContent, EventPropertyType.Guid); + // QUnit.assert.equal(encodedValue, EventPropertyType.Guid | 1 << 13, 'Generic typed Guid'); + // } + // }); + + // this.testCase({ + // name: 'getCommonSchemaMetaData using ValueKind.NotSet returns expected value', + // test: () => { + // let encodedValue; + // encodedValue = Utils.getCommonSchemaMetaData('abc', ValueKind.NotSet, EventPropertyType.String); + // QUnit.assert.equal(EventPropertyType.String, 1); + // QUnit.assert.equal(encodedValue, EventPropertyType.String); + + // encodedValue = Utils.getCommonSchemaMetaData('abc', undefined, EventPropertyType.String); + // QUnit.assert.equal(EventPropertyType.String, 1); + // QUnit.assert.equal(encodedValue, EventPropertyType.String); + // } + // }); + + // this.testCase({ + // name: 'getCommonSchemaMetaData returns correct value for specified value kind and data type', + // test: () => { + // for (let dataType in EventPropertyType) { + // if (dataType) { + // for (let valueKind in ValueKind) { + // if (ValueKind[valueKind] !== ValueKind.CustomerContent_GenericContent) { + // QUnit.assert.equal( + // Utils.getCommonSchemaMetaData(123, ValueKind[valueKind], EventPropertyType[dataType]), + // EventPropertyType[dataType] | ValueKind[valueKind] << 5, `${valueKind}`); + // } + // } + // } + // } + // } + // }); + + this.testCase({ + name: "Check disableSameSiteCookie status", + test: () => { + let excludeValues = [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.2 Safari/605.1.15", + "Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Mobile Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPad; CPU OS 12_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One; MSAppHost/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", + "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/71.0.3578.89 Mobile/15E148 Safari/605.1", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.1 Safari/605.1.15", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/65.0.225212226 Mobile/15E148 Safari/605.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16C101", + "Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Teams/1.1.00.31860 Chrome/61.0.3163.100 Electron/2.0.10 Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G930F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/71.0.3578.89 Mobile/15E148 Safari/605.1", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/605.1.15 (KHTML, like Gecko)", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G935F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", + "Mozilla/5.0 (iPad; CPU OS 12_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; WebView/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6821.400 QQBrowser/10.3.3040.400", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Yammer/2.1.0 Chrome/66.0.3359.181 Electron/3.0.6 Safari/537.36", + "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-A520F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G960U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Teams/1.1.00.31860 Chrome/61.0.3163.100 Electron/2.0.10 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15", + "Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) GSA/65.0.225212226 Mobile/15E148 Safari/605.1", + "Mozilla/5.0 (iPad; CPU OS 12_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16C50", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (iPad; CPU OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", + "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G920F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6821.400 QQBrowser/10.3.3040.400", + "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 EdgiOS/42.8.6 Mobile/16C101 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.0.0; SAMSUNG SM-N950F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "Mozilla/5.0 (Linux; Android 8.1.0; SAMSUNG SM-J530F Build/M1AJQ) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/8.2 Chrome/63.0.3239.111 Mobile Safari/537.36" + ]; + + let acceptValues = [ + "", + null, + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", + "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", + "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko/20100101 Firefox/12.0", + "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)", + "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15" + ]; + + for (let lp = 0; lp < excludeValues.length; lp++) { + QUnit.assert.equal(true, uaDisallowsSameSiteNone(excludeValues[lp]), excludeValues[lp]); + } + + for (let lp = 0; lp < acceptValues.length; lp++) { + QUnit.assert.equal(false, uaDisallowsSameSiteNone(acceptValues[lp]), acceptValues[lp]); + } + } + }); + } +} diff --git a/shared/otel-core/Tests/Unit/src/ext/ValueSanitizerTests.ts b/shared/otel-core/Tests/Unit/src/ext/ValueSanitizerTests.ts new file mode 100644 index 000000000..bf4099271 --- /dev/null +++ b/shared/otel-core/Tests/Unit/src/ext/ValueSanitizerTests.ts @@ -0,0 +1,356 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { TestHelper } from './TestHelper'; +import { IExtendedTelemetryItem, IValueSanitizer } from '../../../../src/interfaces/ext/DataModels'; +import { EventPropertyType, ValueKind } from '../../../../src/enums/ext/Enums'; +import { sanitizeProperty, getCommonSchemaMetaData } from '../../../../src/ext/extUtils'; +import { arrForEach, isNullOrUndefined, objKeys } from '../../../../src/index'; +import { ValueSanitizer } from '../../../../src/ext/ValueSanitizer'; +import { EventPersistence } from "../../../../src/enums/ai/Enums"; + +export class ValueSanitizerTests extends AITestClass { + + private _checkFieldValue(dataSanitizer: IValueSanitizer, path: string, name: string, val: any, stringifyObjects?: boolean) { + // Only add populated properties + let value1 = dataSanitizer.value(path, name, val, stringifyObjects); + let value2 = sanitizeProperty(name, val, stringifyObjects); + + if (!isNullOrUndefined(value1) && !isNullOrUndefined(value2)) { + QUnit.assert.equal(value1.value, value2.value, 'Checking sanitized value [' + path + '.' + name + '] - sanitizeProperty:(' + value2.value + '); Json:' + JSON.stringify(val)); + } else if (isNullOrUndefined(val)) { + QUnit.assert.equal(value1, value2, 'Checking empty [' + path + '.' + name + ']'); + } else if (!isNullOrUndefined(value2)) { + // This is a failure condition as value1 (should be not set) + QUnit.assert.equal(value1, value2.value, 'Checking [' + path + '.' + name + '] - sanitizeProperty:(' + value2 + '); Json:' + JSON.stringify(val)); + } else { + QUnit.assert.equal(value1, value2, 'Checking sanitized values [' + path + '.' + name + '] - sanitizeProperty:(' + value2 + '); Json:' + JSON.stringify(val)); + } + } + + private _checkSerialization(dataSanitizer: IValueSanitizer, theEvent: IExtendedTelemetryItem, stringifyObjects?: boolean) { + // part A + if (theEvent.ext) { + arrForEach(objKeys(theEvent.ext), (key) => { + let rootKey = 'ext.' + key; + arrForEach(objKeys(theEvent.ext[key]), (subKey) => { + this._checkFieldValue(dataSanitizer, rootKey, subKey, theEvent.ext[key][subKey], stringifyObjects); + }); + }); + } + + // part B + if (theEvent.baseData) { + arrForEach(objKeys(theEvent.baseData), (key) => { + this._checkFieldValue(dataSanitizer, 'baseData', key, theEvent.baseData[key], stringifyObjects); + }); + } + + // part C + if (theEvent.data) { + arrForEach(objKeys(theEvent.data), (key) => { + this._checkFieldValue(dataSanitizer, 'data', key, theEvent.data[key], stringifyObjects); + }); + } + } + + public registerTests() { + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with no fieldValueSanitizerProvider - default stringifyObjects', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer(); + + this._checkSerialization(dataSanitizer, event1); + } + }); + + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with no fieldValueSanitizerProvider - stringifyObjects - true', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer(); + + this._checkSerialization(dataSanitizer, event1, true); + } + }); + + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with no fieldValueSanitizerProvider - stringifyObjects - false', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer(); + + this._checkSerialization(dataSanitizer, event1, false); + } + }); + + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with a pass-through (no-op) fieldValueSanitizerProvider - default stringifyObjects', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + + this._checkSerialization(dataSanitizer, event1); + } + }); + + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with a pass-through (no-op) fieldValueSanitizerProvider - stringifyObjects - true', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + + this._checkSerialization(dataSanitizer, event1, true); + } + }); + + this.testCase({ + name: 'Check basic event serialization against sanitizeProperty with a pass-through (no-op) fieldValueSanitizerProvider - stringifyObjects - false', + test: () => { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + + this._checkSerialization(dataSanitizer, event1, false); + } + }); + + this.testCase({ + name: 'Test different value kind variants and property types - default stringifyObjects', + test: () => { + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + let valueKind = ValueKind.NotSet; + while (valueKind < ValueKind.Pii_IPV4AddressLegacy) { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + event1.data.evValue3 = { + value: 123, + kind: valueKind + }; + event1.data.evValue4 = { + value: "456", + kind: valueKind + }; + event1.data.evValue5 = { + value: true, + kind: valueKind + }; + event1.data.evValue6 = { + value: [7, 8, 9], + kind: valueKind + }; + event1.data.evValue7 = { + value: ["10", "11", "12"], + kind: valueKind + }; + event1.data.evValue9 = { + value: [true, false], + kind: valueKind + }; + + event1.data.ptValue1 = { + value: 21, + propertyType: EventPropertyType.Int32 + }; + + event1.data.ptValue2 = { + value: "22", + propertyType: EventPropertyType.String + }; + + event1.data.ptValue2 = { + value: 23.0, + propertyType: EventPropertyType.Double + }; + + event1.data.ptValue3 = { + value: 21 + }; + + event1.data.ptValue4 = { + value: "22" + }; + + event1.data.ptValue5 = { + value: 23.0 + }; + + QUnit.assert.equal(getCommonSchemaMetaData(123, valueKind), 6 | valueKind << 5, `${valueKind}`); + this._checkSerialization(dataSanitizer, event1); + valueKind++; + } + } + }); + + this.testCase({ + name: 'Test different value kind variants and property types - stringifyObjects - true', + test: () => { + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + let valueKind = ValueKind.NotSet; + while (valueKind < ValueKind.Pii_IPV4AddressLegacy) { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + event1.data.evValue3 = { + value: 123, + kind: valueKind + }; + event1.data.evValue4 = { + value: "456", + kind: valueKind + }; + event1.data.evValue5 = { + value: true, + kind: valueKind + }; + event1.data.evValue6 = { + value: [7, 8, 9], + kind: valueKind + }; + event1.data.evValue7 = { + value: ["10", "11", "12"], + kind: valueKind + }; + event1.data.evValue9 = { + value: [true, false], + kind: valueKind + }; + + event1.data.ptValue1 = { + value: 21, + propertyType: EventPropertyType.Int32 + }; + + event1.data.ptValue2 = { + value: "22", + propertyType: EventPropertyType.String + }; + + event1.data.ptValue2 = { + value: 23.0, + propertyType: EventPropertyType.Double + }; + + event1.data.ptValue3 = { + value: 21 + }; + + event1.data.ptValue4 = { + value: "22" + }; + + event1.data.ptValue5 = { + value: 23.0 + }; + + QUnit.assert.equal(getCommonSchemaMetaData(123, valueKind), 6 | valueKind << 5, `${valueKind}`); + this._checkSerialization(dataSanitizer, event1, true); + valueKind++; + } + } + }); + + this.testCase({ + name: 'Test different value kind variants and property types - stringifyObjects - false', + test: () => { + let dataSanitizer = new ValueSanitizer({ + handleField: () => { + return true; + }, + getSanitizer: () => { + return null; + } + }); + let valueKind = ValueKind.NotSet; + while (valueKind < ValueKind.Pii_IPV4AddressLegacy) { + let event1 = TestHelper.mockEvent2(EventPersistence.Normal); + event1.data.evValue3 = { + value: 123, + kind: valueKind + }; + event1.data.evValue4 = { + value: "456", + kind: valueKind + }; + event1.data.evValue5 = { + value: true, + kind: valueKind + }; + event1.data.evValue6 = { + value: [7, 8, 9], + kind: valueKind + }; + event1.data.evValue7 = { + value: ["10", "11", "12"], + kind: valueKind + }; + event1.data.evValue9 = { + value: [true, false], + kind: valueKind + }; + + event1.data.ptValue1 = { + value: 21, + propertyType: EventPropertyType.Int32 + }; + + event1.data.ptValue2 = { + value: "22", + propertyType: EventPropertyType.String + }; + + event1.data.ptValue2 = { + value: 23.0, + propertyType: EventPropertyType.Double + }; + + event1.data.ptValue3 = { + value: 21 + }; + + event1.data.ptValue4 = { + value: "22" + }; + + event1.data.ptValue5 = { + value: 23.0 + }; + + QUnit.assert.equal(getCommonSchemaMetaData(123, valueKind), 6 | valueKind << 5, `${valueKind}`); + this._checkSerialization(dataSanitizer, event1, false); + valueKind++; + } + } + }); + } + } diff --git a/shared/otel-core/Tests/Unit/src/index.tests.ts b/shared/otel-core/Tests/Unit/src/index.tests.ts index c81be1895..166052ea9 100644 --- a/shared/otel-core/Tests/Unit/src/index.tests.ts +++ b/shared/otel-core/Tests/Unit/src/index.tests.ts @@ -36,6 +36,15 @@ import { SendPostManagerTests } from "./ai/SendPostManager.Tests"; import { TraceUtilsTests } from "./trace/traceUtils.Tests"; +// 1ds core tests +import { CoreTest } from './ext/CoreTest'; +import { ESPromiseTests } from './ext/ESPromiseTests'; +import { ESPromiseSchedulerTests } from './ext/ESPromiseSchedulerTests'; +import { DynamicProtoTests } from './ext/DynamicProtoTests'; +import { UtilsTest } from './ext/UtilsTest'; +import { ValueSanitizerTests } from './ext/ValueSanitizerTests'; +import { SpanUtilsTests } from './ext/SpanUtilsTests'; + export function runTests() { // OTel tests new OTelApiTests().registerTests(); @@ -81,4 +90,13 @@ export function runTests() { new ThrottleMgrTest().registerTests(); new UtilTests().registerTests(); new W3CTraceStateModesTests().registerTests(); + + // 1DS (OneCollector) extended tests + new CoreTest('CoreTest').registerTests(); + new ESPromiseTests('ESPromiseTests').registerTests(); + new ESPromiseSchedulerTests('ESPromiseSchedulerTests').registerTests(); + new DynamicProtoTests('DynamicProtoTests').registerTests(); + new UtilsTest('UtilsTest').registerTests(); + new ValueSanitizerTests('ValueSanitizerTests').registerTests(); + new SpanUtilsTests('SpanUtilsTests').registerTests(); } diff --git a/shared/otel-core/src/constants/InternalConstants.ts b/shared/otel-core/src/constants/InternalConstants.ts index 12da0a457..e00032baf 100644 --- a/shared/otel-core/src/constants/InternalConstants.ts +++ b/shared/otel-core/src/constants/InternalConstants.ts @@ -31,4 +31,8 @@ export const STR_PATH = "path"; export const STR_NOT_DYNAMIC_ERROR = "Not dynamic - "; export const STR_REDACTED = "REDACTED"; -export const DEFAULT_SENSITIVE_PARAMS = ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature"]; \ No newline at end of file +export const DEFAULT_SENSITIVE_PARAMS = ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature"]; + +export const STR_DEFAULT_ENDPOINT_URL = "https://browser.events.data.microsoft.com/OneCollector/1.0/"; +export const STR_VERSION = "version"; +export const STR_NOT_SPECIFIED = "not_specified"; \ No newline at end of file diff --git a/shared/otel-core/src/core/SenderPostManager.ts b/shared/otel-core/src/core/SenderPostManager.ts index 43977e2ff..eaaebce4e 100644 --- a/shared/otel-core/src/core/SenderPostManager.ts +++ b/shared/otel-core/src/core/SenderPostManager.ts @@ -8,7 +8,8 @@ import { DisabledPropertyName } from "../constants/Constants"; import { STR_EMPTY } from "../constants/InternalConstants"; import { _throwInternal, _warnToConsole } from "../diagnostics/DiagnosticLogger"; import { _eInternalMessageId, eLoggingSeverity } from "../enums/ai/LoggingEnums"; -import { SendRequestReason, TransportType } from "../enums/ai/SendRequestReason"; +import { SendRequestReason } from "../enums/ai/SendRequestReason"; +import { TransportType } from "../enums/ext/Enums"; import { IDiagnosticLogger } from "../interfaces/ai/IDiagnosticLogger"; import { IProcessTelemetryUnloadContext } from "../interfaces/ai/IProcessTelemetryContext"; import { diff --git a/shared/otel-core/src/enums/ai/Enums.ts b/shared/otel-core/src/enums/ai/Enums.ts index 6ac091dbe..55e82510e 100644 --- a/shared/otel-core/src/enums/ai/Enums.ts +++ b/shared/otel-core/src/enums/ai/Enums.ts @@ -119,7 +119,7 @@ export const DistributedTracingModes = (/* @__PURE__ */ createEnumStyle({ + NotSet: eValueKind.NotSet, + Pii_DistinguishedName: eValueKind.Pii_DistinguishedName, + Pii_GenericData: eValueKind.Pii_GenericData, + Pii_IPV4Address: eValueKind.Pii_IPV4Address, + Pii_IPv6Address: eValueKind.Pii_IPv6Address, + Pii_MailSubject: eValueKind.Pii_MailSubject, + Pii_PhoneNumber: eValueKind.Pii_PhoneNumber, + Pii_QueryString: eValueKind.Pii_QueryString, + Pii_SipAddress: eValueKind.Pii_SipAddress, + Pii_SmtpAddress: eValueKind.Pii_SmtpAddress, + Pii_Identity: eValueKind.Pii_Identity, + Pii_Uri: eValueKind.Pii_Uri, + Pii_Fqdn: eValueKind.Pii_Fqdn, + Pii_IPV4AddressLegacy: eValueKind.Pii_IPV4AddressLegacy, + Pii_IPv6ScrubLastHextets: eValueKind.Pii_IPv6ScrubLastHextets, + Pii_DropValue: eValueKind.Pii_DropValue, + CustomerContent_GenericContent: eValueKind.CustomerContent_GenericContent +})); +export type ValueKind = number | eValueKind + +/** + * The EventLatency contains a set of values that specify the latency with which an event is sent. + */ +export const enum EventLatencyValue { + /** + * Normal latency. + */ + Normal = 1, + /** + * Cost deferred latency. At the moment this latency is treated as Normal latency. + */ + CostDeferred = 2, + /** + * Real time latency. + */ + RealTime = 3, + + /** + * Bypass normal batching/timing and send as soon as possible, this will still send asynchronously. + * Added in v3.1.1 + */ + Immediate = 4 +} + +/** + * The EventLatency contains a set of values that specify the latency with which an event is sent. + */ +export const EventLatency = (/* @__PURE__ */ createEnumStyle({ + /** + * Normal latency. + */ + Normal: EventLatencyValue.Normal, + /** + * Cost deferred latency. At the moment this latency is treated as Normal latency. + */ + CostDeferred: EventLatencyValue.CostDeferred, + /** + * Real time latency. + */ + RealTime: EventLatencyValue.RealTime, + + /** + * Bypass normal batching/timing and send as soon as possible, this will still send asynchronously. + * Added in v3.1.1 + */ + Immediate: EventLatencyValue.Immediate +})); +export type EventLatency = number | EventLatencyValue + +/** + * Enum for property types. + */ +export const enum eEventPropertyType { + Unspecified = 0, + String = 1, + Int32 = 2, + UInt32 = 3, + Int64 = 4, + UInt64 = 5, + Double = 6, + Bool = 7, + Guid = 8, + DateTime = 9 +} + +/** + * Enum for property types. + */ +export const EventPropertyType = (/* @__PURE__ */ createEnumStyle({ + Unspecified: eEventPropertyType.Unspecified, + String: eEventPropertyType.String, + Int32: eEventPropertyType.Int32, + UInt32: eEventPropertyType.UInt32, + Int64: eEventPropertyType.Int64, + UInt64: eEventPropertyType.UInt64, + Double: eEventPropertyType.Double, + Bool: eEventPropertyType.Bool, + Guid: eEventPropertyType.Guid, + DateTime: eEventPropertyType.DateTime +})); +export type EventPropertyType = number | eEventPropertyType + +/** + * Define a specific way to send an event synchronously + */ +export const enum EventSendType { + /** + * Batch and send the event asynchronously, this is the same as either setting the event `sync` flag to false or not setting at all. + */ + Batched = 0, // For backward compatibility numeric 0 === false as a numeric + + /** + * Attempt to send the event synchronously, this is the same as setting the event `sync` flag to true + */ + Synchronous = 1, // For backward compatibility numeric 1 === true as a numeric + + /** + * Attempt to send the event synchronously with a preference for the sendBeacon() API. + * As per the specification, the payload of the event (when converted to JSON) must not be larger than 64kb, + * the sendHook is also not supported or used when sendBeacon. + */ + SendBeacon = 2, + + /** + * Attempt to send the event synchronously with a preference for the fetch() API with the keepalive flag, + * the SDK checks to ensure that the fetch() implementation supports the 'keepalive' flag and if not it + * will fallback to either sendBeacon() or a synchronous XHR request. + * As per the specification, the payload of the event (when converted to JSON) must not be larger than 64kb. + * Note: Not all browsers support the keepalive flag so for those environments the events may still fail + */ + SyncFetch = 3 +} + +/** + * The TraceLevel contains a set of values that specify the trace level for the trace messages. + */ +export const enum eTraceLevel { + /** + * None. + */ + NONE = 0, + /** + * Error trace. + */ + ERROR = 1, + /** + * Warning trace. + */ + WARNING = 2, + /** + * Information trace. + */ + INFORMATION = 3 +} + +export const TraceLevel = (/* @__PURE__ */ createEnumStyle({ + NONE: eTraceLevel.NONE, + ERROR: eTraceLevel.ERROR, + WARNING: eTraceLevel.WARNING, + INFORMATION: eTraceLevel.INFORMATION +})); +export type TraceLevel = number | eTraceLevel; + +export const enum _eExtendedInternalMessageId { + AuthHandShakeError = 501, + AuthRedirectFail = 502, + BrowserCannotReadLocalStorage = 503, + BrowserCannotWriteLocalStorage = 504, + BrowserDoesNotSupportLocalStorage = 505, + CannotParseBiBlobValue = 506, + CannotParseDataAttribute = 507, + CVPluginNotAvailable = 508, + DroppedEvent = 509, + ErrorParsingAISessionCookie = 510, + ErrorProvidedChannels = 511, + FailedToGetCookies = 512, + FailedToInitializeCorrelationVector = 513, + FailedToInitializeSDK = 514, + InvalidContentBlob = 515, + InvalidCorrelationValue = 516, + SessionRenewalDateIsZero = 517, + SendPostOnCompleteFailure = 518, + PostResponseHandler = 519, + SDKNotInitialized = 520 +} + +// export const _ExtendedInternalMessageId = objFreeze({ +// ..._InternalMessageId, +// ...createEnumStyle({ +// AuthHandShakeError: _eExtendedInternalMessageId.AuthHandShakeError, +// AuthRedirectFail: _eExtendedInternalMessageId.AuthRedirectFail, +// BrowserCannotReadLocalStorage: _eExtendedInternalMessageId.BrowserCannotReadLocalStorage, +// BrowserCannotWriteLocalStorage: _eExtendedInternalMessageId.BrowserCannotWriteLocalStorage, +// BrowserDoesNotSupportLocalStorage: _eExtendedInternalMessageId.BrowserDoesNotSupportLocalStorage, +// CannotParseBiBlobValue: _eExtendedInternalMessageId.CannotParseBiBlobValue, +// CannotParseDataAttribute: _eExtendedInternalMessageId.CannotParseDataAttribute, +// CVPluginNotAvailable: _eExtendedInternalMessageId.CVPluginNotAvailable, +// DroppedEvent: _eExtendedInternalMessageId.DroppedEvent, +// ErrorParsingAISessionCookie: _eExtendedInternalMessageId.ErrorParsingAISessionCookie, +// ErrorProvidedChannels: _eExtendedInternalMessageId.ErrorProvidedChannels, +// FailedToGetCookies: _eExtendedInternalMessageId.FailedToGetCookies, +// FailedToInitializeCorrelationVector: _eExtendedInternalMessageId.FailedToInitializeCorrelationVector, +// FailedToInitializeSDK: _eExtendedInternalMessageId.FailedToInitializeSDK, +// InvalidContentBlob: _eExtendedInternalMessageId.InvalidContentBlob, +// InvalidCorrelationValue: _eExtendedInternalMessageId.InvalidCorrelationValue, +// SessionRenewalDateIsZero: _eExtendedInternalMessageId.SessionRenewalDateIsZero, +// SendPostOnCompleteFailure: _eExtendedInternalMessageId.SendPostOnCompleteFailure, +// PostResponseHandler: _eExtendedInternalMessageId.PostResponseHandler, +// SDKNotInitialized: _eExtendedInternalMessageId.SDKNotInitialized +// })}); +export type _ExtendedInternalMessageId = number | _eExtendedInternalMessageId | _eInternalMessageId; + +// Following the format styles as defined by .Net (https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netcore-3.1) +export const enum GuidStyle { + Numeric = "N", // 'N' - 32 digits, + Digits = "D", // 'D' - 32 digits separated by hyphens, + Braces = "B", // 'B' - 32 digits separated by hyphens, enclosed in braces, + Parentheses = "P" // 'P' 32 digits separated by hyphens, enclosed in parentheses +} + +export const enum FieldValueSanitizerType { + NotSet = 0x00, + + String = 0x01, + + Number = 0x02, + + Boolean = 0x03, + + Object = 0x04, + + Array = 0x1000, + + EventProperty = 0x2000 +} + +/** + * An enumeration that identifies the transport type that are requested to be used, if the requested + * transport is not available ir supported the SDK may choose the first available transport or it + * will log a warning to the diagnostic logger. + */ +export const enum TransportType { + /** + * Use the default available api + */ + NotSet = 0, + + /** + * Use XMLHttpRequest or XMLDomainRequest if available + */ + Xhr = 1, + + /** + * Use the Fetch api if available + */ + Fetch = 2, + + /** + * Use sendBeacon api if available + */ + Beacon = 3 +} diff --git a/shared/otel-core/src/ext/AppInsightsExtCore.ts b/shared/otel-core/src/ext/AppInsightsExtCore.ts new file mode 100644 index 000000000..40a09331f --- /dev/null +++ b/shared/otel-core/src/ext/AppInsightsExtCore.ts @@ -0,0 +1,123 @@ +/** +* AppInsightsCore.ts +* @author Abhilash Panwar (abpanwar) Hector Hernandez (hectorh) +* @copyright Microsoft 2018 +*/ +import dynamicProto from "@microsoft/dynamicproto-js"; +import { ITimerHandler, dumpObj, objDeepFreeze, throwError } from "@nevware21/ts-utils"; +import { createDynamicConfig } from "../config/DynamicConfig"; +import { STR_DEFAULT_ENDPOINT_URL, STR_EMPTY, STR_VERSION } from "../constants/InternalConstants"; +import { AppInsightsCore } from "../core/AppInsightsCore"; +import { doPerf } from "../core/PerfManager"; +import { _throwInternal } from "../diagnostics/DiagnosticLogger"; +import { eLoggingSeverity } from "../enums/ai/LoggingEnums"; +import { EventLatencyValue, _eExtendedInternalMessageId } from "../enums/ext/Enums"; +import { IDiagnosticLogger } from "../interfaces/ai/IDiagnosticLogger"; +import { INotificationManager } from "../interfaces/ai/INotificationManager"; +import { ITelemetryItem } from "../interfaces/ai/ITelemetryItem"; +import { IPlugin } from "../interfaces/ai/ITelemetryPlugin"; +import { IConfigDefaults } from "../interfaces/config/IConfigDefaults"; +import { IExtendedConfiguration, IExtendedTelemetryItem, IPropertyStorageOverride } from "../interfaces/ext/DataModels"; +import { FullVersionString, getTime, isLatency } from "./extUtils"; + +/** + * The default settings for the config. + * WE MUST include all defaults here to ensure that the config is created with all of the properties + * defined as dynamic. + */ +const defaultConfig: IConfigDefaults = (/*#__PURE__*/ objDeepFreeze({ + endpointUrl: STR_DEFAULT_ENDPOINT_URL, + propertyStorageOverride: { isVal: _chkPropOverride } +})); + +/*#__NO_SIDE_EFFECTS__*/ +function _chkPropOverride(propertyStorageOverride: IPropertyStorageOverride) { + // Validate property storage override + if (propertyStorageOverride && (!propertyStorageOverride.getProperty || !propertyStorageOverride.setProperty)) { + throwError("Invalid property storage override passed."); + } + + return true; +} + +/** + * @group Classes + * @group Entrypoint + */ +export class AppInsightsExtCore extends AppInsightsCore { + constructor() { + super(); + + dynamicProto(AppInsightsExtCore, this, (_self, _base) => { + + _self.initialize = (config: C, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager) => { + doPerf(_self, () => "AppInsightsCore.initialize", () => { + try { + _base.initialize(createDynamicConfig(config, defaultConfig as C, logger || _self.logger, false).cfg, extensions, logger, notificationManager); + } catch (e) { + let logger = _self.logger; + let message = dumpObj(e); + if (message.indexOf("channels") !== -1) { + // Add some additional context to the underlying reported error + message += "\n - Channels must be provided through config.channels only!"; + } + _throwInternal(logger, + eLoggingSeverity.CRITICAL, + _eExtendedInternalMessageId.FailedToInitializeSDK, "SDK Initialization Failed - no telemetry will be sent: " + message + ); + } + }, () => ({ config, extensions, logger, notificationManager })); + }; + + _self.track = (item: IExtendedTelemetryItem|ITelemetryItem) => { + doPerf(_self, () => "AppInsightsCore.track", () => { + let telemetryItem: IExtendedTelemetryItem = item as IExtendedTelemetryItem; + if (telemetryItem) { + telemetryItem.timings = telemetryItem.timings || {}; + telemetryItem.timings.trackStart = getTime(); + if (!isLatency(telemetryItem.latency)) { + telemetryItem.latency = EventLatencyValue.Normal; + } + + let itemExt = telemetryItem.ext = telemetryItem.ext || {}; + itemExt.sdk = itemExt.sdk || {}; + itemExt.sdk.ver = FullVersionString; + let baseData = telemetryItem.baseData = telemetryItem.baseData || {}; + baseData.properties = baseData.properties || {}; + + let itemProperties = baseData.properties; + itemProperties[STR_VERSION] = itemProperties[STR_VERSION] || _self.pluginVersionString || STR_EMPTY; + } + + _base.track(telemetryItem); + }, () => ({ item: item }), !((item as any).sync)); + }; + + _self.pollInternalLogs = (eventName?: string): ITimerHandler => { + return _base.pollInternalLogs(eventName || "InternalLog"); + }; + + }); + } + + /** + * Initialize the sdk. + * @param config - The configuration to initialize the SDK. + * @param extensions - An array of extensions that are to be used by the core. + */ + public initialize(config: C, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public track(item: IExtendedTelemetryItem|ITelemetryItem) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + /** + * Periodically check logger.queue for + */ + public pollInternalLogs(eventName?: string): ITimerHandler { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + return null; + } +} diff --git a/shared/otel-core/src/ext/ValueSanitizer.ts b/shared/otel-core/src/ext/ValueSanitizer.ts new file mode 100644 index 000000000..aae3c3858 --- /dev/null +++ b/shared/otel-core/src/ext/ValueSanitizer.ts @@ -0,0 +1,366 @@ +import { arrForEach, arrIncludes, arrIndexOf, getLength, isNullOrUndefined, isString, objForEachKey } from "@nevware21/ts-utils"; +import { STR_EMPTY } from "../constants/InternalConstants"; +import { FieldValueSanitizerType } from "../enums/ext/Enums"; +import { + FieldValueSanitizerFunc, FieldValueSanitizerTypes, IEventProperty, IFieldSanitizerDetails, IFieldValueSanitizerProvider, IValueSanitizer +} from "../interfaces/ext/DataModels"; +import { getFieldValueType, isValueAssigned, isValueKind } from "./extUtils"; + +interface ISanitizerMapValue { + canHandle: boolean; + handler?: IValueSanitizer; + fieldHandler?: IFieldValueSanitizerProvider; +} + +function _isSpecialName(name: string) { + return (name == "__proto__" || name == "constructor" || name == "prototype"); +} + +export class ValueSanitizer implements IValueSanitizer { + + public static getFieldType = getFieldValueType; + + /** + * Clear the current value sanitizer cache. + */ + public clearCache: () => void; + + /** + * Add a value sanitizer as a fallback sanitizer if this sanitizer can't handle the path/name. + */ + public addSanitizer: (sanitizer: IValueSanitizer) => void; + + /** + * Adds a field sanitizer to the evaluation list + */ + public addFieldSanitizer: (fieldSanitizer: IFieldValueSanitizerProvider) => void; + + /** + * Removes the value sanitizer as a fallback sanitizer if this sanitizer can't handle the path/name if present. + */ + public rmSanitizer: (theSanitizer: IValueSanitizer) => void; + + /** + * Removes the field sanitizer to the evaluation list if present + */ + public rmFieldSanitizer: (theFieldSanitizer: IFieldValueSanitizerProvider) => void; + + /** + * Does this field value sanitizer handle this path / field combination + * @param path - The field path + * @param name - The name of the field + */ + public handleField: (path: string, name: string) => boolean; + + /** + * Sanitizes the value. It checks the that the property name and value are valid. It also + * checks/populates the correct type and pii of the property value. + * @param path - The root path of the property + * @param name - The property name. + * @param value - The property value or an IEventProperty containing value, type ,pii and customer content. + * @param stringifyObjects - If supplied tells the sanitizer that it should JSON stringify() objects + * @returns IEventProperty containing valid name, value, pii and type or null if invalid. + */ + public value: (path: string, name: string, value: FieldValueSanitizerTypes, stringifyObjects?: boolean) => IEventProperty | null; + + /** + * Sanitizes the Property. It checks the that the property name and value are valid. It also + * checks/populates the correct type and pii of the property value. + * @param path - The root path of the property + * @param name - The property name. + * @param property - The property value or an IEventProperty containing value, type ,pii and customer content. + * @param stringifyObjects - If supplied tells the sanitizer that it should JSON stringify() objects + * @returns IEventProperty containing valid name, value, pii and type or null if invalid. + */ + public property: (path: string, name: string, property: IEventProperty, stringifyObjects?: boolean) => IEventProperty | null; + + /** + * Returns whether this ValueSanitizer is empty + * @returns `true` if it contains no chained sanitizers or field sanitizers, otherwise `false` + */ + public isEmpty?: () => boolean; + + constructor(fieldSanitizerProvider?: IFieldValueSanitizerProvider) { + let _self = this; + + // To aid with performance this is a lookup map to check if the field value sanitizer supports this field + let _sanitizerMap: { [path: string]: { [field: string]: ISanitizerMapValue } } = {}; + let _sanitizers: IValueSanitizer[] = []; + let _fieldSanitizers: IFieldValueSanitizerProvider[] = []; + if (fieldSanitizerProvider) { + _fieldSanitizers.push(fieldSanitizerProvider); + } + + function _getFieldSanitizer(path: string, name: string): ISanitizerMapValue { + let result: ISanitizerMapValue; + let fieldLookup = _sanitizerMap[path]; + if (fieldLookup) { + result = fieldLookup[name]; + } + + if (!result && result !== null) { + // Null is a valid result indicating that the value sanitizer does not support this field + if (isString(path) && isString(name)) { + if (_fieldSanitizers.length > 0) { + for (let lp = 0; lp < _fieldSanitizers.length; lp++) { + if (_fieldSanitizers[lp].handleField(path, name)) { + result = { + canHandle: true, // This instance will handle so we won't assign the handler + fieldHandler: _fieldSanitizers[lp] + }; + break; + } + } + } else if (_sanitizers.length === 0) { + // Special use-case where there is no sanitizer to pass on to, so just resolving the field + // and returning the resulting value (same as sanitizeProperty()) + result = { + canHandle: true + }; + } + } + + // We still don't have a handler so lets lookup the providers + if (!result && result !== null) { + // Setting the result to null -- which means we and any contained sanitizers can't handle this field + result = null; + for (let lp = 0; lp < _sanitizers.length; lp++) { + if (_sanitizers[lp].handleField(path, name)) { + result = { + canHandle: true, + handler: _sanitizers[lp], + fieldHandler: null + }; + break; + } + } + } + + if (!fieldLookup) { + // Handle edge case to avoid prototype pollution + if (_isSpecialName(path)) { + return null; + } + + fieldLookup = _sanitizerMap[path] = {}; + } + + // Handle edge case to avoid prototype pollution + if (_isSpecialName(name)) { + return null; + } + + fieldLookup[name] = result; + } + + return result; + } + + _self.clearCache = () => { + _sanitizerMap = {}; + }; + + _self.addSanitizer = (newSanitizer: IValueSanitizer) => { + if (newSanitizer) { + if (!arrIncludes(_sanitizers, newSanitizer)) { + _sanitizers.push(newSanitizer); + } + + // Invalidate any previously mapped fields + _sanitizerMap = {}; + } + }; + + _self.addFieldSanitizer = (fieldSanitizer: IFieldValueSanitizerProvider) => { + if (fieldSanitizer) { + if (!arrIncludes(_fieldSanitizers, fieldSanitizer)) { + _fieldSanitizers.push(fieldSanitizer); + } + + // Invalidate any previously mapped fields + _sanitizerMap = {}; + } + }; + + _self.rmSanitizer = (theSanitizer: IValueSanitizer) => { + if (theSanitizer) { + let idx = arrIndexOf(_sanitizers, theSanitizer); + if (idx !== -1) { + _sanitizers.splice(idx, 1); + // Invalidate any previously mapped fields + _sanitizerMap = {}; + } + + // Try and remove the sanitizer from any chained sanitizer as well + arrForEach(_sanitizers, (sanitizer) => { + sanitizer && sanitizer.rmSanitizer && sanitizer.rmSanitizer(theSanitizer); + }); + } + }; + + _self.rmFieldSanitizer = (theFieldSanitizer: IFieldValueSanitizerProvider) => { + if (theFieldSanitizer) { + let idx = arrIndexOf(_fieldSanitizers, theFieldSanitizer); + if (idx !== -1) { + _fieldSanitizers.splice(idx, 1); + // Invalidate any previously mapped fields + _sanitizerMap = {}; + } + + // Try and remove the field sanitizer from any chained sanitizer as well + arrForEach(_sanitizers, (sanitizer) => { + sanitizer && sanitizer.rmFieldSanitizer && sanitizer.rmFieldSanitizer(theFieldSanitizer); + }); + } + }; + + _self.isEmpty = () => { + return (getLength(_sanitizers) + getLength(_fieldSanitizers)) === 0; + }; + + _self.handleField = (path: string, name: string): boolean => { + let mapValue: ISanitizerMapValue = _getFieldSanitizer(path, name); + return mapValue ? mapValue.canHandle : false; + }; + + _self.value = (path: string, name: string, value: FieldValueSanitizerTypes, stringifyObjects?: boolean): IEventProperty | null => { + let mapValue: ISanitizerMapValue = _getFieldSanitizer(path, name); + if (mapValue && mapValue.canHandle) { + if (!mapValue.canHandle) { + return null; + } + + if (mapValue.handler) { + // This value sanitizer can't handle this field so pass it only the next one + return mapValue.handler.value(path, name, value, stringifyObjects); + } + + // Check that property is valid + if (!isString(name) || isNullOrUndefined(value) || (value as any) === STR_EMPTY) { + return null; + } + + let property = null; + let fieldType = getFieldValueType(value); + + if ((fieldType & FieldValueSanitizerType.EventProperty) === FieldValueSanitizerType.EventProperty) { + let subType = fieldType & ~FieldValueSanitizerType.EventProperty; + property = value as IEventProperty; + if (!isValueAssigned(property.value) || + (subType !== FieldValueSanitizerType.String && + subType !== FieldValueSanitizerType.Number && + subType !== FieldValueSanitizerType.Boolean && + (subType & FieldValueSanitizerType.Array) !== FieldValueSanitizerType.Array)) { + + // Not a supported IEventProperty type to be able to sanitize + return null; + } + } else if (fieldType === FieldValueSanitizerType.String || + fieldType === FieldValueSanitizerType.Number || + fieldType === FieldValueSanitizerType.Boolean || + (fieldType & FieldValueSanitizerType.Array) === FieldValueSanitizerType.Array) { + // If the property isn't IEventProperty (and is either string, number, boolean or array), convert it into one. + property = _convertToProperty(path, name, value); + } else if (fieldType === FieldValueSanitizerType.Object) { + property = _convertToProperty(path, name, !!stringifyObjects ? JSON.stringify(value) : value); + } + + if (property) { + return _handleProperty(mapValue, path, name, fieldType, property, stringifyObjects); + } + } + + return null; + }; + + _self.property = (path: string, name: string, property: IEventProperty, stringifyObjects?: boolean): IEventProperty | null => { + let mapValue: ISanitizerMapValue = _getFieldSanitizer(path, name); + if (!mapValue || !mapValue.canHandle) { + return null; + } + + // Check that property is valid + if (!isString(name) || isNullOrUndefined(property) || !isValueAssigned(property.value)) { + return null; + } + + let fieldType: FieldValueSanitizerType = getFieldValueType(property.value); + if (fieldType === FieldValueSanitizerType.NotSet) { + // Not a supported field that we can sanitize or serialize + return null; + } + + return _handleProperty(mapValue, path, name, fieldType, property, stringifyObjects); + }; + + function _handleProperty(mapValue: ISanitizerMapValue, path: string, name: string, fieldType: FieldValueSanitizerType, + property: IEventProperty, stringifyObjects?: boolean): IEventProperty | null { + + if (mapValue.handler) { + // This value sanitizer can't handle this field so pass it only the next one + return mapValue.handler.property(path, name, property, stringifyObjects); + } + + // If either pii or cc is set convert value to string (since only string pii/cc is allowed). + // If the value is a complex type like an array that can't be converted to string we will drop + // the property. + if (!isNullOrUndefined(property.kind)) { + if ((fieldType & FieldValueSanitizerType.Array) === FieldValueSanitizerType.Array || !isValueKind(property.kind)) { + return null; + } + + // Convert the value to a string and assign back to the original value + property.value = property.value.toString(); + } + + return _callFieldSanitizer(mapValue.fieldHandler, path, name, fieldType, property); + } + + function _convertToProperty(path: string, name: string, value: any): IEventProperty | null { + if (isValueAssigned(value)) { + return { value: value } as IEventProperty; + } + + return null; + } + + function _callFieldSanitizer(fieldProvider: IFieldValueSanitizerProvider, path: string, name: string, theType: FieldValueSanitizerType, property: IEventProperty) { + if (property && fieldProvider) { + let sanitizer: FieldValueSanitizerFunc = fieldProvider.getSanitizer(path, name, theType, property.kind, property.propertyType); + if (sanitizer) { + // This is where we the field will call the handler to "scrub" the value. This the primary hook for the ClientHashing Plugin to + // be able to apply the hashFunc() / Sha256 conversion of the properties value + if (theType === FieldValueSanitizerType.Object) { + // Special case of an embedded object (ext.metadata, data.properties) + let newValue: any = { }; + let propValue = property.value; + objForEachKey(propValue, (propKey, theValue) => { + let newPath = path + "." + name; + if (isValueAssigned(theValue)) { + let newProp = _convertToProperty(newPath, propKey, theValue); + newProp = _callFieldSanitizer(fieldProvider, newPath, propKey, getFieldValueType(theValue), newProp); + if (newProp) { + newValue[propKey] = newProp.value; + } + } + }); + + property.value = newValue; + } else { + let details: IFieldSanitizerDetails = { + path: path, + name: name, + type: theType, + prop: property, + sanitizer: _self + }; + + property = sanitizer.call(_self, details); + } + } + } + + return property; + } + } +} diff --git a/shared/otel-core/src/ext/extSpanUtils.ts b/shared/otel-core/src/ext/extSpanUtils.ts new file mode 100644 index 000000000..549cacf4c --- /dev/null +++ b/shared/otel-core/src/ext/extSpanUtils.ts @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { + ILazyValue, arrIncludes, asString, getLazy, getNavigator, isBoolean, isNullOrUndefined, isNumber, isString, strLower, strStartsWith, + throwError +} from "@nevware21/ts-utils"; +import { STR_NOT_SPECIFIED } from "../constants/InternalConstants"; +import { eOTelSpanKind } from "../enums/otel/OTelSpanKind"; +import { eOTelSpanStatusCode } from "../enums/otel/OTelSpanStatus"; +import { IAppInsightsCore } from "../interfaces/ai/IAppInsightsCore"; +import { IConfiguration } from "../interfaces/ai/IConfiguration"; +import { IExtendedTelemetryItem } from "../interfaces/ext/DataModels"; +import { OTelAttributeValue } from "../interfaces/otel/IOTelAttributes"; +import { IAttributeContainer } from "../interfaces/otel/attribute/IAttributeContainer"; +import { IReadableSpan } from "../interfaces/otel/trace/IReadableSpan"; +import { + getHttpClientIp, getHttpHost, getHttpMethod, getHttpScheme, getHttpStatusCode, getHttpUrl, getSyntheticType, getUserAgent +} from "../internal/commonUtils"; +import { hrTimeToMilliseconds } from "../internal/timeHelpers"; +import { + ATTR_CLIENT_ADDRESS, ATTR_CLIENT_PORT, ATTR_ENDUSER_ID, ATTR_ENDUSER_PSEUDO_ID, ATTR_ERROR_TYPE, ATTR_EXCEPTION_MESSAGE, + ATTR_EXCEPTION_STACKTRACE, ATTR_EXCEPTION_TYPE, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_NETWORK_LOCAL_ADDRESS, + ATTR_NETWORK_LOCAL_PORT, ATTR_NETWORK_PEER_ADDRESS, ATTR_NETWORK_PEER_PORT, ATTR_NETWORK_PROTOCOL_NAME, ATTR_NETWORK_PROTOCOL_VERSION, + ATTR_NETWORK_TRANSPORT, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_FULL, ATTR_URL_PATH, ATTR_URL_QUERY, ATTR_URL_SCHEME, + ATTR_USER_AGENT_ORIGINAL, EXP_ATTR_ENDUSER_ID, EXP_ATTR_ENDUSER_PSEUDO_ID, EXP_ATTR_SYNTHETIC_TYPE, SEMATTRS_DB_NAME, + SEMATTRS_DB_OPERATION, SEMATTRS_DB_STATEMENT, SEMATTRS_DB_SYSTEM, SEMATTRS_ENDUSER_ID, SEMATTRS_EXCEPTION_MESSAGE, + SEMATTRS_EXCEPTION_STACKTRACE, SEMATTRS_EXCEPTION_TYPE, SEMATTRS_HTTP_CLIENT_IP, SEMATTRS_HTTP_FLAVOR, SEMATTRS_HTTP_HOST, + SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_ROUTE, SEMATTRS_HTTP_SCHEME, SEMATTRS_HTTP_STATUS_CODE, SEMATTRS_HTTP_TARGET, SEMATTRS_HTTP_URL, + SEMATTRS_HTTP_USER_AGENT, SEMATTRS_NET_HOST_IP, SEMATTRS_NET_HOST_NAME, SEMATTRS_NET_HOST_PORT, SEMATTRS_NET_PEER_IP, + SEMATTRS_NET_PEER_NAME, SEMATTRS_NET_PEER_PORT, SEMATTRS_NET_TRANSPORT, SEMATTRS_PEER_SERVICE, SEMATTRS_RPC_GRPC_STATUS_CODE, + SEMATTRS_RPC_SYSTEM +} from "../otel/attribute/SemanticConventions"; +import { createAttributeContainer } from "../otel/attribute/attributeContainer"; +import { fieldRedaction } from "../utils/EnvUtils"; +import { toISOString } from "../utils/HelperFuncs"; + +/** + * Azure SDK namespace. + * @internal + */ +const AzNamespace = "az.namespace"; +const AzResourceNamespace = "azure.resource_provider.namespace"; + +const PORT_REGEX: ILazyValue = (/*#__PURE__*/ getLazy(() => new RegExp(/(https?)(:\/\/.*)(:\d+)(\S*)/))); +const HTTP_DOT = "http."; + +const _MS_PROCESSED_BY_METRICS_EXTRACTORS = "_MS.ProcessedByMetricExtractors"; + +/** + * Legacy HTTP semantic convention values + * @internal + */ +const _ignoreSemanticValues: ILazyValue = (/* #__PURE__*/ getLazy(_initIgnoreSemanticValues)); + +/** + * OTelSpan common schema Part B telemetry definition + */ +export interface IMsWebSpanTelemetry { + /** + * The span name is a human-readable string which concisely identifies the work + * represented by the Span, for example, an RPC method name, a function name, or + * the name of a subtask or stage within a larger computation. The span name should + * be the most general string that identifies a (statistically) interesting class + * of Spans, rather than individual Span instances. That is, "get_user" is a + * reasonable name, while "get_user/314159", where "314159" is a user ID, is not a + * good name due to its high cardinality. + * @see [OpenTelemetry Span Name Guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#span) + * @example + * ```json + * "get_user" + * ``` + */ + name: string; + + /** + * Based on OpenTelemetry definition of SpanKind + * it is the type of span. Can be used to specify additional relationships between + * spans in addition to a parent/child relationship. + * @example + * ```json + * 2 + * ``` + */ + kind: eOTelSpanKind; + + /** + * Start time of the span. This field must be formatted in UTC ISO8601 + * format, with a trailing 'Z' character. Note: the number of decimal + * seconds digits provided is variable (and unspecified). Consumers + * should handle this, i.e. managed code consumers should not use format + * "O" for parsing as it specifies a fixed length. + * @example + * ```json + * "2018-09-05T22:51:22.4936Z" + * ``` + */ + startTime: string; + + /** + * Boolean to indicate the status of the operation whether it was a success or + * failed. This field is required. When not set explicitly to false - a request is + * considered to be successful. + * @example + * ```json + * true + * ``` + */ + success: boolean; + + /** + * Status message for the span execution. This may be the exception type, error + * code or friendly message to indicate status for the operation. This can be used + * to report generic status for spans (not protocol-specific). + * @remark + * If you report `httpStatusCode`, `statusMessage` should not be reported and will be ignored. + * @example + * ```json + * "Connection Failure" + * ``` + */ + statusMessage?: string; + + /** + * The spanId of this span's parent span. If this is a root span, then this field + * must be empty. + * @example + * ```json + * "103067aa04a70897" + * ``` + */ + parentId?: string; + + /** + * For spans of type Client/Consumer for calls to Azure resources provide the Azure + * resource provider who would be fullfilling the request. Please follow the list + * provided [here](https://docs.microsoft.com/azure/azure-resource-manager/management/azure-services-resource-providers) + * @example + * ```json + * "Microsoft.EventHub" + * ``` + */ + azureResourceProvider?: string; + + /** + * Links can be used to represent batched operations where a Span was initiated by + * multiple initiating Spans, each representing a single incoming item being + * processed in the batch. Another example is to link operation that is causally + * related to multiple operations. The "allocate host" operation could potentially + * fulfill multiple "create vm" operations. + * + * An array of related span links + * @example + * ```json + * [{"toTraceId":"5eca8b153632494ba00f619d6877b134","toSpanId":"d4c1279b6e7b7c47"}] + * ``` + */ + links?: string; + + /** + * Duration of the span in milliseconds. This is the difference between + * endTime (the Part A "time" field) and startTime. + */ + duration?: number; + + /** + * TraceState provides vendor-specific trace context information. + * It is defined in the [W3C TraceContext specification](https://www.w3.org/TR/trace-context/#tracestate-header). + * @example + * ```json + * "rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" + * ``` + */ + traceState?: string; + + /** + * Additional properties + */ + [key: string]: any; +} + +/* #__NO_SIDE_EFFECTS__ */ +function _initIgnoreSemanticValues(): string[] { + return [ + // Internal Microsoft attributes + _MS_PROCESSED_BY_METRICS_EXTRACTORS, + + // Legacy HTTP semantic values + SEMATTRS_NET_PEER_IP, + SEMATTRS_NET_PEER_NAME, + SEMATTRS_NET_HOST_IP, + SEMATTRS_PEER_SERVICE, + SEMATTRS_HTTP_USER_AGENT, + SEMATTRS_HTTP_METHOD, + SEMATTRS_HTTP_URL, + SEMATTRS_HTTP_STATUS_CODE, + SEMATTRS_HTTP_ROUTE, + SEMATTRS_HTTP_HOST, + SEMATTRS_DB_SYSTEM, + SEMATTRS_DB_STATEMENT, + SEMATTRS_DB_OPERATION, + SEMATTRS_DB_NAME, + SEMATTRS_RPC_SYSTEM, + SEMATTRS_RPC_GRPC_STATUS_CODE, + SEMATTRS_EXCEPTION_TYPE, + SEMATTRS_EXCEPTION_MESSAGE, + SEMATTRS_EXCEPTION_STACKTRACE, + SEMATTRS_HTTP_SCHEME, + SEMATTRS_HTTP_TARGET, + SEMATTRS_HTTP_FLAVOR, + SEMATTRS_NET_TRANSPORT, + SEMATTRS_NET_HOST_NAME, + SEMATTRS_NET_HOST_PORT, + SEMATTRS_NET_PEER_PORT, + SEMATTRS_HTTP_CLIENT_IP, + SEMATTRS_ENDUSER_ID, + HTTP_DOT + "status_text", + + // http Semabtic conventions + ATTR_CLIENT_ADDRESS, + ATTR_CLIENT_PORT, + ATTR_SERVER_ADDRESS, + ATTR_SERVER_PORT, + ATTR_URL_FULL, + ATTR_URL_PATH, + ATTR_URL_QUERY, + ATTR_URL_SCHEME, + ATTR_ERROR_TYPE, + ATTR_NETWORK_LOCAL_ADDRESS, + ATTR_NETWORK_LOCAL_PORT, + ATTR_NETWORK_PROTOCOL_NAME, + ATTR_NETWORK_PEER_ADDRESS, + ATTR_NETWORK_PEER_PORT, + ATTR_NETWORK_PROTOCOL_VERSION, + ATTR_NETWORK_TRANSPORT, + ATTR_USER_AGENT_ORIGINAL, + ATTR_HTTP_REQUEST_METHOD, + ATTR_HTTP_RESPONSE_STATUS_CODE, + ATTR_EXCEPTION_TYPE, + ATTR_EXCEPTION_MESSAGE, + ATTR_EXCEPTION_STACKTRACE, + EXP_ATTR_ENDUSER_ID, + EXP_ATTR_ENDUSER_PSEUDO_ID, + EXP_ATTR_SYNTHETIC_TYPE, + + // Azure SDK attributes are not included as they are not part of the span attributes + AzNamespace, + AzResourceNamespace, + "az.client_request_id", + "azure.client.id", + "az.service_request_id", + "azure.service.request.id" + + ]; +} + +function _applyExtValue(ext: any, extName: any, name: string, value: V, overwriteExt: boolean ) { + if (isString(value) || isNumber(value) || isBoolean(value)) { + let target = ext[extName] = ext[extName] || {}; + _applyValue(target, name, value, overwriteExt); + } +} + +function _applyValue(target: any, name: string, value: V, overwriteTarget: boolean ) { + if (target) { + if (isString(value) || isNumber(value) || isBoolean(value)) { + let targetValue = target[name]; + if (!overwriteTarget && (targetValue || isString(targetValue) || isNumber(targetValue) || isBoolean(targetValue))) { + value = targetValue; + } + + target[name] = value; + } + } + + return target; +} + +function _populateExtensionsFromSpan(telemetryItem: IExtendedTelemetryItem, span: IReadableSpan, container: IAttributeContainer): void { + let ext = telemetryItem.ext = telemetryItem.ext || {}; + + // Map OpenTelemetry enduser attributes to Application Insights user attributes + const endUserId = container.get(ATTR_ENDUSER_ID); + if (endUserId) { + _applyExtValue(ext, "user", "authId", asString(endUserId), false); + } + + const endUserPseudoId = container.get(ATTR_ENDUSER_PSEUDO_ID); + if (endUserPseudoId) { + _applyExtValue(ext, "user", "id", asString(endUserPseudoId), false); + } +} + +/** + * Check to see if the key is in the list of known properties to ignore (exclude) + * from part C properties population. + * @param key - the property key to check + * @param contextKeys - The current context keys + * @returns true if the key should be ignored, false otherwise + */ +function _isIgnorePartCKey(key: string): boolean { + let result = false; + + if (arrIncludes(_ignoreSemanticValues.v, key)) { + // The key is in set of known keys to ignore + result = true; + } else if (strStartsWith(key, "microsoft.")) { + // Ignoring all ALL keys starting with "microsoft." + result = true; + } + + return result; +} + +function _populatePartC(item: IExtendedTelemetryItem, container: IAttributeContainer): void { + if (container) { + let partC = item.data = (item.data || {}); + + _applyValue(partC, "httpHost", getHttpHost(container), false); + _applyValue(partC, "httpScheme", getHttpScheme(container), false); + _applyValue(partC, "httpClientIp", getHttpClientIp(container), false); + _applyValue(partC, "httpUserAgent", getUserAgent(container), false); + _applyValue(partC, "httpRoute", container.get(SEMATTRS_HTTP_ROUTE), false); + + _applyValue(partC, "netPeerName", container.get(SEMATTRS_NET_PEER_NAME), false); + _applyValue(partC, "netPeerPort", container.get(SEMATTRS_NET_PEER_PORT), false); + _applyValue(partC, "netPeerIp", container.get(SEMATTRS_NET_PEER_IP), false); + _applyValue(partC, "peerService", container.get("service.name") || container.get(SEMATTRS_PEER_SERVICE), false); + + let syntheticSource = getSyntheticType(container); + if (!!syntheticSource) { + _applyValue(partC, "userAgentSyntheticType", syntheticSource, false); + } + + let nav = getNavigator(); + if (nav && nav.userAgent) { + _applyValue(partC, "userAgentOriginal", nav.userAgent, false); + } + + // Azure SDK fields + _applyValue(partC, "azureClientRequestId", container.get("azure.client.id") || container.get("az.client_request_id"), false); + _applyValue(partC, "azureServiceRequestId", container.get("azure.service.request.id") || container.get("az.service_request_id"), false); + + + let sampleRate = container.get("microsoft.sample_rate"); + if (!isNullOrUndefined(sampleRate)) { + _applyValue(partC, "sampleRate", sampleRate, false); + } + + container.forEach((key: string, value) => { + // Avoid duplication ignoring fields already mapped. + if (!_isIgnorePartCKey(key)) { + partC[key] = value; + } + }); + } +} + +function _populateHttpProperties(otelSpanTelemetry: IMsWebSpanTelemetry, container: IAttributeContainer, httpMethod: OTelAttributeValue | undefined, config: IConfiguration): void { + if (httpMethod) { + // Step the HTTP method + _applyValue(otelSpanTelemetry, "httpMethod", httpMethod, false); + + // HTTP Dependency + let httpUrl = getHttpUrl(container); + if (httpUrl) { + try { + // Remove default port + const res = PORT_REGEX.v.exec(asString(httpUrl)); + if (res !== null) { + const protocol = res[1]; + const port = res[3]; + if ( + (protocol === "https" && port === ":443") || + (protocol === "http" && port === ":80") + ) { + // Drop port + httpUrl = res[1] + res[2] + res[4]; + } + } + } catch { + /* no-op */ + } + + _applyValue(otelSpanTelemetry, "httpUrl", fieldRedaction(asString(httpUrl), config), false); + } + + const httpStatusCode = getHttpStatusCode(container); + if (httpStatusCode) { + _applyValue(otelSpanTelemetry, "httpStatusCode", httpStatusCode, false); + } + } +} + +function _populateDbProperties(otelSpanTelemetry: IMsWebSpanTelemetry, container: IAttributeContainer, dbSystem: OTelAttributeValue | undefined): void { + if (dbSystem) { + _applyValue(otelSpanTelemetry, "dbSystem", dbSystem, false); + + // Set the statement + _applyValue(otelSpanTelemetry, "dbStatement", container.get(SEMATTRS_DB_STATEMENT) || container.get(SEMATTRS_DB_OPERATION), false); + _applyValue(otelSpanTelemetry, "dbName", container.get(SEMATTRS_DB_NAME) || dbSystem || "", false); + } +} + +function _populateRpcDependencyProperties(otelSpanTelemetry: IMsWebSpanTelemetry, container: IAttributeContainer, rpcSystem: OTelAttributeValue | undefined): void { + if (rpcSystem) { + _applyValue(otelSpanTelemetry, "rpcSystem", strLower(rpcSystem), false); + _applyValue(otelSpanTelemetry, "rpcGrpcStatusCode", container.get(SEMATTRS_RPC_GRPC_STATUS_CODE), false); + } +} + +function _createOTelSpanTelemetryItem(core: IAppInsightsCore, span: IReadableSpan): IExtendedTelemetryItem { + let container = span.attribContainer || createAttributeContainer(span.attributes); + let spanCtx = span.spanContext(); + + let statusCode = span.status ? span.status.code : eOTelSpanStatusCode.UNSET; + + let spanTelemetry: IMsWebSpanTelemetry = { + name: span.name, // Default + kind: span.kind, + startTime: toISOString(new Date(hrTimeToMilliseconds(span.startTime))), + success: statusCode !== eOTelSpanStatusCode.UNSET ? statusCode !== eOTelSpanStatusCode.ERROR : (Number(getHttpStatusCode(container)) || 0) < 400, + duration: hrTimeToMilliseconds(span.duration) + //azureResourceProvider: undefined, // Not currently supported + //links: UNDEFINED_VALUE, // Not currently supported + }; + + // Set the parentId if available + let parentCtx = span.parentSpanContext || (spanCtx ? spanCtx.parentCtx : null); + _applyValue(spanTelemetry, "parentId", span.parentSpanId || (parentCtx ? parentCtx.spanId : null), false); + + if (spanCtx) { + let traceState = spanCtx.traceState; + if (traceState && !traceState.isEmpty) { + _applyValue(spanTelemetry, "traceState", traceState.hdrs(1)[0], false); + } + } + + _populateHttpProperties(spanTelemetry, container, getHttpMethod(container), core.config); + _populateDbProperties(spanTelemetry, container, container.get(SEMATTRS_DB_SYSTEM)); + _populateRpcDependencyProperties(spanTelemetry, container, container.get(SEMATTRS_RPC_SYSTEM)); + + _applyValue(spanTelemetry, "azureResourceProvider", container.get(AzResourceNamespace) || container.get(AzNamespace), false); + + return _createTelemetryItem(spanTelemetry, span, "OTelSpan", "Ms.Web.Span"); +} + +function _createTelemetryItem(item: T, span: IReadableSpan, baseType: string, eventName: string): IExtendedTelemetryItem { + + eventName = eventName || STR_NOT_SPECIFIED; + + if (isNullOrUndefined(item) || + isNullOrUndefined(baseType) || + isNullOrUndefined(eventName)) { + throwError("Input doesn't contain all required fields"); + } + + let iKey = ""; + if ((item as any).iKey) { + iKey = (item as any).iKey; + delete (item as any).iKey; + } + + let telemetryItem: IExtendedTelemetryItem = { + name: eventName, + time: toISOString(span.endTime ? new Date(hrTimeToMilliseconds(span.endTime)) : new Date()), + iKey: iKey, // this will be set in TelemetryContext + ext: {}, // part A + baseType, + baseData: item as any, // Part B + data: {} // part C + }; + + return telemetryItem; +} + +/** + * Create an extended common schema telemetry item from the provided span + * @param core - The app insights core instance + * @param span - The span to create the telemetry item from + * @returns A new extended telemetry item or null if the span kind is not supported + */ +export function createExtendedTelemetryItemFromSpan(core: IAppInsightsCore, span: IReadableSpan): IExtendedTelemetryItem | null { + let telemetryItem: IExtendedTelemetryItem = _createOTelSpanTelemetryItem(core, span); + let container = span.attribContainer || createAttributeContainer(span.attributes); + + if (telemetryItem) { + // Set the Span common schema fields + + // Set start time for the telemetry item from the event, not the time it is being processed (the default) + // The channel envelope creator uses this value when creating the envelope only when defined, otherwise it + // uses the time when the item is being processed + let partB = telemetryItem.baseData = telemetryItem.baseData || {}; + partB.startTime = new Date(hrTimeToMilliseconds(span.startTime)); + + let spanContext = span.spanContext(); + if (spanContext) { + // Add dt extension to the telemetry item + let ext = telemetryItem.ext = telemetryItem.ext || {}; + let dt = ext["dt"] = ext["dt"] || {}; + + // Don't overwrite any existing values + _applyValue(dt, "spanId", spanContext.spanId, false); + _applyValue(dt, "traceId", spanContext.traceId, false); + _applyValue(dt, "traceFlags", spanContext.traceFlags, false); + } + + _populateExtensionsFromSpan(telemetryItem, span, container); + _populatePartC(telemetryItem, container); + + // Azure SDK + } + + return telemetryItem; +} diff --git a/shared/otel-core/src/ext/extUtils.ts b/shared/otel-core/src/ext/extUtils.ts new file mode 100644 index 000000000..19518a388 --- /dev/null +++ b/shared/otel-core/src/ext/extUtils.ts @@ -0,0 +1,433 @@ +/** +* Utils.ts +* @author Abhilash Panwar (abpanwar) Hector Hernandez (hectorh) +* @copyright Microsoft 2018 +* File containing utility functions. +*/ +import { + arrForEach, getInst as getGlobalInst, getNavigator, hasDocument, hasWindow, isArray, isBoolean, isNullOrUndefined, isNumber, isObject, + isString, isUndefined, objForEachKey, perfNow, strIndexOf, strLeft +} from "@nevware21/ts-utils"; +import { STR_EMPTY } from "../constants/InternalConstants"; +import { EventLatency, EventLatencyValue, FieldValueSanitizerType, GuidStyle, eEventPropertyType, eValueKind } from "../enums/ext/Enums"; +import { ICookieMgr } from "../interfaces/ai/ICookieMgr"; +import { ITelemetryItem } from "../interfaces/ai/ITelemetryItem"; +import { IEventProperty, IExtendedTelemetryItem } from "../interfaces/ext/DataModels"; +import { newGuid } from "../utils/CoreUtils"; +import { isReactNative } from "../utils/EnvUtils"; + +export const Version = "#version#"; +export const FullVersionString = "1DS-Web-JS-" + Version; + +const ObjHasOwnProperty = Object.prototype.hasOwnProperty; + +// Defining here so we don't need to take (import) the ApplicationInsights Common module +const strDisabledPropertyName: string = "Microsoft_ApplicationInsights_BypassAjaxInstrumentation"; +const strWithCredentials: string = "withCredentials"; +const strTimeout: string = "timeout"; + +// If value is array just get the type for the first element +const _fieldTypeEventPropMap = { + [FieldValueSanitizerType.NotSet]: eEventPropertyType.Unspecified, + [FieldValueSanitizerType.Number]: eEventPropertyType.Double, + [FieldValueSanitizerType.String]: eEventPropertyType.String, + [FieldValueSanitizerType.Boolean]: eEventPropertyType.Bool, + [FieldValueSanitizerType.Array | FieldValueSanitizerType.Number]: eEventPropertyType.Double, + [FieldValueSanitizerType.Array | FieldValueSanitizerType.String]: eEventPropertyType.String, + [FieldValueSanitizerType.Array | FieldValueSanitizerType.Boolean]: eEventPropertyType.Bool +}; + +/** + * @ignore + */ +// let _uaDisallowsSameSiteNone = null; + +var uInt8ArraySupported: boolean | null = (/* #__PURE__*/ null); +// var _areCookiesAvailable: boolean | undefined; + +/** + * Checks if document object is available + */ +export const isDocumentObjectAvailable: boolean = (/* #__PURE__*/ hasDocument()); + +/** + * Checks if window object is available + */ +export const isWindowObjectAvailable: boolean = (/* #__PURE__*/ hasWindow()); + +/** + * Checks if value is assigned to the given param. + * @param value - The token from which the tenant id is to be extracted. + * @returns True/false denoting if value is assigned to the param. + */ +export function isValueAssigned(value: any) { + /// takes a value and checks for undefined, null and empty string + /// value to be tested + /// true if value is null undefined or emptyString + return !(value === STR_EMPTY || isNullOrUndefined(value)); +} + +/** + * Gets the tenant id from the tenant token. + * @param apiKey - The token from which the tenant id is to be extracted. + * @returns The tenant id. + */ +export function getTenantId(apiKey: string | undefined): string { + if (apiKey) { + let indexTenantId = strIndexOf(apiKey, "-"); + if (indexTenantId > -1) { + return strLeft(apiKey, indexTenantId); + } + } + return STR_EMPTY; +} + +/** + * Checks if Uint8Array are available in the current environment. Safari and Firefox along with + * ReactNative are known to not support Uint8Array properly. + * @returns True if available, false otherwise. + */ +export function isUint8ArrayAvailable(): boolean { + if (uInt8ArraySupported === null) { + uInt8ArraySupported = !isUndefined(Uint8Array) && !isSafariOrFirefox() && !isReactNative(); + } + return uInt8ArraySupported; +} + +/** + * Checks if the value is a valid EventLatency. + * @param value - The value that needs to be checked. + * @returns True if the value is in AWTEventLatency, false otherwise. + */ +export function isLatency(value: EventLatency | undefined): boolean { + if (value && isNumber(value) && value >= EventLatencyValue.Normal && value <= EventLatencyValue.Immediate) { + return true; + } + return false; +} + +/** + * Sanitizes the Property. It checks the that the property name and value are valid. It also + * checks/populates the correct type and pii of the property value. + * @param name - property name - The property name. + * @param property - The property value or an IEventProperty containing value, + * type ,pii and customer content. + * @returns IEventProperty containing valid name, value, pii and type or null if invalid. + */ +export function sanitizeProperty(name: string, + property: string | number | boolean | string[] | number[] | boolean[] | object | IEventProperty, + stringifyObjects?: boolean): IEventProperty | null { + // Check that property is valid + if ((!property && !isValueAssigned(property)) || typeof name !== "string") { + return null; + } + + // Perf optimization -- only need to get the type once not multiple times + let propType = typeof property; + + // If the property isn't IEventProperty (and is either string, number, boolean or array), convert it into one. + if (propType === "string" || propType === "number" || propType === "boolean" || isArray(property)) { + property = ({ value: property } as IEventProperty); + } else if (propType === "object" && !ObjHasOwnProperty.call(property, "value")) { + property = ({ value: stringifyObjects ? JSON.stringify(property) : property } as IEventProperty); + } else if (isNullOrUndefined((property as IEventProperty).value) + || (property as IEventProperty).value === STR_EMPTY || (!isString((property as IEventProperty).value) + && !isNumber((property as IEventProperty).value) && !isBoolean((property as IEventProperty).value) + && !isArray((property as IEventProperty).value))) { + // Since property is IEventProperty, we need to validate its value + return null; + } + + // We need to check that if the property value is an array, it is valid + if (isArray((property as IEventProperty).value) && + !isArrayValid((property as IEventProperty).value as string[] | number[] | boolean[])) { + return null; + } + + // If either pii or cc is set convert value to string (since only string pii/cc is allowed). + // If the value is a complex type like an array that can't be converted to string we will drop + // the property. + if (!isNullOrUndefined((property as IEventProperty).kind)) { + if (isArray((property as IEventProperty).value) || !isValueKind((property as IEventProperty).kind)) { + return null; + } + + (property as IEventProperty).value = (property as IEventProperty).value.toString(); + } + + return (property as IEventProperty); +} + +export function getCommonSchemaMetaData(value: string | boolean | number | string[] | number[] | boolean[] | undefined, kind: number | undefined, type?: number | undefined): number { + let encodedTypeValue = -1; + + if (!isUndefined(value)) { + if (kind > 0) { + if (kind === eValueKind.CustomerContent_GenericContent) { + // encode customer content. Value can only be string. bit 13-16 are for cc + encodedTypeValue = (1 << 13); + } else if (kind <= 13) { + // encode PII. Value can only be string. bits 5-12 are for Pii + encodedTypeValue = (kind << 5); + } + } + + // isDataType checks that the "type" is a number so we don't need to check for undefined + if (isDataType(type)) { + // Data Type is provided and valid, so use that + if (encodedTypeValue === -1) { + // Don't return -1 + encodedTypeValue = 0; + } + + encodedTypeValue |= type; + } else { + let propType = _fieldTypeEventPropMap[getFieldValueType(value)] || -1; + + if (encodedTypeValue !== -1 && propType !== -1) { + // pii exists so we must return correct type + encodedTypeValue |= propType; + } else if (propType === eEventPropertyType.Double) { + encodedTypeValue = propType; + } + } + } + + return encodedTypeValue; +} + +/** + * Helper to get and decode the cookie value using decodeURIComponent, this is for historical + * backward compatibility where the document.cookie value was decoded before parsing. + * @param cookieMgr - The cookie manager to use + * @param name - The name of the cookie to get + * @param decode - A flag to indicate whether the cookie value should be decoded + * @returns The decoded cookie value (if available) otherwise an empty string. + */ +export function getCookieValue(cookieMgr: ICookieMgr, name: string, decode: boolean = true): string { + let cookieValue: string; + if (cookieMgr) { + cookieValue = cookieMgr.get(name); + if (decode && cookieValue && decodeURIComponent) { + cookieValue = decodeURIComponent(cookieValue); + } + } + + return cookieValue || STR_EMPTY; +} + +/** + * Create a new guid. + * @param style - The style of guid to generated, defaults to Digits + * Digits (Default) : 32 digits separated by hyphens: 00000000-0000-0000-0000-000000000000 + * Braces - 32 digits separated by hyphens, enclosed in braces: \{00000000-0000-0000-0000-000000000000\} + * Parentheses - 32 digits separated by hyphens, enclosed in parentheses: (00000000-0000-0000-0000-000000000000) + * Numeric - 32 digits: 00000000000000000000000000000000 + */ +export function createGuid(style: GuidStyle = GuidStyle.Digits): string { + let theGuid = newGuid(); + if (style === GuidStyle.Braces) { + theGuid = "{" + theGuid + "}"; + } else if (style === GuidStyle.Parentheses) { + theGuid = "(" + theGuid + ")"; + } else if (style === GuidStyle.Numeric) { + theGuid = theGuid.replace(/-/g, STR_EMPTY); + } + + return theGuid; +} + +/** + * Pass in the objects to merge as arguments. + * @param obj1 - object to merge. Set this argument to 'true' for a deep extend. + * @param obj2 - object to merge. + * @param obj3 - object to merge. + * @param obj4 - object to merge. + * @param obj5 - object to merge. + * @returns The extended object. + */ +export function extend(obj?: any, obj2?: any, obj3?: any, obj4?: any, obj5?: any): any { + // Variables + var extended = {}; + var deep = false; + var i = 0; + var length = arguments.length; + var theArgs = arguments; + + // Check if a deep merge + if (isBoolean(theArgs[0])) { + deep = theArgs[0]; + i++; + } + + // Loop through each object and conduct a merge + for (; i < length; i++) { + var obj = theArgs[i]; + objForEachKey(obj, (prop, value) => { + // If deep merge and property is an object, merge properties + if (deep && value && isObject(value)) { + if (isArray(value)) { + extended[prop] = extended[prop] || []; + arrForEach(value, (arrayValue, arrayIndex) => { + if (arrayValue && isObject(arrayValue)) { + extended[prop][arrayIndex] = extend(true, extended[prop][arrayIndex], arrayValue); + } else { + extended[prop][arrayIndex] = arrayValue; + } + }); + } else { + extended[prop] = extend(true, extended[prop], value); + } + } else { + extended[prop] = value; + } + }); + } + + return extended; +} + +export let getTime = perfNow; + +export function isValueKind(value: number | undefined): boolean { + // Always assume that it's a number (no type checking) for performance as this is used during the JSON serialization + if (value === eValueKind.NotSet || ((value > eValueKind.NotSet && value <= eValueKind.Pii_IPV4AddressLegacy) || value === eValueKind.CustomerContent_GenericContent)) { + return true; + } + + return false; +} + +function isDataType(value: number): boolean { + // Remark: 0 returns false, but it doesn't affect encoding anyways + // Always assume that it's a number (no type checking) for performance as this is used during the JSON serialization + if (value >= 0 && value <= 9) { + return true; + } + return false; +} + +function isSafariOrFirefox(): boolean { + var nav = getNavigator(); + // If non-browser navigator will be undefined + if (!isUndefined(nav) && nav.userAgent) { + var ua = nav.userAgent.toLowerCase(); + if ((ua.indexOf("safari") >= 0 || ua.indexOf("firefox") >= 0) && ua.indexOf("chrome") < 0) { + return true; + } + } + return false; +} + +export function isArrayValid(value: any[]): boolean { + return value.length > 0; +} + +export function setProcessTelemetryTimings(event: ITelemetryItem, identifier: string): void { + var evt = event as IExtendedTelemetryItem; + evt.timings = evt.timings || {}; + evt.timings.processTelemetryStart = evt.timings.processTelemetryStart || {}; + evt.timings.processTelemetryStart[identifier] = getTime(); +} + +/** + * Returns a bitwise value for the FieldValueSanitizerType enum representing the decoded type of the passed value + * @param value - The value to determine the type + */ +export function getFieldValueType(value: any): FieldValueSanitizerType { + let theType: FieldValueSanitizerType = FieldValueSanitizerType.NotSet; + + if (value !== null && value !== undefined) { + let objType = typeof value; + if (objType === "string") { + theType = FieldValueSanitizerType.String; + } else if (objType === "number") { + theType = FieldValueSanitizerType.Number; + } else if (objType === "boolean") { + theType = FieldValueSanitizerType.Boolean; + } else if (objType === "object") { + theType = FieldValueSanitizerType.Object; + if (isArray(value)) { + theType = FieldValueSanitizerType.Array; + if (value.length > 0) { + // Empty arrays are not supported and are considered to be the same as null + theType |= getFieldValueType(value[0]); + } + } else if (ObjHasOwnProperty.call(value, "value")) { + // Looks like an IEventProperty + theType = FieldValueSanitizerType.EventProperty | getFieldValueType(value.value); + } + } + } + + return theType; +} + +/** + * Helper to identify whether we are running in a chromium based browser environment + */ +export function isChromium() { + return !!getGlobalInst("chrome"); +} + +/** + * Create and open an XMLHttpRequest object + * @param method - The request method + * @param urlString - The url + * @param withCredentials - Option flag indicating that credentials should be sent + * @param disabled - Optional flag indicating that the XHR object should be marked as disabled and not tracked (default is false) + * @param isSync - Optional flag indicating if the instance should be a synchronous request (defaults to false) + * @param timeout - Optional value identifying the timeout value that should be assigned to the XHR request + * @returns A new opened XHR request + */ +export function openXhr(method: string, urlString: string, withCredentials?: boolean, disabled: boolean = false, isSync: boolean = false, timeout?: number) { + + function _wrapSetXhrProp(xhr: XMLHttpRequest, prop: string, value: T) { + try { + xhr[prop] = value; + } catch (e) { + // - Wrapping as depending on the environment setting the property may fail (non-terminally) + } + } + + let xhr = new XMLHttpRequest(); + + if (disabled) { + // Tag the instance so it's not tracked (trackDependency) + // If the environment has locked down the XMLHttpRequest (preventExtensions and/or freeze), this would + // cause the request to fail and we no telemetry would be sent + _wrapSetXhrProp(xhr, strDisabledPropertyName, disabled); + } + + if (withCredentials) { + // Some libraries require that the withCredentials flag is set "before" open and + // - Wrapping as IE 10 has started throwing when setting before open + _wrapSetXhrProp(xhr, strWithCredentials, withCredentials); + } + + xhr.open(method, urlString, !isSync); + + if (withCredentials) { + // withCredentials should be set AFTER open (https://xhr.spec.whatwg.org/#the-withcredentials-attribute) + // And older firefox instances from 11+ will throw for sync events (current versions don't) which happens during unload processing + _wrapSetXhrProp(xhr, strWithCredentials, withCredentials); + } + + // Only set the timeout for asynchronous requests as + // "Timeout shouldn't be used for synchronous XMLHttpRequests requests used in a document environment or it will throw an InvalidAccessError exception."" + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout + if (!isSync && timeout) { + _wrapSetXhrProp(xhr, strTimeout, timeout); + } + + return xhr; +} + +/** + * Check to see if the value is \> 0 + * @param value - The value to check + * @returns true if \> 0 otherwise false + */ +export function isGreaterThanZero(value: number) { + return value > 0; +} diff --git a/shared/otel-core/src/index.ts b/shared/otel-core/src/index.ts index 0d05a7e04..408072bb5 100644 --- a/shared/otel-core/src/index.ts +++ b/shared/otel-core/src/index.ts @@ -18,7 +18,7 @@ export { IPayloadData, SendPOSTFunction, IXHROverride, OnCompleteCallback } from export { IUnloadHook, ILegacyUnloadHook } from "./interfaces/ai/IUnloadHook"; export { eEventsDiscardedReason, EventsDiscardedReason, eBatchDiscardedReason, BatchDiscardedReason } from "./enums/ai/EventsDiscardedReason"; export { eDependencyTypes, DependencyTypes } from "./enums/ai/DependencyTypes"; -export { SendRequestReason, TransportType } from "./enums/ai/SendRequestReason"; +export { SendRequestReason } from "./enums/ai/SendRequestReason"; //export { StatsType, eStatsType } from "./enums/ai/StatsType"; export { TelemetryUpdateReason } from "./enums/ai/TelemetryUpdateReason"; export { TelemetryUnloadReason } from "./enums/ai/TelemetryUnloadReason"; @@ -375,7 +375,7 @@ export { IUser, IUserContext } from "./interfaces/ai/context/IUser"; export { ITelemetryTrace } from "./interfaces/ai/context/ITelemetryTrace"; // Enums -export { eDistributedTracingModes, DistributedTracingModes, EventPersistence } from "./enums/ai/Enums"; +export { eDistributedTracingModes, DistributedTracingModes, EventPersistence, EventPersistenceValue } from "./enums/ai/Enums"; export { eTraceHeadersMode } from "./enums/ai/TraceHeadersMode"; // Helper functions @@ -411,3 +411,44 @@ export { export const PropertiesPluginIdentifier = "AppInsightsPropertiesPlugin"; export const BreezeChannelIdentifier = "AppInsightsChannelPlugin"; export const AnalyticsPluginIdentifier = "ApplicationInsightsAnalytics"; + +// ========================================================================== +// 1DS (OneCollector) exports - merged from @microsoft/1ds-core-js +// ========================================================================== + +// 1DS Enums +export { + ValueKind, eValueKind, + EventLatency, EventLatencyValue, + EventPropertyType, eEventPropertyType, + EventSendType, + TraceLevel, eTraceLevel, + _ExtendedInternalMessageId, _eExtendedInternalMessageId, + GuidStyle, FieldValueSanitizerType, + TransportType +} from "./enums/ext/Enums"; + +// 1DS Data Models (interfaces) +export { + IExtendedConfiguration, IPropertyStorageOverride, + IEventProperty, IExtendedTelemetryItem, IEventTiming, + FieldValueSanitizerFunc, FieldValueSanitizerTypes, + IFieldSanitizerDetails, IFieldValueSanitizerProvider, IValueSanitizer +} from "./interfaces/ext/DataModels"; + +// 1DS Classes +export { AppInsightsExtCore } from "./ext/AppInsightsExtCore"; +export { ValueSanitizer } from "./ext/ValueSanitizer"; + +// 1DS Utils +export { + isValueAssigned, isLatency, isUint8ArrayAvailable, getTenantId, sanitizeProperty, + Version, FullVersionString, getCommonSchemaMetaData, getCookieValue, + extend, createGuid, isDocumentObjectAvailable, isWindowObjectAvailable, + setProcessTelemetryTimings, getTime, + isArrayValid, isValueKind, getFieldValueType, + isChromium, isGreaterThanZero +} from "./ext/extUtils"; + +// 1DS Span Utils +export { createExtendedTelemetryItemFromSpan } from "./ext/extSpanUtils"; diff --git a/shared/otel-core/src/interfaces/ai/ISenderPostManager.ts b/shared/otel-core/src/interfaces/ai/ISenderPostManager.ts index 38d4135c6..5c2776b94 100644 --- a/shared/otel-core/src/interfaces/ai/ISenderPostManager.ts +++ b/shared/otel-core/src/interfaces/ai/ISenderPostManager.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { ITimerHandler } from "@nevware21/ts-utils"; -import { TransportType } from "../../enums/ai/SendRequestReason"; +import { TransportType } from "../../enums/ext/Enums"; import { IXDomainRequest } from "./IXDomainRequest"; import { IPayloadData, IXHROverride, OnCompleteCallback } from "./IXHROverride"; diff --git a/shared/otel-core/src/interfaces/ext/DataModels.ts b/shared/otel-core/src/interfaces/ext/DataModels.ts new file mode 100644 index 000000000..86e262d48 --- /dev/null +++ b/shared/otel-core/src/interfaces/ext/DataModels.ts @@ -0,0 +1,286 @@ +/** +* DataModels.ts +* @author Abhilash Panwar (abpanwar) Hector Hernandez (hectorh) +* @copyright Microsoft 2018 +* File containing the interfaces for Web JS SDK. +*/ +import { EventPersistenceValue } from "../../enums/ai/Enums"; +import { EventLatencyValue, EventSendType, FieldValueSanitizerType } from "../../enums/ext/Enums"; +import { IConfiguration } from "../ai/IConfiguration"; +import { ITelemetryItem } from "../ai/ITelemetryItem"; + +/** + * An interface used to create an event property value along with tagging it as PII, or customer content. + * Caution: Customer content and PII are mutually exclusive. You can use only one of them at a time. + * If you use both, then the property will be considered invalid, and therefore won't be sent. + */ +export interface IEventProperty { + /** + * The value for the property. + */ + value: string | number | boolean | string[] | number[] | boolean[]; + + /** + * [Optional] The value kind associated with property value. The constant enum ValueKind should be used to specify the + * different kinds. + */ + kind?: number /*| ValueKind*/; + + /** + * [Optional] The data type for the property. Valid values accepted by onecollector are + * "string", "bool", "double", "int64", "datetime", "guid". + * The EventPropertyType constant enum should be used to specify the different property type values. + */ + propertyType?: number /*| EventPropertyType*/; +} + +/** + * An interface used to create an event, along with its name, properties, type, timestamp, and priority. + */ +export interface IExtendedTelemetryItem extends ITelemetryItem { + /** + * Properties to be captured about the telemetry item. + * Custom properties (alternatively referred to as Part C properties for a Common Schema event) can be + * directly added under data. + */ + data?: { [key: string]: any; }; + + /** + * Telemetry properties pertaining to domain about which data is being captured. Example, duration, referrerUri for browser page. + * These are alternatively referred to as Part B properties for a Common Schema event. + */ + baseData?: { [key: string]: any; }; + + /** + * An EventLatency value, that specifies the latency for the event.The EventLatency constant should be + * used to specify the different latency values. + */ + latency?: number | EventLatencyValue; + + /** + * [Optional] An EventPersistence value, that specifies the persistence for the event. The EventPersistence constant + * should be used to specify the different persistence values. + */ + persistence?: number | EventPersistenceValue; + + /** + * [Optional] A boolean that specifies whether the event should be sent as a sync request. + */ + sync?: boolean | EventSendType; + /** + * [Optional] A timings object. + */ + timings?: IEventTiming; +} + +/** + * The IExtendedConfiguration interface holds the configuration details passed to core during initialize. + */ +export interface IExtendedConfiguration extends IConfiguration { + /** + * [Optional] The property storage override that should be used to store + * internal SDK properties, otherwise stored as cookies. It is needed where cookies are not available. + */ + propertyStorageOverride?: IPropertyStorageOverride; + + /** + * [Optional] A boolean that indicated whether to disable the use of cookies by the 1DS Web SDK. The cookies added by the SDK are + * MicrosoftApplicationsTelemetryDeviceId. If cookies are disabled, then session events are not sent unless propertyStorageOverride + * is provided to store the values elsewhere. + */ + disableCookiesUsage?: boolean; + + /** + * [Optional] Name of the Anon cookie. The value will be set in the qsp header to collector requests. Collector will use this value to look for specific cookie to use for anid property. + */ + anonCookieName?: string; + + /** + * [Optional] Disables additional internal event timings that are added during processing of events, the timings are not sent as part telemetry items to the server + */ + disableEventTimings?: boolean; + + /** + * [Optional] Enables support for objects with compound keys which indirectly represent an object where the "key" of the object contains a "." as part of it's name. + * @example + * ```typescript + * event: { "somedata.embeddedvalue": 123 } + * ``` + */ + enableCompoundKey?: boolean; + + /** + * Add "&w=0" parameter to support UA Parsing when web-workers don't have access to Document. + * Default is false + */ + enableWParam?: boolean; + + // End of Internal note: remove these after consuming the ApplicationInsights Core version that defines these on IConfiguration + } + +/** + * An interface used for telemetry event timings. + */ +export interface IEventTiming { + /** + * Time when 1DS Core calls track + */ + trackStart?: number; + /** + * Array of times when each plugin configured in 1DS calls processTelemetry method + */ + processTelemetryStart?: { [key: string]: number; }; + /** + * Array of times when a specific channel tried to send the telemetry to configured endpoint + */ + sendEventStart?: { [key: string]: number; }; + /** + * Array of times when a specific channel received a response from endpoint or request timed out + */ + sendEventCompleted?: { [key: string]: number; }; + /** + * Array of times when a specific channel started serialization of the telemetry event + */ + serializationStart?: { [key: string]: number; }; + /** + * Array of times when a specific channel completed serialization of the telemetry event + */ + serializationCompleted?: { [key: string]: number; }; +} + +/** + * The IPropertyStorageOverride interface provides a custom interface for storing internal SDK properties - otherwise they are + * stored as cookies. + * You need this interface when you intend to run auto collection for common properties, or when you log a session in + * a non browser environment. + */ +export interface IPropertyStorageOverride { + /** + * A function for passing key value pairs to be stored. + * @param key - The key for the key value pair. + * @param value - The value for the key value pair. + */ + setProperty: (key: string, value: string) => void; + /** + * A function that gets a value for a given key. + * @param key - The key for which the value must be fetched. + */ + getProperty: (key: string) => string; +} + +export type FieldValueSanitizerFunc = (details: IFieldSanitizerDetails) => IEventProperty | null; + +export type FieldValueSanitizerTypes = string | number | boolean | object | string[] | number[] | boolean[] | IEventProperty; + +/** + * This interface defines the object that is passed to any provided FieldValueSanitizerFunc, it provides not only the value to be sanitized but also + * some context about the value like it's location within the envelope (serialized object), the format is defined via the + * [Common Schema 4.0](https://aka.ms/CommonSchema) specification. + */ +export interface IFieldSanitizerDetails { + + /** + * The path within the event where the value is stored + */ + path: string; + + /** + * The name of the field with the event path that will store the value + */ + name: string; + + /** + * Identifies the type of the property value + */ + type: FieldValueSanitizerType; + + /** + * The value for the property. + */ + prop: IEventProperty; + + /** + * A reference to the value sanitizer that created the details + */ + sanitizer: IValueSanitizer; +} + +/** + * This interface is used during the serialization of individual fields when converting the events into envelope (serialized object) which is sent to the services, + * the format is defined via the [Common Schema 4.0](https://aka.ms/CommonSchema) specification. The path and field names used are based + * on how the data is serialized to the service (CS 4.0 location) and not specifically the location on the event object you pass into the track methods (unless they are the same). + */ +export interface IFieldValueSanitizerProvider { + /** + * Does this field value sanitizer handle this path / field combination + * @param path - The field path + * @param name - The name of the field + */ + handleField(path: string, name: string): boolean; + + /** + * Get the field sanitizer for this type of field based on the field type, value kind and/or event property type + * @param path - The field path + * @param name - The name of the field + * @param theType - The type of field + * @param theKind - The value kind of the field + * @param propType - The property type of the field + */ + getSanitizer(path: string, name: string, theType: FieldValueSanitizerType, theKind?: number/* ValueKind*/, propType?: number/*EventPropertyType*/): FieldValueSanitizerFunc | null | undefined; +} + +/** + * This interface is used during the serialization of events into envelope (serialized object) which is sent to the services, the format is defined via the + * [Common Schema 4.0](https://aka.ms/CommonSchema) specification. The path and field names used are based on how the data is serialized + * to the service (CS 4.0 location) and not specifically the location on the event object you pass into the track methods (unless they are the same). + */ +export interface IValueSanitizer { + /** + * Add a value sanitizer as a fallback sanitizer if this sanitizer can't handle the path/name. + */ + addSanitizer: (sanitizer: IValueSanitizer) => void; + + /** + * Adds a field sanitizer to the evaluation list + */ + addFieldSanitizer: (fieldSanitizer: IFieldValueSanitizerProvider) => void; + + /** + * Removes the value sanitizer as a fallback sanitizer if this sanitizer can't handle the path/name if present. + */ + rmSanitizer: (theSanitizer: IValueSanitizer) => void; + + /** + * Removes the field sanitizer to the evaluation list if present + */ + rmFieldSanitizer: (theFieldSanitizer: IFieldValueSanitizerProvider) => void; + + /** + * Does this field value sanitizer handle this path / field combination + * @param path - The field path + * @param name - The name of the field + */ + handleField: (path: string, name: string) => boolean; + + /** + * Sanitizes the value. It checks the that the property name and value are valid. It also + * checks/populates the correct type and pii of the property value. + * @param path - The root path of the property + * @param name - The property name. + * @param value - The property value or an IEventProperty containing value, type ,pii and customer content. + * @param stringifyObjects - If supplied tells the sanitizer that it should JSON stringify() objects + * @returns IEventProperty containing valid name, value, pii and type or null if invalid. + */ + value: (path: string, name: string, value: FieldValueSanitizerTypes, stringifyObjects?: boolean) => IEventProperty | null; + + /** + * Sanitizes the Property. It checks the that the property name and value are valid. It also + * checks/populates the correct type and pii of the property value. + * @param path - The root path of the property + * @param name - The property name. + * @param property - The property value or an IEventProperty containing value, type ,pii and customer content. + * @param stringifyObjects - If supplied tells the sanitizer that it should JSON stringify() objects + * @returns IEventProperty containing valid name, value, pii and type or null if invalid. + */ + property: (path: string, name: string, property: IEventProperty, stringifyObjects?: boolean) => IEventProperty | null; +} diff --git a/shared/otel-core/src/utils/HelperFuncs.ts b/shared/otel-core/src/utils/HelperFuncs.ts index f28c6aa2c..f9fc1e769 100644 --- a/shared/otel-core/src/utils/HelperFuncs.ts +++ b/shared/otel-core/src/utils/HelperFuncs.ts @@ -8,7 +8,7 @@ import { } from "@nevware21/ts-utils"; import { STR_EMPTY } from "../constants/InternalConstants"; import { FeatureOptInMode } from "../enums/ai/FeatureOptInEnums"; -import { TransportType } from "../enums/ai/SendRequestReason"; +import { TransportType } from "../enums/ext/Enums"; import { IConfiguration } from "../interfaces/ai/IConfiguration"; import { IPlugin } from "../interfaces/ai/ITelemetryPlugin"; import { IXDomainRequest } from "../interfaces/ai/IXDomainRequest"; From 95a321ad55feaa97245dfe88f76e935494a4592d Mon Sep 17 00:00:00 2001 From: Nev <54870357+MSNev@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:48:56 -0800 Subject: [PATCH 2/2] [OTel-Sdk] Merge the 1ds-core-js changes from [Beta] for traceApi - Address dependency issues --- AISKU/Tests/Unit/src/CdnThrottle.tests.ts | 30 +- .../Unit/src/SnippetInitialization.Tests.ts | 5 +- .../Unit/src/ThrottleSentMessage.tests.ts | 14 +- .../Unit/src/applicationinsights.e2e.tests.ts | 2 +- AISKU/Tests/Unit/src/sanitizer.e2e.tests.ts | 2 +- AISKU/Tests/Unit/src/sender.e2e.tests.ts | 2 +- .../Tests/es6-module-type-check/package.json | 4 +- AISKU/package.json | 10 +- AISKU/src/ApplicationInsightsContainer.ts | 3 +- AISKULight/package.json | 9 +- .../package.json | 9 +- channels/tee-channel-js/package.json | 9 +- common/Tests/Framework/package.json | 7 +- common/config/rush/command-line.json | 10 + common/config/rush/npm-shrinkwrap.json | 1109 +++++++++-------- common/scripts/install-run-rush.js | 26 +- common/scripts/install-run-rushx.js | 6 +- common/scripts/install-run.js | 84 +- examples/AISKU/package.json | 2 +- examples/cfgSync/package.json | 6 +- examples/dependency/package.json | 2 +- examples/shared-worker/package.json | 6 +- .../package.json | 9 +- .../package.json | 8 +- .../package.json | 9 +- .../package.json | 5 +- .../package.json | 9 +- .../package.json | 9 +- gruntfile.js | 25 +- package.json | 46 +- .../AppInsights/Core/CorePerfCheck.Tests.ts | 14 +- .../src/ai/ApplicationInsightsCore.Tests.ts | 4 +- .../Unit/src/ext/ESPromiseSchedulerTests.ts | 8 +- shared/otel-core/package.json | 9 +- .../otel-core/src/ext/AppInsightsExtCore.ts | 6 +- shared/otel-core/src/ext/ValueSanitizer.ts | 24 +- shared/otel-core/src/ext/extSpanUtils.ts | 2 +- shared/otel-core/src/ext/extUtils.ts | 7 +- .../src/interfaces/ext/DataModels.ts | 2 +- .../src/telemetry/TelemetryItemCreator.ts | 2 +- shared/otel-noop/package.json | 9 +- .../package.json | 4 +- tools/chrome-debug-extension/package.json | 6 +- tools/config/package.json | 3 +- tools/release-tools/package.json | 3 +- tools/rollup-es5/package.json | 7 +- tools/rollup-plugin-uglify3-js/package.json | 7 +- tools/shims/package.json | 9 +- 48 files changed, 831 insertions(+), 772 deletions(-) diff --git a/AISKU/Tests/Unit/src/CdnThrottle.tests.ts b/AISKU/Tests/Unit/src/CdnThrottle.tests.ts index bb2bd4a52..12e1e90b1 100644 --- a/AISKU/Tests/Unit/src/CdnThrottle.tests.ts +++ b/AISKU/Tests/Unit/src/CdnThrottle.tests.ts @@ -1,17 +1,9 @@ import { AppInsightsSku } from "../../../src/AISku"; -import { ApplicationInsightsContainer } from "../../../src/ApplicationInsightsContainer"; -import { IApplicationInsights } from "../../../src/IApplicationInsights"; -import { Snippet } from "../../../src/Snippet"; import { AITestClass, Assert, IFetchArgs, PollingAssert } from "@microsoft/ai-test-framework"; -import { IConfig, IConfiguration, LoggingSeverity, _eInternalMessageId, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig } from "@microsoft/otel-core-js"; -import { SinonSpy } from "sinon"; -import { createSnippetV5 } from "./testSnippetV5"; -import { CdnFeatureMode, FeatureOptInMode, getGlobal, getGlobalInst, isFunction, newId } from "@microsoft/otel-core-js"; -import { createSnippetV6 } from "./testSnippetV6"; +import { IConfig, IConfiguration, _eInternalMessageId, IThrottleMgrConfig } from "@microsoft/otel-core-js"; +import { CdnFeatureMode, FeatureOptInMode, getGlobal, getGlobalInst } from "@microsoft/otel-core-js"; import { CfgSyncPlugin, ICfgSyncConfig, ICfgSyncMode } from "@microsoft/applicationinsights-cfgsync-js"; -import { createSyncPromise, doAwait } from "@nevware21/ts-async"; -import { ICfgSyncCdnConfig } from "@microsoft/applicationinsights-cfgsync-js/src/Interfaces/ICfgSyncCdnConfig"; -const ApplicationInsights = AppInsightsSku; +import { createSyncPromise } from "@nevware21/ts-async"; const TestInstrumentationKey = 'b7170927-2d1c-44f1-acec-59f4e1751c11'; @@ -87,11 +79,11 @@ const sampleConfig = { export class CdnThrottle extends AITestClass { private _ai: AppInsightsSku; - private getAi: ApplicationInsights; + private getAi: AppInsightsSku; private _config: IConfiguration | IConfig; private identifier: string; private fetchStub: any; - init: ApplicationInsights; + init: AppInsightsSku; private res: any; private _fetch: any; loggingSpy: any; @@ -185,7 +177,7 @@ export class CdnThrottle extends AITestClass { }, 0); }); this.fetchStub = this.sandbox.spy((doc as any), "fetch"); - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: { instrumentationKey: TestInstrumentationKey, featureOptIn : {["iKeyUsage"]: {mode: FeatureOptInMode.disable}}, @@ -240,7 +232,7 @@ export class CdnThrottle extends AITestClass { }); this.fetchStub = this.sandbox.spy((doc as any), "fetch"); - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: this._config, }); this.init.loadAppInsights(); @@ -283,7 +275,7 @@ export class CdnThrottle extends AITestClass { }; this.fetchStub = this.sandbox.spy((doc as any), "fetch"); - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: noSetconfig, }); this.init.loadAppInsights(); @@ -341,7 +333,7 @@ export class CdnThrottle extends AITestClass { }} }; - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: config, }); this.init.loadAppInsights(); @@ -382,7 +374,7 @@ export class CdnThrottle extends AITestClass { }, 0); }); this.fetchStub = this.sandbox.spy((doc as any), "fetch"); - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: { instrumentationKey: TestInstrumentationKey, extensionConfig : {["AppInsightsCfgSyncPlugin"] : { @@ -426,7 +418,7 @@ export class CdnThrottle extends AITestClass { }, 0); }); this.fetchStub = this.sandbox.spy((doc as any), "fetch"); - this.init = new ApplicationInsights({ + this.init = new AppInsightsSku({ config: { instrumentationKey: TestInstrumentationKey, extensionConfig : {["AppInsightsCfgSyncPlugin"] : { diff --git a/AISKU/Tests/Unit/src/SnippetInitialization.Tests.ts b/AISKU/Tests/Unit/src/SnippetInitialization.Tests.ts index 6882dc120..6db447cb6 100644 --- a/AISKU/Tests/Unit/src/SnippetInitialization.Tests.ts +++ b/AISKU/Tests/Unit/src/SnippetInitialization.Tests.ts @@ -11,7 +11,6 @@ import { BreezeChannelIdentifier, ContextTagKeys, DistributedTracingModes, IConfig, IDependencyTelemetry, RequestHeaders, utlRemoveSessionStorage, utlSetSessionStorage } from "@microsoft/otel-core-js"; -import { getGlobal } from "@microsoft/applicationinsights-shims"; import { IPropTelemetryContext } from "@microsoft/applicationinsights-properties-js"; import { dumpObj, isPromiseLike, objHasOwnProperty, strSubstring } from "@nevware21/ts-utils"; import { AppInsightsSku } from "../../../src/AISku"; @@ -1060,12 +1059,12 @@ export class SnippetInitializationTests extends AITestClass { }); } - private _initializeSnippet(snippet: Snippet): IApplicationInsights { + private _initializeSnippet(snippet: Snippet): AppInsightsSku { try { //this.useFakeServer = false; // Call the initialization - ((ApplicationInsightsContainer.getAppInsights(snippet, snippet.version)) as IApplicationInsights); + ((ApplicationInsightsContainer.getAppInsights(snippet, snippet.version)) as AppInsightsSku); // Setup Sinon stuff const appInsights: AppInsightsSku = (snippet as any).appInsights; diff --git a/AISKU/Tests/Unit/src/ThrottleSentMessage.tests.ts b/AISKU/Tests/Unit/src/ThrottleSentMessage.tests.ts index ed7795361..73bae8435 100644 --- a/AISKU/Tests/Unit/src/ThrottleSentMessage.tests.ts +++ b/AISKU/Tests/Unit/src/ThrottleSentMessage.tests.ts @@ -3,12 +3,10 @@ import { ApplicationInsightsContainer } from "../../../src/ApplicationInsightsCo import { IApplicationInsights } from "../../../src/IApplicationInsights"; import { Snippet } from "../../../src/Snippet"; import { AITestClass, Assert } from "@microsoft/ai-test-framework"; -import { IConfig, IConfiguration, LoggingSeverity, _eInternalMessageId, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig } from "@microsoft/otel-core-js"; -import { SinonSpy } from "sinon"; +import { IConfig, IConfiguration, _eInternalMessageId, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig } from "@microsoft/otel-core-js"; import { createSnippetV5 } from "./testSnippetV5"; import { FeatureOptInMode, newId } from "@microsoft/otel-core-js"; import { createSnippetV6 } from "./testSnippetV6"; -const ApplicationInsights = AppInsightsSku; const TestInstrumentationKey = 'b7170927-2d1c-44f1-acec-59f4e1751c11'; @@ -27,7 +25,7 @@ const tconfig = { export class ThrottleSentMessage extends AITestClass { private _ai: IApplicationInsights; - private getAi: ApplicationInsights; + private getAi: AppInsightsSku; private _config: IConfiguration | IConfig; private _logger; @@ -65,7 +63,7 @@ export class ThrottleSentMessage extends AITestClass { this.useFakeServer = false; this._config = this._getTestConfig(); - const init = new ApplicationInsights({ + const init = new AppInsightsSku({ config: this._config }); @@ -197,7 +195,7 @@ export class ThrottleSentMessage extends AITestClass { let config = this._getTestConfig(); config.throttleMgrCfg= {[_eInternalMessageId.InstrumentationKeyDeprecation]:tconfig, [_eInternalMessageId.DefaultThrottleMsgKey]:tconfig}; config.featureOptIn = {["iKeyUsage"]: {mode: FeatureOptInMode.disable}} - let init = new ApplicationInsights({ + let init = new AppInsightsSku({ config: config }); @@ -257,12 +255,12 @@ export class ThrottleSentMessage extends AITestClass { } - private _initializeSnippet(snippet: Snippet): ApplicationInsights { + private _initializeSnippet(snippet: Snippet): AppInsightsSku { try { //this.useFakeServer = false; // Call the initialization - ((ApplicationInsightsContainer.getAppInsights(snippet, snippet.version)) as IApplicationInsights); + ((ApplicationInsightsContainer.getAppInsights(snippet, snippet.version)) as AppInsightsSku); // Setup Sinon stuff const appInsights: AppInsightsSku = (snippet as any).appInsights; diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index fcf55e00f..1313e7a86 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -51,7 +51,7 @@ export class ApplicationInsightsTests extends AITestClass { // Context private tagKeys = new ContextTagKeys(); - private _config; + private _config: IConfiguration; private _appId: string; private _ctx: any; diff --git a/AISKU/Tests/Unit/src/sanitizer.e2e.tests.ts b/AISKU/Tests/Unit/src/sanitizer.e2e.tests.ts index be829cf5d..248fe5a9f 100644 --- a/AISKU/Tests/Unit/src/sanitizer.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/sanitizer.e2e.tests.ts @@ -1,4 +1,4 @@ -import { AppInsightsSku as ApplicationInsights } from "../../../src/AISku"; +import { AppInsightsSku, AppInsightsSku as ApplicationInsights } from "../../../src/AISku"; import { IApplicationInsights } from "../../../src/IApplicationInsights"; import { Sender } from "@microsoft/applicationinsights-channel-js"; import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; diff --git a/AISKU/Tests/Unit/src/sender.e2e.tests.ts b/AISKU/Tests/Unit/src/sender.e2e.tests.ts index 14188ff70..969215ef1 100644 --- a/AISKU/Tests/Unit/src/sender.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/sender.e2e.tests.ts @@ -1,4 +1,4 @@ -import { AppInsightsSku as ApplicationInsights } from "../../../src/AISku"; +import { AppInsightsSku, AppInsightsSku as ApplicationInsights } from "../../../src/AISku"; import { IApplicationInsights } from "../../../src/IApplicationInsights"; import { Sender } from "@microsoft/applicationinsights-channel-js"; import { BreezeChannelIdentifier, utlGetSessionStorage, utlRemoveSessionStorage } from "@microsoft/otel-core-js"; diff --git a/AISKU/Tests/es6-module-type-check/package.json b/AISKU/Tests/es6-module-type-check/package.json index f04f68c76..73008d34b 100644 --- a/AISKU/Tests/es6-module-type-check/package.json +++ b/AISKU/Tests/es6-module-type-check/package.json @@ -10,7 +10,9 @@ "module": "dist-es5/applicationinsights-test-module-type-check.js", "types": "types/applicationinsights-test-module-type-check.d.ts", "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "clean-modules": "node -e \"['node_modules'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "npm run clean-modules && npm run clean && git clean -xdf", "build": "tsc --project tsconfig.json --noEmit", "rebuild": "npm run build", "test": "", diff --git a/AISKU/package.json b/AISKU/package.json index 22c0c32d1..672ecf2cc 100644 --- a/AISKU/package.json +++ b/AISKU/package.json @@ -13,7 +13,9 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS" }, "scripts": { - "clean": "rimraf dist dist-es5 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean-es6-tests": "cd Tests/es6-module-type-check && npm run full-clean && cd ../..", + "full-clean": "npm run full-clean-es6-tests && git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt aisku", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -42,8 +44,8 @@ "grunt-cli": "^1.4.3", "@nevware21/ts-async": ">= 0.5.5 < 2.x", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -73,7 +75,7 @@ "@microsoft/otel-core-js": "0.0.1-alpha", "@microsoft/applicationinsights-dependencies-js": "3.3.11", "@microsoft/applicationinsights-properties-js": "3.3.11", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/AISKU/src/ApplicationInsightsContainer.ts b/AISKU/src/ApplicationInsightsContainer.ts index 40b342c3a..66dd601ff 100644 --- a/AISKU/src/ApplicationInsightsContainer.ts +++ b/AISKU/src/ApplicationInsightsContainer.ts @@ -1,11 +1,10 @@ import { throwUnsupported } from "@nevware21/ts-utils"; import { AppInsightsSku } from "./AISku"; -import { IApplicationInsights } from "./IApplicationInsights"; import { Snippet } from "./Snippet"; export class ApplicationInsightsContainer { - public static getAppInsights(snippet: Snippet, version: number) : IApplicationInsights { + public static getAppInsights(snippet: Snippet, version: number) : AppInsightsSku { const theSku = new AppInsightsSku(snippet); // Two target scenarios: diff --git a/AISKULight/package.json b/AISKULight/package.json index cd82cd0f6..119336d95 100644 --- a/AISKULight/package.json +++ b/AISKULight/package.json @@ -9,7 +9,8 @@ "types": "types/applicationinsights-web-basic.d.ts", "sideEffects": false, "scripts": { - "clean": "rimraf dist dist-es5 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt aiskulite", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -37,8 +38,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -62,7 +63,7 @@ "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/applicationinsights-channel-js": "3.3.11", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/channels/applicationinsights-channel-js/package.json b/channels/applicationinsights-channel-js/package.json index f1764b385..d7649d0e1 100644 --- a/channels/applicationinsights-channel-js/package.json +++ b/channels/applicationinsights-channel-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/channels/applicationinsights-channel-js" }, "scripts": { - "clean": "rimraf dist dist-es5 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt aichannel", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -36,8 +37,8 @@ "@types/sinon": "4.3.3", "grunt": "^1.5.3", "grunt-cli": "^1.4.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "@rollup/plugin-commonjs": "^24.0.0", @@ -58,7 +59,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/channels/tee-channel-js/package.json b/channels/tee-channel-js/package.json index 32f9c1e95..2429223b4 100644 --- a/channels/tee-channel-js/package.json +++ b/channels/tee-channel-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/channels/tee-channel-js" }, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt teechannel", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -37,8 +38,8 @@ "@types/sinon": "4.3.3", "grunt": "^1.5.3", "grunt-cli": "^1.4.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "@rollup/plugin-commonjs": "^24.0.0", @@ -59,7 +60,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/common/Tests/Framework/package.json b/common/Tests/Framework/package.json index 429bd18ed..c69089f0d 100644 --- a/common/Tests/Framework/package.json +++ b/common/Tests/Framework/package.json @@ -16,7 +16,8 @@ "module": "dist-es5/ai-test-framework.js", "types": "types/ai-test-framework.d.ts", "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser", "build:esm": "grunt tst-framework", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -34,7 +35,7 @@ "@types/sinon": "4.3.3", "grunt": "^1.5.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -54,7 +55,7 @@ }, "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" } } diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json index 34828c72c..a0317385e 100644 --- a/common/config/rush/command-line.json +++ b/common/config/rush/command-line.json @@ -94,6 +94,16 @@ "ignoreMissingScript": true, "allowWarningsInSuccessfulBuild": true }, + { + "commandKind": "bulk", + "name": "full-clean", + "summary": "Run all full clean tasks to clean each project", + "description": "Run all full clean tasks to clean each project", + "safeForSimultaneousRushProcesses": true, + "enableParallelism": true, + "ignoreMissingScript": true, + "allowWarningsInSuccessfulBuild": true + }, { "commandKind": "bulk", "name": "api-docs", diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 09df7ac87..109632c28 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -11,10 +11,10 @@ "@microsoft/api-extractor": "^7.40.0", "@microsoft/applicationinsights-offlinechannel-js": "0.3.11", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -183,83 +183,33 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "peer": true, - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "peer": true, - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", + "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -272,6 +222,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "peer": true + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -288,9 +254,9 @@ "peer": true }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -300,59 +266,55 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "peer": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "peer": true, "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=10.10.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "node_modules/@humanwhocodes/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "peer": true + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "peer": true, - "engines": { - "node": ">=18.18.0" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "peer": true, "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=18.18.0" + "node": "*" } }, "node_modules/@humanwhocodes/module-importer": { @@ -368,37 +330,12 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "peer": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz", - "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } + "node_modules/@humanwhocodes/object-schema": { + "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==", + "deprecated": "Use @eslint/object-schema instead", + "peer": true }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", @@ -406,20 +343,20 @@ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "node_modules/@microsoft/api-extractor": { - "version": "7.56.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.56.2.tgz", - "integrity": "sha512-d94f7S+H43jDxY/YIyp5UOE9N12HZmEPP5Ct96us+fw1FVKBoy4itTopdVM1VrcpduuA7fK/t31CgA2jM8AqSA==", + "version": "7.57.6", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.57.6.tgz", + "integrity": "sha512-0rFv/D8Grzw1Mjs2+8NGUR+o4h9LVm5zKRtMeWnpdB5IMJF4TeHCL1zR5LMCIudkOvyvjbhMG5Wjs0B5nqsrRQ==", "dependencies": { - "@microsoft/api-extractor-model": "7.32.2", + "@microsoft/api-extractor-model": "7.33.4", "@microsoft/tsdoc": "~0.16.0", - "@microsoft/tsdoc-config": "~0.18.0", - "@rushstack/node-core-library": "5.19.1", - "@rushstack/rig-package": "0.6.0", - "@rushstack/terminal": "0.21.0", - "@rushstack/ts-command-line": "5.2.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.20.3", + "@rushstack/rig-package": "0.7.2", + "@rushstack/terminal": "0.22.3", + "@rushstack/ts-command-line": "5.3.3", "diff": "~8.0.2", - "lodash": "~4.17.15", - "minimatch": "10.1.2", + "lodash": "~4.17.23", + "minimatch": "10.2.1", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", @@ -430,13 +367,13 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.32.2.tgz", - "integrity": "sha512-Ussc25rAalc+4JJs9HNQE7TuO9y6jpYQX9nWD1DhqUzYPBr3Lr7O9intf+ZY8kD5HnIqeIRJX7ccCT0QyBy2Ww==", + "version": "7.33.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.4.tgz", + "integrity": "sha512-u1LTaNTikZAQ9uK6KG1Ms7nvNedsnODnspq/gH2dcyETWvH4hVNGNDvRAEutH66kAmxA4/necElqGNs1FggC8w==", "dependencies": { "@microsoft/tsdoc": "~0.16.0", - "@microsoft/tsdoc-config": "~0.18.0", - "@rushstack/node-core-library": "5.19.1" + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.20.3" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { @@ -517,23 +454,23 @@ "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==" }, "node_modules/@microsoft/tsdoc-config": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.0.tgz", - "integrity": "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==", + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.1.tgz", + "integrity": "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==", "dependencies": { "@microsoft/tsdoc": "0.16.0", - "ajv": "~8.12.0", + "ajv": "~8.18.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "node_modules/@nevware21/grunt-eslint-ts": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@nevware21/grunt-eslint-ts/-/grunt-eslint-ts-0.5.1.tgz", - "integrity": "sha512-Ita/SqAURvKj0SlyyxZAXyUAscDieMUD1tf+O9pzc/2P3Q2NSXWHeCRw+cOdBYnTRKxW4miGCJwlVst8p93ULA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@nevware21/grunt-eslint-ts/-/grunt-eslint-ts-0.5.2.tgz", + "integrity": "sha512-k2gzszSryZ+oeM1lCSAgXHXeMvPtzyesHKKd1sH8etQMvmwQJq0lYi5VpjIABzgWAE1jO5/4ZPQq0XB2QieAag==", "dependencies": { - "@nevware21/ts-async": ">= 0.5.2 < 2.x", - "@nevware21/ts-utils": ">= 0.11.3 < 2.x", + "@nevware21/ts-async": ">= 0.5.5 < 2.x", + "@nevware21/ts-utils": ">= 0.12.6 < 2.x", "eslint-formatter-codeframe": "^7.32.1" }, "engines": { @@ -542,19 +479,19 @@ "peerDependencies": { "@typescript-eslint/eslint-plugin": "*", "@typescript-eslint/parser": "*", - "eslint": ">=7", + "eslint": "^7.0.0 || ^8.0.0", "eslint-plugin-security": "*", "grunt": ">=1", "typescript": ">=1" } }, "node_modules/@nevware21/grunt-ts-plugin": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@nevware21/grunt-ts-plugin/-/grunt-ts-plugin-0.5.1.tgz", - "integrity": "sha512-ezNls+4NTWOI4D4WLeEWeGOKAQdJ1PnEpj+DpGaP0FJAEk5aXhx4tRGIhXr8wE7bNuUDI3lctZjR+GONbAgekg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@nevware21/grunt-ts-plugin/-/grunt-ts-plugin-0.5.2.tgz", + "integrity": "sha512-lW0vWYDYV+ZlMf+2+edD/VdSjH/Gfy2+nuxbTCeNxySkC1FPrWFDh3Iefe8BplIdoySoZxVyqhsCaME+SoCO4Q==", "dependencies": { - "@nevware21/ts-async": ">= 0.5.2 < 2.x", - "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + "@nevware21/ts-async": ">= 0.5.5 < 2.x", + "@nevware21/ts-utils": ">= 0.12.6 < 2.x" }, "engines": { "node": ">= 0.8.0" @@ -573,9 +510,9 @@ } }, "node_modules/@nevware21/ts-utils": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.12.6.tgz", - "integrity": "sha512-UsS1hbgr/V/x8dT7hVHvr/PwHzASi8/Itis1+L8ykLiqsUXdfzrB1maL0vMmKbDEJpmGARsoC/7RIswi+n248Q==" + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.13.0.tgz", + "integrity": "sha512-F3mD+DsUn9OiZmZc5tg0oKqrJCtiCstwx+wE+DNzFYh2cCRUuzTYdK9zGGP/au2BWvbOQ6Tqlbjr2+dT1P3AlQ==" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -775,12 +712,12 @@ "node_modules/@rush-temp/ai-test-framework": { "version": "0.0.0", "resolved": "file:projects/ai-test-framework.tgz", - "integrity": "sha512-gV0fnBBxoCSVWqwoPnu7CfCh2oDENBSIH1P9SbTAG9d+vnQHfyRyzBzv9yEV65cTk8YLFhFYWPxYuCAjok7vXQ==", + "integrity": "sha512-VgoMDyogzcGs5XR0K7Fi/C653d983T8V7tzvg/KOgrDSa6Ks3iNLZ2TFTpEY1IWknSPoRu2diyab/UzcQVVkgA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -803,13 +740,13 @@ "node_modules/@rush-temp/applicationinsights-analytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-analytics-js.tgz", - "integrity": "sha512-DiYorNJcMR8s8RG4s+DX2NCF0wqnHqBihKQnubknb/FLc5T8B55/u36gVfJlB5K5oiAgP6aOa8QIy0qw0rp5mg==", + "integrity": "sha512-EKVRYDcLFb9dGu5BR8Utgkh2Qk9lZ5Y7xRKZq/B5gW9q1FMCTPGwv9wZ2Swtx0RI+E6IOc1hsC0U6+YQvT+FWw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -833,14 +770,14 @@ "node_modules/@rush-temp/applicationinsights-cfgsync-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-cfgsync-js.tgz", - "integrity": "sha512-Inw2c6TEKENTTis04Hyq90DmuJTjUaY+CnBbeM+FXo7ODaRXnMxYTUBlK1nZ8JxQ8ONQTWtrMCGzwX/aNcW+mg==", + "integrity": "sha512-URhFXMqy96W1UXj2AE7kq72vP8HRk9TaZHqNQIxwUIXfqBx0rZ7Rw2xzSGDKBzKJBlU+ve10sidY+4vN8FoMiA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -864,14 +801,14 @@ "node_modules/@rush-temp/applicationinsights-channel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-channel-js.tgz", - "integrity": "sha512-j2k8rZQcGqxFo6IqPOZDtgzC63P/zH3AfnOt0nJ1tAlqCWk1zDWyOBF4Aq4Ig+ps5dZ5Ocvfi/p35r5HUA9vCA==", + "integrity": "sha512-OyWs8IIRQkADwzJxg4aQDd/59pLyB5gMclxnoPugXm8YgmUbZzR0bn007SsI7zl56C13zaf1A1MTpgKjajpKGw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -892,14 +829,14 @@ "node_modules/@rush-temp/applicationinsights-dependencies-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-dependencies-js.tgz", - "integrity": "sha512-rb8Fwpy0sEa+JyZa9X6JxP5nBmQRh91wSJ86VbV96eY5SQkuWLHK7NGg0tEdGezkMrpa6AOFmEO1crzURjK8PQ==", + "integrity": "sha512-xC5gEesFTd+w3IiCcZyIdadIvCzyij02pjTwERJDXfs/582q7QyrMT9nDlLQKyUZUTN4rwOtCPi9uuAUSRtpxw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -931,12 +868,12 @@ "node_modules/@rush-temp/applicationinsights-osplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-osplugin-js.tgz", - "integrity": "sha512-MfkaNUfM2TrtMN21TMsoSs6po6QeCPFaIdELW6O+p4tBAc2B8uPhRTO5HyV2SVoPG4al6XZmbHMwpVl1yNJZOw==", + "integrity": "sha512-JVfZY+IPVF9uV8B0WcNu7LA+J3oz3B0RepblHTRuJhPBL35MBGAMA9QntIWBtBlb5BUn5prCIkBzZNbjHk1PgQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -954,13 +891,13 @@ "node_modules/@rush-temp/applicationinsights-perfmarkmeasure-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-perfmarkmeasure-js.tgz", - "integrity": "sha512-U4JcdJY5P4PbCbvE2vQlnXWKTg/Mij62+uezZO+Rmgv0ORJQa6g71hwnbKUgLBx0c310yZL47uyP6pMSPKjjSw==", + "integrity": "sha512-Cpa1t7sU6n43KKKIqAbc/aCSwweGsmUqVwcq3KNGv0AXGFeNh4g51aVOUXav7RDIHo3Khiw1MbBOdMtdZeUKzA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -980,13 +917,13 @@ "node_modules/@rush-temp/applicationinsights-properties-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-properties-js.tgz", - "integrity": "sha512-nAKIm5irjY5mm4S3LJ2k/5gX5VoG0Q6yAQmzCMMfg7Q3C78LSBEtivw1/mo5lI53vhMkFvnJGatZ44yljnUNbA==", + "integrity": "sha512-34Tem8vxmPr/PjJAuPCY2BorGAM9xTbwAF7r21osQ1MrgpvIz7+xU9cNc9VSM6560B4iD02pnxHkQRvGa+QnzA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1010,11 +947,11 @@ "node_modules/@rush-temp/applicationinsights-rollup-es5": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-es5.tgz", - "integrity": "sha512-XLXXEaCIHUBvkDwE6Ao+pq7J5N6eHkU9pfE5P1DlzCCdObRyWu3+c6F8J8YAiQuymWxeTzCgXErZBylPdta0Gg==", + "integrity": "sha512-bbE0L/rNcHgRDQT7W4GMwHS71ItBcCGiSftX6bwEYuk7RokoWtxutqB8k7Mh8yjtuHuJ3tGCCX4Z+dvYAVlmqw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1035,10 +972,10 @@ "node_modules/@rush-temp/applicationinsights-rollup-plugin-uglify3-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-plugin-uglify3-js.tgz", - "integrity": "sha512-o3wUUg5MzKFiLRBgua5NQB6fdqGF59fZnYLuJmENr+vqSaql8s8zTydFwuzFzRw8kajDk1hmi3py+6H6Wq/EpA==", + "integrity": "sha512-AUYdwP4usT3Et/1pyQ9HEcZjn+rhp7Px9/RlNb4CtPcA+WVc6UqDVZ28BkSaN1/UNWx3LJ6cHrl5drP4fhubUQ==", "dependencies": { - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1057,20 +994,18 @@ "node_modules/@rush-temp/applicationinsights-shims": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-shims.tgz", - "integrity": "sha512-da6+hree5hR3Tf6GhsS00TL7d3IxYwVN306NXXG5LVl7Pd8Rgi+hE39SmHd2OyCbWWoxGDe2t4/4pugQbXkTlQ==", + "integrity": "sha512-eEtInmih5+VTFUfDpv9I3qd1Eq1iLFmA15ocw0GpUVLcEndmeaYnZBHZHf7AMmSdQIaURn/g6kJjgmLLDQqjFQ==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^12.1.2", "@types/qunit": "^2.19.3", "grunt": "^1.5.3", "grunt-cli": "^1.4.3", - "grunt-rollup": "^12.0.0", "rollup": "^3.20.0", "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-minify-es": "^1.1.1", @@ -1081,14 +1016,14 @@ "node_modules/@rush-temp/applicationinsights-teechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-teechannel-js.tgz", - "integrity": "sha512-aiOfZAdexDw3V4pxKOQNrR041LuPXc72RjrSWFVcIS2eLYN+MjSz8xjfZu3kbGJncj11ATABh5BQAVVbwiZMtA==", + "integrity": "sha512-WO38kPvbAoZzySvrJKZL3DlTCyj6AbBvXkJNbi1St6ywrx9fXWR/sTf5I1n3C+mDp46GaTB79yEnFNxWdqr9Qg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1118,15 +1053,15 @@ "node_modules/@rush-temp/applicationinsights-web": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web.tgz", - "integrity": "sha512-suv4QMx3b2zQpCKK2WmjmH+/5NktGRx4afF25qkeoOvjIywlp4G9eZcEzJD2t+ioS1I85ZaNooLR/bqhKEgisA==", + "integrity": "sha512-/P817h1m4RvjZQciFcSQKyin1PclYtzaw6f4m7Ggnw024h2FFvg3P+0CgV7hKjmDU2ZjlXT928wiAkrZhxXmQg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/applicationinsights-offlinechannel-js": "0.3.11", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1153,14 +1088,14 @@ "node_modules/@rush-temp/applicationinsights-web-basic": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-basic.tgz", - "integrity": "sha512-yJPY31+DTRRNjGE153o8U5xoqH+Cw6JUhlW6D55SgI+4VUaXQinsoPyoVMCXx/dgkl84V3WBGd8XRS9QM0QvDQ==", + "integrity": "sha512-JON5hjP92lU/hrcUmSK99DVLSL+gRjVtlZFb7kStH1zpcLol8yljc5qIaFqlW/5R/vN1Tymk5NSnD/RZ3H8ApA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1188,14 +1123,14 @@ "node_modules/@rush-temp/otel-core-js": { "version": "0.0.0", "resolved": "file:projects/otel-core-js.tgz", - "integrity": "sha512-4nsCt/Kb9wv5xX9wgCWxqBJA1Q3yD/ZhjWP18i+G55yGNwkvon/KT/+55X2NFTndFvON5yazznnT1J+CIQmd0Q==", + "integrity": "sha512-YhFvRNKks6T00fJ7QQcI/XlZdoxkIJcMGOPsNgqfhGYOhg9W05NPy8/h2jufypmf298Z8zpR0Uu8AtHn2RKHlA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1219,14 +1154,14 @@ "node_modules/@rush-temp/otel-noop-js": { "version": "0.0.0", "resolved": "file:projects/otel-noop-js.tgz", - "integrity": "sha512-l8/HnBK7kIhmIRPxJ69xfPe/8Pn2uTVmGHPINYeCUs0NuNxfDBdCgcsdXCwR452KWmRriW8DzrPI588yRnm4iw==", + "integrity": "sha512-P1zmUho41zBe5mitbiZrumAZxdNduDhKFKkNed+HUQppazEFLxfz1fevmkbVFQ06OL7/Hmz4I6YK1lM1s8WjNA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -1248,11 +1183,11 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "5.19.1", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.19.1.tgz", - "integrity": "sha512-ESpb2Tajlatgbmzzukg6zyAhH+sICqJR2CNXNhXcEbz6UGCQfrKCtkxOpJTftWc8RGouroHG0Nud1SJAszvpmA==", + "version": "5.20.3", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.20.3.tgz", + "integrity": "sha512-95JgEPq2k7tHxhF9/OJnnyHDXfC9cLhhta0An/6MlkDsX2A6dTzDrTUG18vx4vjc280V0fi0xDH9iQczpSuWsw==", "dependencies": { - "ajv": "~8.13.0", + "ajv": "~8.18.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", @@ -1270,25 +1205,10 @@ } } }, - "node_modules/@rushstack/node-core-library/node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@rushstack/problem-matcher": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.1.1.tgz", - "integrity": "sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", "peerDependencies": { "@types/node": "*" }, @@ -1299,21 +1219,21 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.6.0.tgz", - "integrity": "sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.2.tgz", + "integrity": "sha512-9XbFWuqMYcHUso4mnETfhGVUSaADBRj6HUAAEYk50nMPn8WRICmBuCphycQGNB3duIR6EEZX3Xj3SYc2XiP+9A==", "dependencies": { "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" } }, "node_modules/@rushstack/terminal": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.21.0.tgz", - "integrity": "sha512-cLaI4HwCNYmknM5ns4G+drqdEB6q3dCPV423+d3TZeBusYSSm09+nR7CnhzJMjJqeRcdMAaLnrA4M/3xDz4R3w==", + "version": "0.22.3", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.22.3.tgz", + "integrity": "sha512-gHC9pIMrUPzAbBiI4VZMU7Q+rsCzb8hJl36lFIulIzoceKotyKL3Rd76AZ2CryCTKEg+0bnTj406HE5YY5OQvw==", "dependencies": { - "@rushstack/node-core-library": "5.19.1", - "@rushstack/problem-matcher": "0.1.1", + "@rushstack/node-core-library": "5.20.3", + "@rushstack/problem-matcher": "0.2.1", "supports-color": "~8.1.1" }, "peerDependencies": { @@ -1326,11 +1246,11 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.2.0.tgz", - "integrity": "sha512-lYxCX0nDdkDtCkVpvF0m25ymf66SaMWuppbD6b7MdkIzvGXKBXNIVZlwBH/C0YfkanrupnICWf2n4z3AKSfaHw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.3.tgz", + "integrity": "sha512-c+ltdcvC7ym+10lhwR/vWiOhsrm/bP3By2VsFcs5qTKv+6tTmxgbVrtJ5NdNjANiV5TcmOZgUN+5KYQ4llsvEw==", "dependencies": { - "@rushstack/terminal": "0.21.0", + "@rushstack/terminal": "0.22.3", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -1428,7 +1348,8 @@ "node_modules/@sinonjs/text-encoding": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", - "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==" + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "deprecated": "Deprecated: no longer maintained and no longer used by Sinon packages. See\n https://github.com/sinonjs/nise/issues/243 for replacement details." }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", @@ -1453,12 +1374,6 @@ "@types/unist": "*" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "peer": true - }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -1468,12 +1383,12 @@ } }, "node_modules/@types/node": { - "version": "25.2.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.1.tgz", - "integrity": "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==", + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", "optional": true, "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/qunit": { @@ -1506,16 +1421,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", - "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/type-utils": "8.54.0", - "@typescript-eslint/utils": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -1528,21 +1443,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.54.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", - "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "engines": { @@ -1553,18 +1468,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "peer": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -1579,13 +1494,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1596,9 +1511,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1612,14 +1527,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", - "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -1631,14 +1546,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1649,17 +1564,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "peer": true, "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -1675,25 +1590,16 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "peer": true, "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1712,15 +1618,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1730,18 +1636,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1752,12 +1658,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "peer": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1774,9 +1680,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "peer": true, "bin": { "acorn": "bin/acorn" @@ -1803,14 +1709,14 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -1933,9 +1839,9 @@ } }, "node_modules/b4a": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", - "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "peerDependencies": { "react-native-b4a": "*" }, @@ -1946,9 +1852,12 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/bare-events": { "version": "2.8.2", @@ -1964,10 +1873,9 @@ } }, "node_modules/bare-fs": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.3.tgz", - "integrity": "sha512-9+kwVx8QYvt3hPWnmb19tPnh38c6Nihz8Lx3t0g9+4GoIf3/fTgYwM4Z6NxgI+B9elLQA7mLE9PpqcWtOMRDiQ==", - "optional": true, + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", + "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", @@ -1988,10 +1896,9 @@ } }, "node_modules/bare-os": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", - "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", - "optional": true, + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.7.1.tgz", + "integrity": "sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==", "engines": { "bare": ">=1.14.0" } @@ -2000,18 +1907,17 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", - "optional": true, "dependencies": { "bare-os": "^3.0.1" } }, "node_modules/bare-stream": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", - "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", - "optional": true, + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", + "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", "dependencies": { - "streamx": "^2.21.0" + "streamx": "^2.21.0", + "teex": "^1.0.1" }, "peerDependencies": { "bare-buffer": "*", @@ -2030,26 +1936,27 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", - "optional": true, "dependencies": { "bare-path": "^3.0.0" } }, "node_modules/basic-ftp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", - "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", "engines": { "node": ">=10.0.0" } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -2209,9 +2116,9 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -2383,6 +2290,18 @@ "node": ">=8" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2487,62 +2406,59 @@ } }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", + "cross-spawn": "^7.0.2", "debug": "^4.3.2", + "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-formatter-codeframe": { @@ -2561,9 +2477,9 @@ } }, "node_modules/eslint-plugin-security": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.1.tgz", - "integrity": "sha512-XjVGBhtDZJfyuhIxnQ/WMm385RbX3DBu7H1J7HNNhmB2tnGxMeqVSnYv79oAj992ayvIBZghsymwkYFS6cGH4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz", + "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==", "peer": true, "dependencies": { "safe-regex": "^2.1.1" @@ -2576,16 +2492,16 @@ } }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2604,9 +2520,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2619,16 +2535,20 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "peer": true + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/eslint/node_modules/ignore": { @@ -2647,9 +2567,9 @@ "peer": true }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2659,29 +2579,17 @@ } }, "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "peer": true, "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint-visitor-keys": "^3.4.1" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "peer": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -2856,6 +2764,21 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "peer": true }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -2890,15 +2813,15 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "peer": true, "dependencies": { - "flat-cache": "^4.0.0" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=16.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/fill-range": { @@ -2996,22 +2919,23 @@ } }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "peer": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.4" + "keyv": "^4.5.3", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=16" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.4.tgz", + "integrity": "sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==", "peer": true }, "node_modules/for-in": { @@ -3042,9 +2966,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -3059,19 +2983,6 @@ "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", @@ -3154,6 +3065,11 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -3163,9 +3079,9 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3213,12 +3129,15 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3266,6 +3185,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "peer": true + }, "node_modules/grunt": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz", @@ -3390,9 +3315,9 @@ } }, "node_modules/grunt-rollup/node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "version": "2.80.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", + "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", "bin": { "rollup": "dist/bin/rollup" }, @@ -3403,6 +3328,20 @@ "fsevents": "~2.3.2" } }, + "node_modules/grunt/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/grunt/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/grunt/node_modules/glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -3767,6 +3706,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4058,9 +4006,9 @@ } }, "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -4230,11 +4178,11 @@ } }, "node_modules/minimatch": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz", - "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.1.tgz", + "integrity": "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==", "dependencies": { - "@isaacs/brace-expansion": "^5.0.1" + "brace-expansion": "^5.0.2" }, "engines": { "node": "20 || >=22" @@ -4682,9 +4630,9 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -4694,6 +4642,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "peer": true, "engines": { "node": ">=6" } @@ -4892,10 +4841,75 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "peer": true + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/rollup": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", - "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "bin": { "rollup": "dist/bin/rollup" }, @@ -5402,23 +5416,38 @@ } }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "dependencies": { "b4a": "^1.6.4" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "peer": true + }, "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", @@ -5509,10 +5538,22 @@ "node": ">=4" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-query-selector": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", - "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==" + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", + "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==" }, "node_modules/typedoc": { "version": "0.26.11", @@ -5535,6 +5576,11 @@ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x" } }, + "node_modules/typedoc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -5544,11 +5590,11 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5632,9 +5678,9 @@ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "optional": true }, "node_modules/unist-util-is": { @@ -5720,6 +5766,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "peer": true, "dependencies": { "punycode": "^2.1.0" } diff --git a/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js index ab7defd16..4733f4d8c 100644 --- a/common/scripts/install-run-rush.js +++ b/common/scripts/install-run-rush.js @@ -16,16 +16,6 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ 176760 -/*!****************************!*\ - !*** external "node:path" ***! - \****************************/ -(module) { - -module.exports = require("node:path"); - -/***/ }, - /***/ 973024 /*!**************************!*\ !*** external "node:fs" ***! @@ -34,6 +24,16 @@ module.exports = require("node:path"); module.exports = require("node:fs"); +/***/ }, + +/***/ 176760 +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +(module) { + +module.exports = require("node:path"); + /***/ } /******/ }); @@ -113,9 +113,9 @@ module.exports = require("node:fs"); var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk. (() => { -/*!************************************************!*\ - !*** ./lib-esnext/scripts/install-run-rush.js ***! - \************************************************/ +/*!**********************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run-rush.js ***! + \**********************************************************/ __webpack_require__.r(__webpack_exports__); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! node:path */ 176760); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_0__); diff --git a/common/scripts/install-run-rushx.js b/common/scripts/install-run-rushx.js index 6581521f3..67d51a05b 100644 --- a/common/scripts/install-run-rushx.js +++ b/common/scripts/install-run-rushx.js @@ -17,9 +17,9 @@ /******/ (() => { // webpackBootstrap /******/ "use strict"; var __webpack_exports__ = {}; -/*!*************************************************!*\ - !*** ./lib-esnext/scripts/install-run-rushx.js ***! - \*************************************************/ +/*!***********************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run-rushx.js ***! + \***********************************************************/ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index 9274e7038..b25266e4f 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -16,10 +16,10 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ 90178 -/*!****************************************************!*\ - !*** ./lib-esnext/utilities/executionUtilities.js ***! - \****************************************************/ +/***/ 953844 +/*!**************************************************************!*\ + !*** ./lib-intermediate-esm/utilities/executionUtilities.js ***! + \**************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); @@ -49,30 +49,10 @@ function escapeArgumentIfNeeded(command, isWindows = IS_WINDOWS) { /***/ }, -/***/ 176760 -/*!****************************!*\ - !*** external "node:path" ***! - \****************************/ -(module) { - -module.exports = require("node:path"); - -/***/ }, - -/***/ 731421 -/*!*************************************!*\ - !*** external "node:child_process" ***! - \*************************************/ -(module) { - -module.exports = require("node:child_process"); - -/***/ }, - -/***/ 832286 -/*!************************************************!*\ - !*** ./lib-esnext/utilities/npmrcUtilities.js ***! - \************************************************/ +/***/ 359480 +/*!**********************************************************!*\ + !*** ./lib-intermediate-esm/utilities/npmrcUtilities.js ***! + \**********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); @@ -97,14 +77,8 @@ __webpack_require__.r(__webpack_exports__); * @returns * The text of the the .npmrc. */ -// create a global _combinedNpmrc for cache purpose -const _combinedNpmrcMap = new Map(); function _trimNpmrcFile(options) { const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties, env = process.env } = options; - const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); - if (combinedNpmrcFromCache !== undefined) { - return combinedNpmrcFromCache; - } let npmrcFileLines = []; if (linesToPrepend) { npmrcFileLines.push(...linesToPrepend); @@ -118,8 +92,6 @@ function _trimNpmrcFile(options) { npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); const resultLines = trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties); const combinedNpmrc = resultLines.join('\n'); - //save the cache - _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); return combinedNpmrc; } /** @@ -337,13 +309,13 @@ function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarF /***/ }, -/***/ 848161 -/*!**************************!*\ - !*** external "node:os" ***! - \**************************/ +/***/ 731421 +/*!*************************************!*\ + !*** external "node:child_process" ***! + \*************************************/ (module) { -module.exports = require("node:os"); +module.exports = require("node:child_process"); /***/ }, @@ -355,6 +327,26 @@ module.exports = require("node:os"); module.exports = require("node:fs"); +/***/ }, + +/***/ 848161 +/*!**************************!*\ + !*** external "node:os" ***! + \**************************/ +(module) { + +module.exports = require("node:os"); + +/***/ }, + +/***/ 176760 +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +(module) { + +module.exports = require("node:path"); + /***/ } /******/ }); @@ -434,9 +426,9 @@ module.exports = require("node:fs"); var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk. (() => { -/*!*******************************************!*\ - !*** ./lib-esnext/scripts/install-run.js ***! - \*******************************************/ +/*!*****************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run.js ***! + \*****************************************************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RUSH_JSON_FILENAME: () => (/* binding */ RUSH_JSON_FILENAME), @@ -453,8 +445,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(node_os__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! node:path */ 176760); /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 832286); -/* harmony import */ var _utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utilities/executionUtilities */ 90178); +/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 359480); +/* harmony import */ var _utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utilities/executionUtilities */ 953844); // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. /* eslint-disable no-console */ diff --git a/examples/AISKU/package.json b/examples/AISKU/package.json index 5e141df6c..bc042fd54 100644 --- a/examples/AISKU/package.json +++ b/examples/AISKU/package.json @@ -54,6 +54,6 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-web": "3.3.11", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" } } diff --git a/examples/cfgSync/package.json b/examples/cfgSync/package.json index 274ac4d84..92c50b330 100644 --- a/examples/cfgSync/package.json +++ b/examples/cfgSync/package.json @@ -42,8 +42,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -67,6 +67,6 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-web": "3.3.11", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" } } diff --git a/examples/dependency/package.json b/examples/dependency/package.json index f63b76f6b..1d8488569 100644 --- a/examples/dependency/package.json +++ b/examples/dependency/package.json @@ -55,6 +55,6 @@ "@microsoft/applicationinsights-web": "3.3.11", "@microsoft/applicationinsights-dependencies-js": "3.3.11", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" } } diff --git a/examples/shared-worker/package.json b/examples/shared-worker/package.json index 2dc7b4256..936c6ceac 100644 --- a/examples/shared-worker/package.json +++ b/examples/shared-worker/package.json @@ -42,8 +42,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -66,6 +66,6 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-web": "3.3.11", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" } } diff --git a/extensions/applicationinsights-analytics-js/package.json b/extensions/applicationinsights-analytics-js/package.json index 141dca3c2..8f12c7553 100644 --- a/extensions/applicationinsights-analytics-js/package.json +++ b/extensions/applicationinsights-analytics-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-analytics-js" }, "scripts": { - "clean": "rimraf dist dist-es5 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt ai", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -51,8 +52,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "qunit": "^2.11.2", "typedoc": "^0.26.6", "sinon": "^7.3.1" @@ -64,7 +65,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" }, "license": "MIT" } diff --git a/extensions/applicationinsights-cfgsync-js/package.json b/extensions/applicationinsights-cfgsync-js/package.json index b621c63bf..6801c7d6b 100644 --- a/extensions/applicationinsights-cfgsync-js/package.json +++ b/extensions/applicationinsights-cfgsync-js/package.json @@ -13,6 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-cfgsync-js" }, "scripts": { + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt cfgsync", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -37,8 +39,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -60,7 +62,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/extensions/applicationinsights-dependencies-js/package.json b/extensions/applicationinsights-dependencies-js/package.json index 4d967ac0b..3b3a3effd 100644 --- a/extensions/applicationinsights-dependencies-js/package.json +++ b/extensions/applicationinsights-dependencies-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-dependencies-js" }, "scripts": { - "clean": "rimraf dist dist-es5 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt deps", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -38,8 +39,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "@rollup/plugin-commonjs": "^24.0.0", @@ -60,7 +61,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "license": "MIT" diff --git a/extensions/applicationinsights-osplugin-js/package.json b/extensions/applicationinsights-osplugin-js/package.json index e170b0ead..194ea914a 100644 --- a/extensions/applicationinsights-osplugin-js/package.json +++ b/extensions/applicationinsights-osplugin-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-osplugin-js" }, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt osplugin", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -33,7 +34,7 @@ "@microsoft/otel-core-js": "0.0.1-alpha", "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" }, "devDependencies": { diff --git a/extensions/applicationinsights-perfmarkmeasure-js/package.json b/extensions/applicationinsights-perfmarkmeasure-js/package.json index 9ea46a5f8..bc7827ea7 100644 --- a/extensions/applicationinsights-perfmarkmeasure-js/package.json +++ b/extensions/applicationinsights-perfmarkmeasure-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-perfmarkmeasure-js" }, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt perfmarkmeasure", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -37,8 +38,8 @@ "tslib": "^2.0.0", "grunt": "^1.5.3", "grunt-cli": "^1.4.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -57,7 +58,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" }, "license": "MIT" } diff --git a/extensions/applicationinsights-properties-js/package.json b/extensions/applicationinsights-properties-js/package.json index e9c096d62..239c5ab61 100644 --- a/extensions/applicationinsights-properties-js/package.json +++ b/extensions/applicationinsights-properties-js/package.json @@ -13,7 +13,8 @@ "url": "https://github.com/microsoft/ApplicationInsights-JS/tree/main/extensions/applicationinsights-properties-js" }, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt properties", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -38,8 +39,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -61,7 +62,7 @@ "@microsoft/dynamicproto-js": "^2.0.3", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/otel-core-js": "0.0.1-alpha", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" }, "license": "MIT" } diff --git a/gruntfile.js b/gruntfile.js index fab171934..791d9b6ff 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -48,7 +48,7 @@ module.exports = function (grunt) { transform: _removeEs6DynamicProto }; } - + const versionPlaceholder = '"#version#"'; const aiCoreDefaultNameReplacements = [ @@ -501,7 +501,7 @@ module.exports = function (grunt) { options: { format: "umd", name: "" + key + "Tests", - sourcemap: false, + sourcemap: true, onwarn: function(warning, handler) { if (warning.code === "THIS_IS_UNDEFINED") { return; @@ -519,14 +519,14 @@ module.exports = function (grunt) { handler(warning); }, - plugins: function() { + plugins: (function(modPath) { return function() { return [ removeEs6DynamicProto(), typeScriptPlugin({ compilerOptions: { - sourceMap: false, + sourceMap: true, inlineSources: true, - inlineSourceMap: true, + inlineSourceMap: false, noImplicitAny: false, module: "es6", moduleResolution: "node", @@ -543,7 +543,8 @@ module.exports = function (grunt) { "**/*.d.ts" ], include: [ - "**/*.ts" + modPath.replace(/^\.\//,'') + "/src/**/*.ts", + modPath.replace(/^\.\//,'') + "/Tests/Unit/**/*.ts" ], tsconfig: false, cacheDir: testPath + "/.rollup-cache" @@ -558,7 +559,7 @@ module.exports = function (grunt) { sourceMap: true }) ]; - } + }; })(modulePath) }, files: { [testPath + "/Unit/dist/" + (modules[key].unitTestName || key + ".tests.js")]: testEntry, @@ -658,14 +659,14 @@ module.exports = function (grunt) { return; } } - + if (warning.code === "EVAL") { return; } handler(warning); }, - plugins: function() { + plugins: (function(modPath) { return function() { return [ typeScriptPlugin({ compilerOptions: { @@ -685,7 +686,9 @@ module.exports = function (grunt) { "**/*.d.ts" ], include: [ - "**/*.ts" + modPath.replace(/^\.\//,'') + "/src/**/*.ts", + modPath.replace(/^\.\//,'') + "/Tests/Perf/**/*.ts", + modPath.replace(/^\.\//,'') + "/test/Perf/**/*.ts" ], tsconfig: false }), @@ -697,7 +700,7 @@ module.exports = function (grunt) { commonJs(), removeEs6DynamicProto() ]; - } + }; })(modulePath) }, files: { [testPath + "/Perf/dist/" + (modules[key].unitTestName || key + ".tests.js")]: testEntry, diff --git a/package.json b/package.json index 0425e22d5..415c8dda4 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "setVersion": "node ./tools/release-tools/setVersion.js", "purge": "node common/scripts/install-run-rush.js purge", "rushClean": "node common/scripts/install-run-rush.js clean", - "fullClean": "npm run rushClean && git clean -xdf && npm install && rush update --recheck --full", + "clean": "npm run rushClean && npm install && rush update --recheck --full", + "rushFullClean": "node common/scripts/install-run-rush.js full-clean", + "fullClean": "npm run rushFullClean && git clean -xdf && npm install && rush update --recheck --full", "fullCleanBuild": "npm run fullClean && npm run rebuild", "ai-min": "node common/scripts/install-run-rush.js ai-min", "ai-restore": "node common/scripts/install-run-rush.js ai-restore", @@ -48,38 +50,38 @@ }, "homepage": "https://github.com/microsoft/ApplicationInsights-JS#readme", "devDependencies": { - "@microsoft/rush": "5.167.0", - "@nevware21/grunt-eslint-ts": "^0.5.1", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@typescript-eslint/eslint-plugin": "^5.46.1", - "@typescript-eslint/parser": "^5.46.1", + "@microsoft/rush": "5.169.3", + "@nevware21/grunt-eslint-ts": "^0.5.2", + "@nevware21/grunt-ts-plugin": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^12.1.2", - "rollup": "^3.20.0", - "rollup-plugin-cleanup": "^3.2.1", - "rollup-plugin-sourcemaps": "^0.6.3", + "@rollup/plugin-typescript": "12.3.0", + "@types/node": "18.19.121", + "@typescript-eslint/eslint-plugin": "^5.46.1", + "@typescript-eslint/parser": "^5.46.1", "archiver": "^5.3.0", "connect": "^3.7.0", - "eslint": "^7.29.0", - "eslint-config-standard": "^16.0.3", - "eslint-plugin-import": "^2.23.4", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.1.0", - "eslint-plugin-security": "^1.4.0", + "eslint": "^8.57.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^16.0.0", + "eslint-plugin-promise": "^6.6.0", + "eslint-plugin-security": "^1.7.1", "eventemitter2": "6.4.9", - "grunt": "^1.5.3", - "grunt-cli": "^1.4.3", - "grunt-rollup": "^12.0.0", - "grunt-contrib-connect": "^3.0.0", + "grunt": "^1.6.1", + "grunt-cli": "^1.5.0", + "grunt-contrib-connect": "^5.0.1", "grunt-contrib-copy": "^1.0.0", - "grunt-contrib-uglify": "^5.2.1", + "grunt-contrib-uglify": "^5.2.2", + "grunt-rollup": "^12.0.0", "puppeteer": "^24.8.2", "request": "^2.88.2", + "rollup": "^3.20.0", + "rollup-plugin-cleanup": "^3.2.1", + "rollup-plugin-sourcemaps": "^0.6.3", "typedoc": "^0.26.6", "typescript": "^4.9.3", "whatwg-fetch": "^3.6.2", - "@types/node": "18.19.121" + "ajv": "8.18.0" } } diff --git a/shared/otel-core/Tests/Perf/src/AppInsights/Core/CorePerfCheck.Tests.ts b/shared/otel-core/Tests/Perf/src/AppInsights/Core/CorePerfCheck.Tests.ts index 8bf666691..140dda42e 100644 --- a/shared/otel-core/Tests/Perf/src/AppInsights/Core/CorePerfCheck.Tests.ts +++ b/shared/otel-core/Tests/Perf/src/AppInsights/Core/CorePerfCheck.Tests.ts @@ -1,8 +1,6 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework"; -import { _eInternalMessageId } from "@microsoft/otel-core-js"; -import { _InternalLogMessage } from "../../../src/Diagnostics/DiagnosticLogger"; -import { optimizeObject, setValue } from "@microsoft/otel-core-js"; import { isObject, isPlainObject, isString, objForEachKey, objKeys } from "@nevware21/ts-utils"; +import { optimizeObject, setValue } from "../../../../../src/utils/HelperFuncs"; interface PerfMeasurements { duration: number; @@ -178,7 +176,7 @@ export class CorePerfCheckTests extends AITestClass { timeout: 60000, test: () => { let iterations = 90000; - let baseTestObject = { }; + let baseTestObject: any = { }; for (let lp = 0; lp < 40; lp++) { baseTestObject["test.value" + lp] = "Test Value " + lp; } @@ -450,7 +448,7 @@ export class CorePerfCheckTests extends AITestClass { timeout: 120000, test: () => { let iterations = 10000; - let baseTestObject = { }; + let baseTestObject: any = { }; for (let lp = 0; lp < 40; lp++) { baseTestObject["test.value" + lp] = "Test Value " + lp; } @@ -580,7 +578,7 @@ export class CorePerfCheckTests extends AITestClass { test: () => { let iterations = 100000; let objectFields = 19; - let baseTestObject = { }; + let baseTestObject: any = { }; for (let lp = 0; lp < objectFields; lp++) { baseTestObject["value" + lp] = "Test Value " + lp; } @@ -615,7 +613,7 @@ export class CorePerfCheckTests extends AITestClass { test: () => { let iterations = 100000; let objectFields = 19; - let baseTestObject = { + let baseTestObject: any = { a: 1 }; for (let lp = 0; lp < objectFields - 1; lp++) { @@ -652,7 +650,7 @@ export class CorePerfCheckTests extends AITestClass { test: () => { let iterations = 100000; let objectFields = 21; - let baseTestObject = { }; + let baseTestObject: any = { }; for (let lp = 0; lp < objectFields; lp++) { baseTestObject["value" + lp] = "Test Value " + lp; } diff --git a/shared/otel-core/Tests/Unit/src/ai/ApplicationInsightsCore.Tests.ts b/shared/otel-core/Tests/Unit/src/ai/ApplicationInsightsCore.Tests.ts index 8c026c207..dd46ffdbb 100644 --- a/shared/otel-core/Tests/Unit/src/ai/ApplicationInsightsCore.Tests.ts +++ b/shared/otel-core/Tests/Unit/src/ai/ApplicationInsightsCore.Tests.ts @@ -5,11 +5,10 @@ import { ITelemetryItem } from "../../../../src/interfaces/ai/ITelemetryItem"; import { IAppInsightsCore } from "../../../../src/interfaces/ai/IAppInsightsCore"; import { normalizeJsName } from "../../../../src/utils/HelperFuncs"; import { random32, mwcRandomSeed, newId, randomValue, mwcRandom32 } from "../../../../src/utils/RandomHelper"; -import { isNullOrUndefined, isString } from "@nevware21/ts-utils"; +import { isNullOrUndefined } from "@nevware21/ts-utils"; import { SenderPostManager } from "../../../../src/core/SenderPostManager"; import { OnCompleteCallback, IPayloadData } from "../../../../src/interfaces/ai/IXHROverride"; import { _ISenderOnComplete, _ISendPostMgrConfig } from "../../../../src/interfaces/ai/ISenderPostManager"; -import { TransportType } from "../../../../src/enums/ai/SendRequestReason"; import { fieldRedaction } from "../../../../src/utils/EnvUtils"; import { _InternalLogMessage, DiagnosticLogger } from "../../../../src/diagnostics/DiagnosticLogger"; import { AppInsightsCore } from "../../../../src/core/AppInsightsCore"; @@ -18,6 +17,7 @@ import { _eInternalMessageId, LoggingSeverity } from "../../../../src/enums/ai/L import { ActiveStatus } from "../../../../src/enums/ai/InitActiveStatusEnum"; import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTimeoutPromise, doAwaitResponse } from "@nevware21/ts-async"; import { setBypassLazyCache } from "@nevware21/ts-utils"; +import { TransportType } from "../../../../src/enums/ext/Enums"; const AIInternalMessagePrefix = "AITR_"; const MaxInt32 = 0xFFFFFFFF; diff --git a/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts b/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts index 3d0db7ab5..85d0486b0 100644 --- a/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts +++ b/shared/otel-core/Tests/Unit/src/ext/ESPromiseSchedulerTests.ts @@ -48,10 +48,10 @@ export class ESPromiseSchedulerTests extends AITestClass { expectedOrder.push("finished3"); expectedOrder.push("test4"); expectedOrder.push("sch4.1"); - expectedOrder.push("reject4-Timeout: Task [test1.0.3-(t4)] - Running: * ms"); + expectedOrder.push("reject4-Timeout: Task [test1.*.3-(t4)] - Running: * ms"); expectedOrder.push("test2.2"); expectedOrder.push("sch2.3"); - expectedOrder.push("reject2.2-Timeout: Task [test1.0.4-(2.2)] - Running: * ms"); + expectedOrder.push("reject2.2-Timeout: Task [test1.*.4-(2.2)] - Running: * ms"); expectedOrder.push("test3.1"); expectedOrder.push("finished3.1"); expectedOrder.push("test4.1"); @@ -184,8 +184,8 @@ export class ESPromiseSchedulerTests extends AITestClass { QUnit.assert.equal(order.length, expectedOrder.length, "Expecting all scheduled event have completed"); for (let lp = 0; lp < expectedOrder.length; lp++) { if (order.length > lp) { - if (strIndexOf(expectedOrder[lp], "*")) { - QUnit.assert.ok(makeRegex(expectedOrder[lp])!.test(order[lp]), "Checking - " + order[lp]); + if (strIndexOf(expectedOrder[lp], "*") != -1) { + QUnit.assert.ok(makeRegex(expectedOrder[lp])!.test(order[lp]), "Checking - " + order[lp] + " matches expected - " + expectedOrder[lp]); } else { QUnit.assert.equal(order[lp], expectedOrder[lp], expectedOrder[lp]); } diff --git a/shared/otel-core/package.json b/shared/otel-core/package.json index 8877e2dcb..beb9fda1f 100644 --- a/shared/otel-core/package.json +++ b/shared/otel-core/package.json @@ -17,7 +17,8 @@ "module": "dist-es5/index.js", "types": "types/otel-core-js.d.ts", "scripts": { - "clean": "rimraf dist dist-es5 dist-es2020 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','dist-es2020','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt otelCore", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -49,8 +50,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -73,7 +74,7 @@ "dependencies": { "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" } } diff --git a/shared/otel-core/src/ext/AppInsightsExtCore.ts b/shared/otel-core/src/ext/AppInsightsExtCore.ts index 40a09331f..36410a9cb 100644 --- a/shared/otel-core/src/ext/AppInsightsExtCore.ts +++ b/shared/otel-core/src/ext/AppInsightsExtCore.ts @@ -1,5 +1,5 @@ /** -* AppInsightsCore.ts +* AppInsightsExtCore.ts * @author Abhilash Panwar (abpanwar) Hector Hernandez (hectorh) * @copyright Microsoft 2018 */ @@ -51,7 +51,7 @@ export class AppInsightsExtCore { _self.initialize = (config: C, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager) => { - doPerf(_self, () => "AppInsightsCore.initialize", () => { + doPerf(_self, () => "AppInsightsExtCore.initialize", () => { try { _base.initialize(createDynamicConfig(config, defaultConfig as C, logger || _self.logger, false).cfg, extensions, logger, notificationManager); } catch (e) { @@ -70,7 +70,7 @@ export class AppInsightsExtCore { - doPerf(_self, () => "AppInsightsCore.track", () => { + doPerf(_self, () => "AppInsightsExtCore.track", () => { let telemetryItem: IExtendedTelemetryItem = item as IExtendedTelemetryItem; if (telemetryItem) { telemetryItem.timings = telemetryItem.timings || {}; diff --git a/shared/otel-core/src/ext/ValueSanitizer.ts b/shared/otel-core/src/ext/ValueSanitizer.ts index aae3c3858..80cc78315 100644 --- a/shared/otel-core/src/ext/ValueSanitizer.ts +++ b/shared/otel-core/src/ext/ValueSanitizer.ts @@ -1,4 +1,4 @@ -import { arrForEach, arrIncludes, arrIndexOf, getLength, isNullOrUndefined, isString, objForEachKey } from "@nevware21/ts-utils"; +import { arrForEach, arrIncludes, arrIndexOf, getLength, isNullOrUndefined, isString, objCreate, objForEachKey } from "@nevware21/ts-utils"; import { STR_EMPTY } from "../constants/InternalConstants"; import { FieldValueSanitizerType } from "../enums/ext/Enums"; import { @@ -84,7 +84,7 @@ export class ValueSanitizer implements IValueSanitizer { let _self = this; // To aid with performance this is a lookup map to check if the field value sanitizer supports this field - let _sanitizerMap: { [path: string]: { [field: string]: ISanitizerMapValue } } = {}; + let _sanitizerMap: { [path: string]: { [field: string]: ISanitizerMapValue } } = objCreate(null); let _sanitizers: IValueSanitizer[] = []; let _fieldSanitizers: IFieldValueSanitizerProvider[] = []; if (fieldSanitizerProvider) { @@ -92,10 +92,10 @@ export class ValueSanitizer implements IValueSanitizer { } function _getFieldSanitizer(path: string, name: string): ISanitizerMapValue { - let result: ISanitizerMapValue; + let result: ISanitizerMapValue | null; let fieldLookup = _sanitizerMap[path]; if (fieldLookup) { - result = fieldLookup[name]; + result = fieldLookup[name] as ISanitizerMapValue | null; } if (!result && result !== null) { @@ -142,7 +142,7 @@ export class ValueSanitizer implements IValueSanitizer { return null; } - fieldLookup = _sanitizerMap[path] = {}; + fieldLookup = _sanitizerMap[path] = objCreate(null); } // Handle edge case to avoid prototype pollution @@ -157,7 +157,7 @@ export class ValueSanitizer implements IValueSanitizer { } _self.clearCache = () => { - _sanitizerMap = {}; + _sanitizerMap = objCreate(null); }; _self.addSanitizer = (newSanitizer: IValueSanitizer) => { @@ -167,7 +167,7 @@ export class ValueSanitizer implements IValueSanitizer { } // Invalidate any previously mapped fields - _sanitizerMap = {}; + _sanitizerMap = objCreate(null); } }; @@ -178,7 +178,7 @@ export class ValueSanitizer implements IValueSanitizer { } // Invalidate any previously mapped fields - _sanitizerMap = {}; + _sanitizerMap = objCreate(null); } }; @@ -188,7 +188,7 @@ export class ValueSanitizer implements IValueSanitizer { if (idx !== -1) { _sanitizers.splice(idx, 1); // Invalidate any previously mapped fields - _sanitizerMap = {}; + _sanitizerMap = objCreate(null); } // Try and remove the sanitizer from any chained sanitizer as well @@ -204,7 +204,7 @@ export class ValueSanitizer implements IValueSanitizer { if (idx !== -1) { _fieldSanitizers.splice(idx, 1); // Invalidate any previously mapped fields - _sanitizerMap = {}; + _sanitizerMap = objCreate(null); } // Try and remove the field sanitizer from any chained sanitizer as well @@ -226,10 +226,6 @@ export class ValueSanitizer implements IValueSanitizer { _self.value = (path: string, name: string, value: FieldValueSanitizerTypes, stringifyObjects?: boolean): IEventProperty | null => { let mapValue: ISanitizerMapValue = _getFieldSanitizer(path, name); if (mapValue && mapValue.canHandle) { - if (!mapValue.canHandle) { - return null; - } - if (mapValue.handler) { // This value sanitizer can't handle this field so pass it only the next one return mapValue.handler.value(path, name, value, stringifyObjects); diff --git a/shared/otel-core/src/ext/extSpanUtils.ts b/shared/otel-core/src/ext/extSpanUtils.ts index 549cacf4c..578a43772 100644 --- a/shared/otel-core/src/ext/extSpanUtils.ts +++ b/shared/otel-core/src/ext/extSpanUtils.ts @@ -216,7 +216,7 @@ function _initIgnoreSemanticValues(): string[] { SEMATTRS_ENDUSER_ID, HTTP_DOT + "status_text", - // http Semabtic conventions + // http Semantic conventions ATTR_CLIENT_ADDRESS, ATTR_CLIENT_PORT, ATTR_SERVER_ADDRESS, diff --git a/shared/otel-core/src/ext/extUtils.ts b/shared/otel-core/src/ext/extUtils.ts index 19518a388..7c39e0f6e 100644 --- a/shared/otel-core/src/ext/extUtils.ts +++ b/shared/otel-core/src/ext/extUtils.ts @@ -246,9 +246,10 @@ export function createGuid(style: GuidStyle = GuidStyle.Digits): string { * @param obj5 - object to merge. * @returns The extended object. */ -export function extend(obj?: any, obj2?: any, obj3?: any, obj4?: any, obj5?: any): any { +export function extend(obj?: any, obj2?: any, obj3?: any, obj4?: any, obj5?: any): any; +export function extend(): any { // Variables - var extended = {}; + var extended: any = {}; var deep = false; var i = 0; var length = arguments.length; @@ -262,7 +263,7 @@ export function extend(obj?: any, obj2?: any, obj3?: any, obj4?: any, obj5?: any // Loop through each object and conduct a merge for (; i < length; i++) { - var obj = theArgs[i]; + let obj = theArgs[i]; objForEachKey(obj, (prop, value) => { // If deep merge and property is an object, merge properties if (deep && value && isObject(value)) { diff --git a/shared/otel-core/src/interfaces/ext/DataModels.ts b/shared/otel-core/src/interfaces/ext/DataModels.ts index 86e262d48..a400a4df6 100644 --- a/shared/otel-core/src/interfaces/ext/DataModels.ts +++ b/shared/otel-core/src/interfaces/ext/DataModels.ts @@ -114,7 +114,7 @@ export interface IExtendedConfiguration extends IConfiguration { * Default is false */ enableWParam?: boolean; - + // End of Internal note: remove these after consuming the ApplicationInsights Core version that defines these on IConfiguration } diff --git a/shared/otel-core/src/telemetry/TelemetryItemCreator.ts b/shared/otel-core/src/telemetry/TelemetryItemCreator.ts index b36e10a67..e2842557f 100644 --- a/shared/otel-core/src/telemetry/TelemetryItemCreator.ts +++ b/shared/otel-core/src/telemetry/TelemetryItemCreator.ts @@ -72,5 +72,5 @@ export class TelemetryItemCreator { * @returns ITelemetryItem that is sent to channel */ - public static create = createTelemetryItem; + public static create = createTelemetryItem; } diff --git a/shared/otel-noop/package.json b/shared/otel-noop/package.json index d1c2cd7e2..843e79da8 100644 --- a/shared/otel-noop/package.json +++ b/shared/otel-noop/package.json @@ -18,7 +18,8 @@ "license": "MIT", "sideEffects": false, "scripts": { - "clean": "rimraf dist dist-es5 dist-es2020 build browser types temp rush-logs", + "clean": "node -e \"['dist','dist-es5','dist-es2020','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:browser && npm run sri && npm run dtsgen", "build:esm": "grunt otelNoop", "build:browser": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -47,8 +48,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "globby": "^11.0.0", "magic-string": "^0.25.7", "pako": "^2.0.3", @@ -72,7 +73,7 @@ "@microsoft/otel-core-js": "0.0.1-alpha", "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "@nevware21/ts-async": ">= 0.5.5 < 2.x" } } diff --git a/tools/applicationinsights-web-snippet/package.json b/tools/applicationinsights-web-snippet/package.json index 583658f8c..c9e7eb6b3 100644 --- a/tools/applicationinsights-web-snippet/package.json +++ b/tools/applicationinsights-web-snippet/package.json @@ -54,7 +54,7 @@ "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-sourcemaps": "^0.6.3", "typedoc": "^0.26.6", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1" + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2" } } diff --git a/tools/chrome-debug-extension/package.json b/tools/chrome-debug-extension/package.json index 6ad86f32c..a5f399e18 100644 --- a/tools/chrome-debug-extension/package.json +++ b/tools/chrome-debug-extension/package.json @@ -47,7 +47,7 @@ "@microsoft/applicationinsights-shims": "3.0.1", "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-async": ">= 0.5.5 < 2.x", - "@nevware21/ts-utils": ">= 0.12.6 < 2.x", + "@nevware21/ts-utils": ">= 0.13.0 < 2.x", "file-saver": "^2.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -72,8 +72,8 @@ "rollup-plugin-peer-deps-external": "^2.2.4", "rollup": "^3.20.0", "rollup-plugin-sourcemaps": "^0.6.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "typescript": "^4.9.3", "archiver": "^5.3.0" } diff --git a/tools/config/package.json b/tools/config/package.json index 3acad6576..e1b8ae456 100644 --- a/tools/config/package.json +++ b/tools/config/package.json @@ -9,7 +9,8 @@ "url": "git+https://github.com/microsoft/ApplicationInsights-JS.git" }, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:browser && npm run build:test", "build:browser": "grunt copy-config", "build:test": "grunt copy-testConfig", diff --git a/tools/release-tools/package.json b/tools/release-tools/package.json index 81f20c559..d1b9f817c 100644 --- a/tools/release-tools/package.json +++ b/tools/release-tools/package.json @@ -6,7 +6,8 @@ "homepage": "https://github.com/microsoft/ApplicationInsights-JS", "sideEffects": false, "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "update": "rush update", "build": "", "rebuild": "", diff --git a/tools/rollup-es5/package.json b/tools/rollup-es5/package.json index 1a1b35dab..826ef690b 100644 --- a/tools/rollup-es5/package.json +++ b/tools/rollup-es5/package.json @@ -17,7 +17,8 @@ "module": "dist-es5/applicationinsights-rollup-es5.js", "types": "types/applicationinsights-rollup-es5.d.ts", "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:bundle", "build:esm": "grunt rollupes5", "build:bundle": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -40,8 +41,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", diff --git a/tools/rollup-plugin-uglify3-js/package.json b/tools/rollup-plugin-uglify3-js/package.json index a2f2908f0..e64a1a533 100644 --- a/tools/rollup-plugin-uglify3-js/package.json +++ b/tools/rollup-plugin-uglify3-js/package.json @@ -12,7 +12,8 @@ "rollup-plugin" ], "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:bundle", "build:esm": "grunt rollupuglify", "build:bundle": "npx rollup -c rollup.config.js --bundleConfigAsCjs", @@ -28,8 +29,8 @@ "grunt": "^1.5.3", "grunt-cli": "^1.4.3", "grunt-rollup": "^12.0.0", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", diff --git a/tools/shims/package.json b/tools/shims/package.json index deb0c3a72..93138a086 100644 --- a/tools/shims/package.json +++ b/tools/shims/package.json @@ -16,7 +16,8 @@ "module": "dist-es5/applicationinsights-shims.js", "types": "types/applicationinsights-shims.d.ts", "scripts": { - "clean": "git clean -xdf", + "clean": "node -e \"['dist','dist-es5','build','browser','types','temp','rush-logs'].forEach(d=>{try{require('fs').rmSync(d,{recursive:true,force:true})}catch(e){}})\"", + "full-clean": "git clean -xdf", "build": "npm run build:esm && npm run build:bundle", "build:esm": "grunt shims", "build:bundle": "rollup -c rollup.config.js --bundleConfigAsCjs", @@ -42,8 +43,8 @@ "@microsoft/applicationinsights-rollup-es5": "1.0.2", "grunt": "^1.5.3", "grunt-cli": "^1.4.3", - "@nevware21/grunt-ts-plugin": "^0.5.1", - "@nevware21/grunt-eslint-ts": "^0.5.1", + "@nevware21/grunt-ts-plugin": "^0.5.2", + "@nevware21/grunt-eslint-ts": "^0.5.2", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-replace": "^5.0.2", @@ -54,6 +55,6 @@ "typescript": "^4.9.3" }, "dependencies": { - "@nevware21/ts-utils": ">= 0.12.6 < 2.x" + "@nevware21/ts-utils": ">= 0.13.0 < 2.x" } }