From b4daa4bb430ad65eeac7b8b355ced3550b993540 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 3 Sep 2024 10:04:36 -0700 Subject: [PATCH 1/7] add in memery split for offline support --- .../Tests/Unit/src/channel.tests.ts | 140 ++++-- .../Tests/Unit/src/offlinetimer.tests.ts | 22 +- .../src/Interfaces/IOfflineProvider.ts | 8 + .../offline-channel-js/src/OfflineChannel.ts | 308 +++++++++---- common/config/rush/npm-shrinkwrap.json | 421 ++++++++++-------- 5 files changed, 588 insertions(+), 311 deletions(-) diff --git a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts index c0d8b8af5..863cb3ad4 100644 --- a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts @@ -1,6 +1,6 @@ import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; -import { DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, IConfig } from "@microsoft/applicationinsights-common"; -import { AppInsightsCore, IConfiguration, arrForEach, getGlobal, getGlobalInst } from "@microsoft/applicationinsights-core-js"; +import { DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, EventPersistence, IConfig } from "@microsoft/applicationinsights-common"; +import { AppInsightsCore, IConfiguration, arrForEach, getGlobal, getGlobalInst, objKeys } from "@microsoft/applicationinsights-core-js"; import { TestChannel, mockTelemetryItem } from "./TestHelper"; import { OfflineChannel } from "../../../src/OfflineChannel" import { IOfflineChannelConfiguration, eStorageProviders } from "../../../src/applicationinsights-offlinechannel-js"; @@ -15,6 +15,7 @@ export class ChannelTests extends AITestClass { private evtDiscard: any; private evtStore: any; private batchDrop: any; + private levelKeys: any; public testInitialize() { super.testInitialize(); @@ -31,6 +32,7 @@ export class ChannelTests extends AITestClass { this.evtSent = 0; this.evtStore = 0; this.batchDrop = 0; + this.levelKeys = [EventPersistence.Critical, EventPersistence.Normal]; } @@ -53,6 +55,7 @@ export class ChannelTests extends AITestClass { this.evtSent = 0; this.evtStore = 0; this.batchDrop = 0; + this.levelKeys = null; } @@ -87,8 +90,16 @@ export class ChannelTests extends AITestClass { offlineListener.setOnlineState(1); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "online should process next"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); @@ -129,8 +140,17 @@ export class ChannelTests extends AITestClass { offlineListener.setOnlineState(1); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "online should process next"); + + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); @@ -184,19 +204,32 @@ export class ChannelTests extends AITestClass { let evt = mockTelemetryItem(); expectedStoreId.push(evt.ver); channel.processTelemetry(evt); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "online should process next"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); Assert.equal(this.batchDrop, 0, "batch drop listener notification should not be called"); offlineListener.setOnlineState(2); channel.processTelemetry(evt); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process"); this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); let storage = AITestClass.orgLocalStorage; let storageKey = "AIOffline_1_dc.services.visualstudio.com"; @@ -220,7 +253,8 @@ export class ChannelTests extends AITestClass { Assert.deepEqual(Object.keys(evts).length, 0, "storage should not have one event"); let request = requests[0]; this.sendJsonResponse(request, {}, 200); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in memo should not have item"); offlineListener.setOnlineState(2); @@ -323,17 +357,30 @@ export class ChannelTests extends AITestClass { offlineListener.setOnlineState(1); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "online should process next"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "online should process next"); + + let inMemoBatch = inMemoMap[EventPersistence.Normal]; offlineListener.setOnlineState(2); channel.processTelemetry(evt); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process"); this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); this.clock.tick(10); @@ -415,7 +462,12 @@ export class ChannelTests extends AITestClass { let ver1 = evt1.ver; let evt2 = mockTelemetryItem(2); channel.processTelemetry(evt1); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 1, "online should process evt1"); channel.processTelemetry(evt2); @@ -474,7 +526,9 @@ export class ChannelTests extends AITestClass { }); this.clock.tick(1); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + //let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; this.sandbox.stub((inMemoBatch) as any, "addEvent").callsFake((evt) => { return false; }); @@ -491,7 +545,8 @@ export class ChannelTests extends AITestClass { let evt = mockTelemetryItem(); channel.processTelemetry(evt); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "should not process evt"); this.clock.tick(1); @@ -543,8 +598,19 @@ export class ChannelTests extends AITestClass { return sender1(payload, oncomplete, sync) }); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.equal(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); @@ -557,11 +623,14 @@ export class ChannelTests extends AITestClass { offlineListener.setOnlineState(2); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); this.clock.tick(300); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in Memo should have no events remaining"); let storage = AITestClass.orgLocalStorage; let storageKey = "AIOffline_1_dc.services.visualstudio.com"; @@ -602,15 +671,27 @@ export class ChannelTests extends AITestClass { let offlineListener = channel.getOfflineListener() as any; offlineListener.setOnlineState(2); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + + // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + // Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); let config = channel["_getDbgPlgTargets"]()[0]; Assert.ok(config, "should have config"); Assert.equal(config.url, DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH, "should have expected url"); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); // should get url from online channel first @@ -619,7 +700,8 @@ export class ChannelTests extends AITestClass { this.core.config.endpointUrl = expectedUrl; this.core.config.instrumentationKey = "test1"; this.clock.tick(1); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl, "in memo has expected url"); config = channel["_getDbgPlgTargets"]()[0]; @@ -632,7 +714,8 @@ export class ChannelTests extends AITestClass { this.core.config.instrumentationKey = "test2"; this.core.config.endpointUrl = expectedUrl1; this.clock.tick(1); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl1, "in memo has expected url test1"); config = channel["_getDbgPlgTargets"]()[0]; @@ -647,7 +730,8 @@ export class ChannelTests extends AITestClass { this.core.config.endpointUrl = expectedUrl2; this.core.config.extensionConfig[sendChannel.identifier].endpointUrl = expectedUrl2; this.clock.tick(1); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl2, "in memo has expected url test1"); config = channel["_getDbgPlgTargets"]()[0]; diff --git a/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts b/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts index 29872c2fd..eeb02fc6c 100644 --- a/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts @@ -80,18 +80,22 @@ export class Offlinetimer extends AITestClass { inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer, "in memo timer should be created"); Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); - let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + //let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch && inMemoBatch.count(), 2, "should have two events"); // offline, flush all events in memory, and processTelemetry is not called again this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(!inMemoTimer.enabled, "in memo timer enabled should be false with no events in memory"); this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(!inMemoTimer.enabled, "in memo timer enabled should be false with no events in memory and no processTelemtry is called"); @@ -102,11 +106,13 @@ export class Offlinetimer extends AITestClass { channel.processTelemetry(validEvt); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one event left after flush"); this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(!inMemoTimer.enabled, "in memo timer should be canceld with no events in memory test1"); @@ -115,12 +121,14 @@ export class Offlinetimer extends AITestClass { channel.processTelemetry(validEvt); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one event left after flush"); offlineListener.setOnlineState(1); this.clock.tick(2000); - inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(!inMemoTimer.enabled, "in memo timer should be canceld with no events in memory test2"); diff --git a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts index bdc27e92a..121a1b6b0 100644 --- a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts +++ b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts @@ -145,6 +145,14 @@ export interface IOfflineChannelConfiguration { */ overrideInstrumentationKey?: string; + /** + * Identifies when saving events into the persistent storage, events will be batched and saved separately based on persistence level + * this is useful to help reduce the loss of critical events during cleaning process + * but it will result in more frequest storage implementations. + * Default: false + */ + splitEvtsWithPersistenceLevel?: boolean; + //TODO: add do sampling } diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index e4d133750..1ad225bb4 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -13,12 +13,12 @@ import { eLoggingSeverity, mergeEvtNamespace, onConfigChange, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise, ITaskScheduler, createAsyncPromise, createTaskScheduler } from "@nevware21/ts-async"; -import { ITimerHandler, isFunction, isString, objDeepFreeze, scheduleTimeout } from "@nevware21/ts-utils"; +import { ITimerHandler, isFunction, isString, objDeepFreeze, objForEachKey, scheduleTimeout } from "@nevware21/ts-utils"; import { EVT_DISCARD_STR, EVT_SENT_STR, EVT_STORE_STR, batchDropNotification, callNotification, isGreaterThanZero, isValidPersistenceLevel } from "./Helpers/Utils"; import { InMemoryBatch } from "./InMemoryBatch"; -import { IPostTransmissionTelemetryItem } from "./Interfaces/IInMemoryBatch"; +import { IInMemoryBatch, IPostTransmissionTelemetryItem } from "./Interfaces/IInMemoryBatch"; import { IOfflineBatchHandler, OfflineBatchCallback, OfflineBatchStoreCallback, eBatchSendStatus, eBatchStoreStatus } from "./Interfaces/IOfflineBatch"; @@ -33,6 +33,7 @@ const DefaultOfflineIdentifier = "OfflineChannel"; const DefaultBatchInterval = 15000; const DefaultInMemoMaxTime = 15000; const PostChannelIdentifier = "PostChannel"; +const PersistenceKeys = [EventPersistence.Critical, EventPersistence.Normal]; interface IUrlLocalStorageConfig { @@ -62,7 +63,8 @@ const defaultOfflineChannelConfig: IConfigDefaults maxSentBatchInterval: { isVal: isGreaterThanZero, v: DefaultBatchInterval}, primaryOnlineChannelId: [BreezeChannelIdentifier, PostChannelIdentifier], overrideInstrumentationKey: undefValue, - senderCfg: {} as IOfflineSenderConfig + senderCfg: {} as IOfflineSenderConfig, + splitEvtsWithPersistenceLevel: false }); //TODO: add tests for sharedAnanlytics @@ -80,7 +82,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // Internal properties used for tracking the current state, these are "true" internal/private properties for this instance let _hasInitialized; let _paused; - let _inMemoBatch: InMemoryBatch; + //let _inMemoBatch: InMemoryBatch; let _sender: Sender; let _urlCfg: IUrlLocalStorageConfig; let _offlineListener: IOfflineListener; @@ -103,6 +105,8 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr let _notificationManager: INotificationManager | undefined; let _isLazyInit: boolean; let _dependencyPlugin: IChannelControls; + let _splitEvts: Boolean; + let _inMemoMap: { [priority: EventPersistence]: InMemoryBatch }; _initDefaults(); @@ -181,15 +185,16 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr //TODO: add function to better get level item.persistence = item.persistence || (item.baseData && item.baseData.persistence) || EventPersistence.Normal; // in case the level is in baseData - if (_shouldCacheEvent(_urlCfg, item) && _inMemoBatch) { + if (_shouldCacheEvent(_urlCfg, item) && _inMemoMap) { if (_overrideIkey) { item.iKey = _overrideIkey; } - let added = _inMemoBatch.addEvent(evt); + //let added = _inMemoBatch.addEvent(evt); + let added = _addEvtToMap(item); // inMemo is full if (!added) { _flushInMemoItems(); - let retry = _inMemoBatch.addEvent(evt); + let retry = _addEvtToMap(item) if (!retry) { _evtDropNotification([evt], EventsDiscardedReason.QueueFull); _throwInternal(_diagLogger, @@ -240,9 +245,12 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _self.onunloadFlush = () => { if (!_paused) { - while (_inMemoBatch && _inMemoBatch.count()) { + while (_hasEvts()) { _flushInMemoItems(true); } + // while (_inMemoBatch && _inMemoBatch.count()) { + // _flushInMemoItems(true); + // } // TODO: unloadprovider might send events out of order } }; @@ -273,7 +281,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _self["_getDbgPlgTargets"] = () => { - return [_urlCfg, _inMemoBatch, _senderInst, _inMemoFlushTimer, _sendNextBatchTimer]; + return [_urlCfg, _inMemoMap, _senderInst, _inMemoFlushTimer, _sendNextBatchTimer]; }; @@ -285,7 +293,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _offlineListener = null; _diagLogger = null; _endpoint = null; - _inMemoBatch = null; + //_inMemoBatch = null; _convertUndefined = undefValue; _maxBatchSize = null; _sendNextBatchTimer = null; @@ -299,6 +307,8 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _evtsLimitInMemo = null; _isLazyInit = false; _dependencyPlugin = null; + _splitEvts= false; + _inMemoMap = null; } @@ -315,9 +325,14 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr if (!_inMemoFlushTimer) { _inMemoFlushTimer = scheduleTimeout(() => { _flushInMemoItems(); - if (_inMemoBatch && _inMemoBatch.count() && _inMemoFlushTimer) { + let hasEvts = _hasEvts(); + if (hasEvts && _inMemoFlushTimer) { _inMemoFlushTimer.refresh(); + } + // if (_inMemoBatch && _inMemoBatch.count() && _inMemoFlushTimer) { + // _inMemoFlushTimer.refresh(); + // } _setSendNextTimer(); }, _inMemoTimerOut); @@ -329,86 +344,172 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr } //flush only flush max batch size event, may still have events lefts + // ********************************************************************************** + // do you need to add function to flush each individual batch (for addevent process) function _flushInMemoItems(unload?: boolean) { try { // TODO: add while loop to flush everything - let inMemo = _inMemoBatch; - let evts = inMemo && inMemo.getItems(); - if (!evts || !evts.length) { - return; - } - let payloadArr:string[] = []; - let size = 0; - let idx = -1; - let criticalCnt = 0; - arrForEach(evts, (evt, index) => { - let curEvt = evt as IPostTransmissionTelemetryItem - idx = index; - let payload = _getPayload(curEvt); - size += payload.length; - if (size > _maxBatchSize) { + let hasEvts = false; + objForEachKey(_inMemoMap, (key) => { + let inMemoBatch: IInMemoryBatch = _inMemoMap[key]; + let inMemo = inMemoBatch; + let evts = inMemo && inMemo.getItems(); + if (!evts || !evts.length) { return; } - if(curEvt.persistence == EventPersistence.Critical) { - criticalCnt ++; - } - idx = index; - payloadArr.push(payload); - - }); - if (!payloadArr.length) { - return; - } - - let sentItems = evts.slice(0, idx + 1); - - _inMemoBatch = _inMemoBatch.createNew(_endpoint, inMemo.getItems().slice(idx + 1), _evtsLimitInMemo); - - let payloadData: IStorageTelemetryItem = null; - if (_offineSupport && _offineSupport.createOneDSPayload) { - payloadData = _offineSupport.createOneDSPayload(sentItems); - if (payloadData) { - payloadData.criticalCnt = criticalCnt; + let payloadArr:string[] = []; + let size = 0; + let idx = -1; + let criticalCnt = 0; + arrForEach(evts, (evt, index) => { + let curEvt = evt as IPostTransmissionTelemetryItem + idx = index; + let payload = _getPayload(curEvt); + size += payload.length; + if (size > _maxBatchSize) { + return; + } + if(curEvt.persistence == EventPersistence.Critical) { + criticalCnt ++; + } + idx = index; + payloadArr.push(payload); + + }); + if (!payloadArr.length) { + return; } - } else { - payloadData = _constructPayloadData(payloadArr, criticalCnt); - } - - - let callback: OfflineBatchStoreCallback = (res) => { - if (!res || !res.state) { - return null; + let sentItems = evts.slice(0, idx + 1); + if (idx + 1 < evts.length) { + // keep track if there is any remaining events + hasEvts = true; + } + _inMemoMap[key] = inMemoBatch.createNew(_endpoint, inMemo.getItems().slice(idx + 1), _evtsLimitInMemo); + + let payloadData: IStorageTelemetryItem = null; + if (_offineSupport && _offineSupport.createOneDSPayload) { + payloadData = _offineSupport.createOneDSPayload(sentItems); + if (payloadData) { + payloadData.criticalCnt = criticalCnt; + } + + } else { + payloadData = _constructPayloadData(payloadArr, criticalCnt); } - let state = res.state; - - if (state == eBatchStoreStatus.Failure) { - if (!unload) { - // for unload, just try to add each batch once - arrForEach(sentItems, (item) => { - _inMemoBatch.addEvent(item); - }); - _setupInMemoTimer(); + let callback: OfflineBatchStoreCallback = (res) => { + if (!res || !res.state) { + return null; + } + let state = res.state; + + if (state == eBatchStoreStatus.Failure) { + if (!unload) { + // for unload, just try to add each batch once + arrForEach(sentItems, (item) => { + _addEvtToMap(item); + }); + _setupInMemoTimer(); + + } else { + // unload, drop events + _evtDropNotification(sentItems, EventsDiscardedReason.NonRetryableStatus); + } + } else { - // unload, drop events - _evtDropNotification(sentItems, EventsDiscardedReason.NonRetryableStatus); + // if eBatchStoreStatus is success + _storeNotification(sentItems); } - - } else { - // if eBatchStoreStatus is success - _storeNotification(sentItems); + }; + + if (payloadData && _urlCfg && _urlCfg.batchHandler) { + let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload); + _queueStorageEvent("storeBatch", promise); } - }; - if (payloadData && _urlCfg && _urlCfg.batchHandler) { - let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload); - _queueStorageEvent("storeBatch", promise); - } - if (_inMemoBatch && !_inMemoBatch.count()) { + }); + if (!hasEvts) { _inMemoFlushTimer && _inMemoFlushTimer.cancel(); } + + // let inMemo = inMemoBatch; + // let evts = inMemo && inMemo.getItems(); + // if (!evts || !evts.length) { + // return; + // } + // let payloadArr:string[] = []; + // let size = 0; + // let idx = -1; + // let criticalCnt = 0; + // arrForEach(evts, (evt, index) => { + // let curEvt = evt as IPostTransmissionTelemetryItem + // idx = index; + // let payload = _getPayload(curEvt); + // size += payload.length; + // if (size > _maxBatchSize) { + // return; + // } + // if(curEvt.persistence == EventPersistence.Critical) { + // criticalCnt ++; + // } + // idx = index; + // payloadArr.push(payload); + + // }); + // if (!payloadArr.length) { + // return; + // } + + // let sentItems = evts.slice(0, idx + 1); + // inMemoBatch = inMemoBatch.createNew(_endpoint, inMemo.getItems().slice(idx + 1), _evtsLimitInMemo); + + // let payloadData: IStorageTelemetryItem = null; + // if (_offineSupport && _offineSupport.createOneDSPayload) { + // payloadData = _offineSupport.createOneDSPayload(sentItems); + // if (payloadData) { + // payloadData.criticalCnt = criticalCnt; + // } + + // } else { + // payloadData = _constructPayloadData(payloadArr, criticalCnt); + // } + + + // let callback: OfflineBatchStoreCallback = (res) => { + // if (!res || !res.state) { + // return null; + // } + // let state = res.state; + + // if (state == eBatchStoreStatus.Failure) { + // if (!unload) { + // // for unload, just try to add each batch once + // arrForEach(sentItems, (item) => { + // inMemoBatch.addEvent(item); + // }); + // _setupInMemoTimer(); + + // } else { + // // unload, drop events + // _evtDropNotification(sentItems, EventsDiscardedReason.NonRetryableStatus); + // } + + // } else { + // // if eBatchStoreStatus is success + // _storeNotification(sentItems); + // } + // }; + // if (payloadData && _urlCfg && _urlCfg.batchHandler) { + // let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload); + // _queueStorageEvent("storeBatch", promise); + // } + + // if (_inMemoBatch && !_inMemoBatch.count()) { + // _inMemoFlushTimer && _inMemoFlushTimer.cancel(); + // } + } catch (e) { // eslint-disable-next-line no-empty @@ -632,14 +733,33 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr batchHandler: handler }; _evtsLimitInMemo = storageConfig.eventsLimitInMem; + _inMemoMap = _inMemoMap || {}; // transfer previous events to new buffer - let evts = null; - let curEvts = _inMemoBatch && _inMemoBatch.getItems(); - if (curEvts && curEvts.length) { - evts = curEvts.slice(0); - _inMemoBatch.clear(); - } - _inMemoBatch = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); + arrForEach(PersistenceKeys, (key) => { + // when init map, we will initize a in memo batch for each EventPersistence key + // previous evts + let curEvts = null; + // evts to be transferred to new inMemo map + let evts = null; + let inMemoBatch = null; + + if ( _inMemoMap && _inMemoMap[key]) { + let inMemoBatch = _inMemoMap[key]; + curEvts = inMemoBatch && inMemoBatch.getItems(); + } + if (curEvts && curEvts.length) { + evts = curEvts.slice(0); + inMemoBatch && inMemoBatch.clear(); + } + _inMemoMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); + + }); + // let curEvts = _inMemoBatch && _inMemoBatch.getItems(); + // if (curEvts && curEvts.length) { + // evts = curEvts.slice(0); + // _inMemoBatch.clear(); + // } + // _inMemoBatch = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); _inMemoTimerOut = storageConfig.inMemoMaxTime; let onlineConfig = ctx.getExtCfg(_primaryChannelId, {}) || {}; _convertUndefined = onlineConfig.convertUndefined; @@ -647,6 +767,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _setRetryTime(); _maxBatchInterval = storageConfig.maxSentBatchInterval; _maxBatchSize = storageConfig.maxBatchsize; + _splitEvts = storageConfig.splitEvtsWithPersistenceLevel; } _urlCfg = urlConfig; _endpoint = curUrl; @@ -676,6 +797,29 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr return _dependencyPlugin; } + function _hasEvts() { + let hasEvts = false; + objForEachKey(_inMemoMap, (key) => { + let inMemoBatch = _inMemoMap[key]; + if (inMemoBatch && inMemoBatch.count()) { + hasEvts = true; + return -1; + } + }); + return hasEvts; + + } + + function _addEvtToMap(item:IPostTransmissionTelemetryItem) { + // if split evts is false, all events will be saved into EventPersistence.Normal batch + let mapKey = EventPersistence.Normal; + if (_splitEvts && item.persistence) { + mapKey = item.persistence; + } + let inMemoBatch = _inMemoMap[mapKey]; + return inMemoBatch.addEvent(item); + } + function _callNotification(evtName: string, theArgs: any[]) { callNotification(_notificationManager, evtName, theArgs); diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 6c76300b9..cd92c9b9e 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -206,9 +206,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "peer": true, "dependencies": { "@eslint/object-schema": "^2.1.4", @@ -289,9 +289,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", - "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -599,7 +599,7 @@ "node_modules/@rush-temp/1ds-core-js": { "version": "0.0.0", "resolved": "file:projects/1ds-core-js.tgz", - "integrity": "sha512-ZO22LVtrMJ5blPWDj0ZpypiyTo1no96ynfhwnrn3Z4yc2bGbDSU5i7iG3gFCoCi8UCt7/mpw1Aq2XBF1w6vmvQ==", + "integrity": "sha512-x5w+iCVokN7FXKi8HnhvMYwE4/FyswiB6GFpRHyaDKxRqQxAHbyHiHh1r2gRyVTXhBoofALW0K9kCdY/CEfziw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -627,7 +627,7 @@ "node_modules/@rush-temp/1ds-post-js": { "version": "0.0.0", "resolved": "file:projects/1ds-post-js.tgz", - "integrity": "sha512-KBo0cFpPAw8nWO7H7e6YOolGoWhSZu2G49cUxZO++pDmJ3H1nxJ+dID2IB1sXfvy3Gl/ltDtS1klphYFUCRQEg==", + "integrity": "sha512-LbNTPCVp9YHeKbCgClZlTefdn1HhqAWkmQTyK4wT0JQTox8mmUpF0yFrCPdxFQVkmTPOOW1HU58vRZxNi9g+Mw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -649,7 +649,7 @@ "node_modules/@rush-temp/ai-test-framework": { "version": "0.0.0", "resolved": "file:projects/ai-test-framework.tgz", - "integrity": "sha512-+m5LukVkSVoPNFxrfIayPiDb0uJOKE3qg5qiyl8lkIpa8toCvG3Xmx9IYHSV+zM9G1FrO9pjWt0aYX2fLlenAw==", + "integrity": "sha512-L1Ls3ZmnO5U5XUzxd7BMqjrC0blWmatDRBFa+90kmD4M12yOaPGZVPFpgvjUw865c5SQeElAWk9YMvg64YVpeA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -675,7 +675,7 @@ "node_modules/@rush-temp/applicationinsights-analytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-analytics-js.tgz", - "integrity": "sha512-D7QmZAloVMb4Nx2KDmtVBGyGS2wGkAk6IDRxe/S4v2L88WXGFfK085EPclOYY/RQC9fWK3/9uv0Dpk98bK9C9A==", + "integrity": "sha512-kKCGW2YVPzdzQfLksEnUfi/woOyFA2WARlJcj781dO1IixMyu+T+ESSGO3N6MHPWgS0cB1kcoasrXQ9mJse2Sw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -703,7 +703,7 @@ "node_modules/@rush-temp/applicationinsights-cfgsync-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-cfgsync-js.tgz", - "integrity": "sha512-UrHqRpHwpLfcD+LXkXQ+Dy5Ijo9Zo/JlkVUMB1WlG3KBpXD+6uWL8pIdr6Wy0LNzBjt+CRvR5OmhKjI/NAsAHA==", + "integrity": "sha512-qaLzVxfD6qv/HH7PwzgpPtpBqqkkNqve9Nb9V6vQ8gasZorDk1ajq9PCwfhxbbFLb5eV+JawVSg9hVXMseTYxQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -732,7 +732,7 @@ "node_modules/@rush-temp/applicationinsights-channel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-channel-js.tgz", - "integrity": "sha512-I4U51YESjEcahlK0pG99Bq53iZy+oqOMrpXJQ6QvoX5A3rgKNi6IEOMnZJ4arerXti+PvsLcEupxUAgTiHEYXg==", + "integrity": "sha512-Ys5qVVv0xOUN+AFhljOWxX0cCcIvShCaCB0kGQ5CPkjKpGOkE38m8pecsons54SygjpGjtJ4INnAvsS/4FVy+Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -759,7 +759,7 @@ "node_modules/@rush-temp/applicationinsights-chrome-debug-extension": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-chrome-debug-extension.tgz", - "integrity": "sha512-4961+3MKLBirvRr6A90kPQdEFyegO6ZqadLWTpBgtZtiBlKJ2oF89WLk/qJeOyuBxbsocF7XmvwHLUa4vdCjIw==", + "integrity": "sha512-3SK5xT/YElrj5kS3lo3c08lt817OO27mca/TmCzXUQcTtRb5jG6DhqEj1w6nUbdNekf66A5BFtPyWCevpqBcyA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -793,7 +793,7 @@ "node_modules/@rush-temp/applicationinsights-clickanalytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-clickanalytics-js.tgz", - "integrity": "sha512-bakEPrSTUj1jwRSoSz+wlH/XDnj3ft0adNR+OLzYsfFX6rGqdKXdwpBoPRjucY8/RyN+K8gaCYaliZnc+ndf9Q==", + "integrity": "sha512-FuR/dIFfELgLwYqgooh+bdmFyn7XzZGH9/VcfduyVloDV4b+biLCx/Rxpp9+SN8Iw8wSS24lKrTOvUgtJ/BH9g==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -818,7 +818,7 @@ "node_modules/@rush-temp/applicationinsights-common": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-common.tgz", - "integrity": "sha512-CGXlOx9IoispIZDPWWi6B/oau7byOUeo1ZjL3XuFVDp8Od3UptLDZEdSLh3LGKH+mDp8UoQ17bh9dx7gacoseg==", + "integrity": "sha512-4kn58bOc/OOwGryQJxt3wf6CM2HHaFAKZoIwgXp2Fl1g5tHiR55w7JANbjF+U70MbHldfE9w/NMEopXAdH97Yw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -844,7 +844,7 @@ "node_modules/@rush-temp/applicationinsights-core-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-core-js.tgz", - "integrity": "sha512-KcYyMYx1D7x3XmsDaBMB72q1kuq6MnARerVLZFWIs9dgoXVIZMiLRthtlQMh7q0KFI4Gm1SBK/7GP8OL2XcS2Q==", + "integrity": "sha512-yKwjYgnxASjCijhu+e7AZdfNDCywDjDBSn9JpMgzz/XUl28f20ORO1+1trACfoUWbetuwrPlFmlq91OSrgAAfA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -873,7 +873,7 @@ "node_modules/@rush-temp/applicationinsights-debugplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-debugplugin-js.tgz", - "integrity": "sha512-a6zzF5ZRk57NQICg2eXWE9SC5SKF3txv0FmzVeWoQBKXtNz1WA+hz+rcJ3ogMy2sS5pEYcg3BXbunanqJTUI0g==", + "integrity": "sha512-Us6V+j5P2PYMaYBdcuFp9VTlwP/VyUZeI4v9BEYwJ1hkQ7mGpQM69D8rxV53lq8C5DqiUML7kj8Wu7YMh7rFMg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -898,7 +898,7 @@ "node_modules/@rush-temp/applicationinsights-dependencies-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-dependencies-js.tgz", - "integrity": "sha512-UDBi+juobpOPZuR4oI8KR1iVLl/EZKeMwuwQnmWTIqMfcJGpD6/2ONTgWN2AWngcilxsouVBIvfmZeuPUJ1q8Q==", + "integrity": "sha512-lUsChhJd/wwzIqva0Snw/elTyLuMM+8rRJukjFtQpKGSUtRRn6wPEX/lEl62B7Ar0NRboCTJG7IeotP9dbJTFA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -926,7 +926,7 @@ "node_modules/@rush-temp/applicationinsights-example-aisku": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-aisku.tgz", - "integrity": "sha512-bgeFiFqCs92GlSFcxqxk8eRiz9wpUydaYd+lrn8/zv00BnZqry7ONhxPXxzCpkpqNHBThfShTpl8TT+K9ACFmg==", + "integrity": "sha512-HbhJCmEC5pZxhYlaWCRPbce7pKSmJO83gY0AVxDxw1NGppdJUH8VgPRp7SQEFYh7rqMmPQInV/Tet+7CyYy/Mw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.3 < 2.x", @@ -944,7 +944,7 @@ "node_modules/@rush-temp/applicationinsights-example-cfgsync": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-cfgsync.tgz", - "integrity": "sha512-0BMAio69kExJcPokkZDbg7qc+0D2Y2Ol25Klk9W8k+zg09NlVKsNh5jdOBj2LFEVWMCvLK3CXwlQqqmqQ8q2Kg==", + "integrity": "sha512-NW2DaF1jenvbNosBbuG4bBZCfpbFfXQYnLvnT5pClsZhzRfU7c1esRRJQBKHvhEoL3G1SdtjWjqVNXh1RmaVjA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -970,7 +970,7 @@ "node_modules/@rush-temp/applicationinsights-example-dependencies": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-dependencies.tgz", - "integrity": "sha512-QMfBgh+mJN+daVppg+Y8bciWj0H8GjPAoMAHlmElU6ljrBzyAxC6nGraawRBmAUA9sJb1Enoht8tI5wfacTgYw==", + "integrity": "sha512-EFpqhd4fwmbc+CKoTyk9NX2fymPKPBHSNqHG3UenVKQSEsbAn+Pw3L13zAihlb9LObXtEj3SzPYCo1fUUfUM7A==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.3 < 2.x", @@ -988,7 +988,7 @@ "node_modules/@rush-temp/applicationinsights-example-shared-worker": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-shared-worker.tgz", - "integrity": "sha512-5YSeDBZJR4WmoXgFeXRByfMxLBzOL+XIZIY7iOGXIQcSYnI6N5WhsieTw5DYX6r/DkYz3VVcBAYoYEnGcWh8AA==", + "integrity": "sha512-oQgUep80iErzVYXOfI3A8JehVCl2koVSP6Kq+DxgSLB6MIN+9JBH14lq1r7H7yeNcczZ06/afvy7GUNY/uJJgw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1014,7 +1014,7 @@ "node_modules/@rush-temp/applicationinsights-js-release-tools": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-js-release-tools.tgz", - "integrity": "sha512-e9jw61D/jeRuLlSL+dQ2bFp8iqw6Q9ZMeboqX0CX0iYwjAPRiN/59ZK66D0UOgggNkqYgSEqgDi+ycw9XRtGnA==", + "integrity": "sha512-6sVB5NMzKj/P9v9UvZlA/IjQSkGeupaDliSt2IZqy+SlR59Hv335Ekz/5f54xMHu+QiARXJATbjX7lDfCMG8qw==", "dependencies": { "globby": "^11.0.0", "grunt": "^1.5.3" @@ -1023,7 +1023,7 @@ "node_modules/@rush-temp/applicationinsights-offlinechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-offlinechannel-js.tgz", - "integrity": "sha512-Gw6e+zYIprHmV+p9Nuvgoh5R9d4smpvnKbmCqmek62nGDYx+OjwPr9/4sQFa6su2QJ3WgqNHuhhMq9IYY1jvDA==", + "integrity": "sha512-v3SX78V7+6z374XgtKNwGRN7K4MSSnvcONXPPbZv963DYYLoYK9zhOhP0bNpf4V+lgl4HCXmdsNIoswkjDl9PQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1050,7 +1050,7 @@ "node_modules/@rush-temp/applicationinsights-osplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-osplugin-js.tgz", - "integrity": "sha512-xt1A7kEubVFgGTILWzFgN6RVeCE2TvOaGWuShNRnTW65B21oBg8MwJnxF1/W7YD6EWMG8kgxP9dAyA9gueR9Lw==", + "integrity": "sha512-M5MLZsz0BMpVL/4isIJqc39gTPyGAeQM1FhUTqfXblW/QT1fPr8KgMKuugmPnlZq4dl5BFrdxFRrfxTiHGNSGA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1072,7 +1072,7 @@ "node_modules/@rush-temp/applicationinsights-perfmarkmeasure-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-perfmarkmeasure-js.tgz", - "integrity": "sha512-DBYKkwnuXKwznZa1JdQIQafTwotVeGVd8t/51bkbOQf0HxBmbj8mk+ZiYmAfb/EWxoLv9xpQ+oRlRXTXFlA7Vw==", + "integrity": "sha512-MUS9o0Imdp0dDeu69HIaLPgxmaUd++U7IWjKYw8xyYDD79B+Wc3iPZ133NIrMezNTKddmT3kzg6+PkatAcll7w==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1097,7 +1097,7 @@ "node_modules/@rush-temp/applicationinsights-properties-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-properties-js.tgz", - "integrity": "sha512-2iU8/W7Jv8GhnLmggraDTyRNXZpSte8yCobwTRDHulwyILYPXcxFTuO8BD819OXrcVd5ACFRdxggWDwl4+6JrQ==", + "integrity": "sha512-QfnpHo6PXbAZIk6kbKI2Wg92l5V8mfFd1k99avfnQpF9M8dW9oH0s8720rlOwyWiZB8YvZKSPvz3oDUqy6p07Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1125,7 +1125,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-es5": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-es5.tgz", - "integrity": "sha512-1Yw2QKlul+WlTRAHhchUxteaSDaeZjskW1H4R3BT7xv7yGZPi0dp4KtKdKAJZQ+/Z+Zxg4XXOWpuDmv/FYmFtQ==", + "integrity": "sha512-pZV3ytRYW9T6XrXLTRqAt5c23vrywlwfWQ1rrGVh78hlig+Ns/ZJw+jM4JwgSyvce8hcZiR+z1rm0xpKju+oJA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1149,7 +1149,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-plugin-uglify3-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-plugin-uglify3-js.tgz", - "integrity": "sha512-gp8gJ52kIbJpkT406+PBS7rtyCSUnc72otGxnwywqWCuBJvO1O+qaOCIJBYL/wYk1lDpMKejDqG94vPSSQtnFg==", + "integrity": "sha512-WtYrHtc+6IgVGmHIahhl2aYUGuloDq9xCX6VuwObLmccrAqmYq0LYbCanjHi8ugorx/zwwQB37yY3y2WfaDGmw==", "dependencies": { "@nevware21/grunt-eslint-ts": "^0.2.2", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -1170,7 +1170,7 @@ "node_modules/@rush-temp/applicationinsights-shims": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-shims.tgz", - "integrity": "sha512-nn1Ba7iM4optvMfCTznHuBTyCG9O5SOucyrAL0+4pxgIW3VKNx+OqBGqhBIUT/D4csiMSK89wImGXayymhTDfQ==", + "integrity": "sha512-EA90BSGIX2gImZZy0eRTYK//78OuAhZsSpjyUqUVwIyVIdgaS3Y1YCMpWPLK3NquzjAP6bfOcY/EoOn+IrZqxQ==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1192,7 +1192,7 @@ "node_modules/@rush-temp/applicationinsights-teechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-teechannel-js.tgz", - "integrity": "sha512-4HO+2GMH65IR6H08L/3JObxBtxsjTZnZElYzKV5AtxgxHht8iYqeYr4NK+GrV7wgkwr8dxeMT9viopjMuatFXw==", + "integrity": "sha512-RmDDpjp2bfyn1JyJqha3uqpaCVY7Tpn7ntV37jf0+x3pTaOwWNPQmtyjlotzw1Fttc/kSYyegqX1cb4zMrenlA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1219,7 +1219,7 @@ "node_modules/@rush-temp/applicationinsights-test-module-type-check": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-test-module-type-check.tgz", - "integrity": "sha512-pCRNaf+6boYDVA27F+A/ynwgQ7jUOgqEA2Wi/xpWXgtxLc2ye9BXeHkZSTIG69ispNNHg0ES4XUx4J6eFO524Q==", + "integrity": "sha512-Pz9vbrsfAw4T/jDcr76cMVZDRNlWfhZ/ugnyoUilBt6YEBdpYQUkTBLwMvcZZ2rSEqpWmay/CUOWynDyn0SJcg==", "dependencies": { "tslib": ">= 1.0.0", "typescript": "^4.9.3" @@ -1228,7 +1228,7 @@ "node_modules/@rush-temp/applicationinsights-web": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web.tgz", - "integrity": "sha512-CZFz+t7H53q+aGNHshe76Zqebfvndno1dUPJ8D8Qokyejtpr2pc22utjVL1vwXyorSzJfB2qteqcfPohZjrNvw==", + "integrity": "sha512-bPg0LUKQcAzc8U+Y7STZvfik+pKp0cPwwMAt0kdUPgiN2G1RUQIbf+GrALLPsoeEBqzuV1f7OmYjCgv6NV9Zpw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1260,7 +1260,7 @@ "node_modules/@rush-temp/applicationinsights-web-basic": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-basic.tgz", - "integrity": "sha512-yebr8q8UeF/iVm7PBhzc5ffilOF3mzNN6IZP34PILaRKe11uXBAUOB5++zD1E2Hh0KObPdw78+giM3O8N1AhDg==", + "integrity": "sha512-XaY/PNVw+JxE+gGtjziF+ZFaKiPXwEticQo508WhL2NeDsUTYEckkkzAZpRQkv2YF6oztLkCtMUUs4EufOy7tw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1287,12 +1287,12 @@ "node_modules/@rush-temp/applicationinsights-web-config": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-config.tgz", - "integrity": "sha512-FwPOZ+esirRqdKg9s7VTxtWqGJ9CQ/gIJ0PfUvTolAF9JZCVw5wQeHD4Tv/KiziZhB50CNaGshnPmLpWGVzo9g==" + "integrity": "sha512-WwlTM/noixyLMqKFBLKa9o88N/2Z3dA9m0R6Qc9UvBNseZqPIpvl1vRMDnmwjMMV6lV3FsmeSmjD7LCJphXF2Q==" }, "node_modules/@rush-temp/applicationinsights-web-snippet": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-snippet.tgz", - "integrity": "sha512-6ZMLBb5IYvPxsnObebo/C7DbO5lgp9YaFw0is2K6+JII067pA0PRcnRrENiYVhiVktHiaOT/wlkH88M4eKVoJw==", + "integrity": "sha512-nD0rJrtU+viELosW90TRQ+B9MEfEHX4gdqN1IGVy6hFzm31W20LI958iF5XX5WiQslQh4VdytdqUUsEZvBXr0Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1389,13 +1389,19 @@ } }, "node_modules/@shikijs/core": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", - "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.0.tgz", + "integrity": "sha512-7Uy6nAWNdYY8GKVIgsdC1+JK1kMvA7gy3fl0gz0BGbsTrT1ve8VFUz+x3SkW9yWq0XhqjkunITFG6sCCWXbTOA==", "dependencies": { + "@shikijs/vscode-textmate": "^9.1.1", "@types/hast": "^3.0.4" } }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.1.1.tgz", + "integrity": "sha512-K/Xw/+uLXHtEp9bwTRbcwSB05du8J0k+O/n8nU7Z+J84BS9C+x6dWRUh3q2Pn8F19p+wPV1GU1xWSSimHlk9nA==" + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -1627,16 +1633,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", - "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz", + "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/type-utils": "8.2.0", - "@typescript-eslint/utils": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/type-utils": "8.3.0", + "@typescript-eslint/utils": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1660,15 +1666,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", - "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz", + "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4" }, "engines": { @@ -1688,13 +1694,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", - "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0" + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1705,13 +1711,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", - "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz", + "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/utils": "8.3.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1729,9 +1735,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", - "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1742,15 +1748,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", - "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -1806,15 +1812,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", - "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0" + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1828,12 +1834,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", - "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/types": "8.3.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2285,9 +2291,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "version": "1.0.30001655", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", + "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==", "funding": [ { "type": "opencollective", @@ -2709,9 +2715,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -2734,16 +2740,16 @@ } }, "node_modules/eslint": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", - "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.1", + "@eslint/config-array": "^0.18.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.9.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -3284,6 +3290,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5789,11 +5808,12 @@ } }, "node_modules/shiki": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", - "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.0.tgz", + "integrity": "sha512-GZGG99Ft3wwuO2cAHExfPEtL5p+iQSDqGPhXako6kjW/dYyFikZi+6eKggZ8554wQatpADkwA+lUOlfl76KBng==", "dependencies": { - "@shikijs/core": "1.14.1", + "@shikijs/core": "1.16.0", + "@shikijs/vscode-textmate": "^9.1.1", "@types/hast": "^3.0.4" } }, @@ -6534,9 +6554,9 @@ "peer": true }, "@eslint/config-array": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", - "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "peer": true, "requires": { "@eslint/object-schema": "^2.1.4", @@ -6602,9 +6622,9 @@ } }, "@eslint/js": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", - "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "peer": true }, "@eslint/object-schema": { @@ -6813,7 +6833,7 @@ }, "@rush-temp/1ds-core-js": { "version": "file:projects\\1ds-core-js.tgz", - "integrity": "sha512-ZO22LVtrMJ5blPWDj0ZpypiyTo1no96ynfhwnrn3Z4yc2bGbDSU5i7iG3gFCoCi8UCt7/mpw1Aq2XBF1w6vmvQ==", + "integrity": "sha512-x5w+iCVokN7FXKi8HnhvMYwE4/FyswiB6GFpRHyaDKxRqQxAHbyHiHh1r2gRyVTXhBoofALW0K9kCdY/CEfziw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -6840,7 +6860,7 @@ }, "@rush-temp/1ds-post-js": { "version": "file:projects\\1ds-post-js.tgz", - "integrity": "sha512-KBo0cFpPAw8nWO7H7e6YOolGoWhSZu2G49cUxZO++pDmJ3H1nxJ+dID2IB1sXfvy3Gl/ltDtS1klphYFUCRQEg==", + "integrity": "sha512-LbNTPCVp9YHeKbCgClZlTefdn1HhqAWkmQTyK4wT0JQTox8mmUpF0yFrCPdxFQVkmTPOOW1HU58vRZxNi9g+Mw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -6861,7 +6881,7 @@ }, "@rush-temp/ai-test-framework": { "version": "file:projects\\ai-test-framework.tgz", - "integrity": "sha512-+m5LukVkSVoPNFxrfIayPiDb0uJOKE3qg5qiyl8lkIpa8toCvG3Xmx9IYHSV+zM9G1FrO9pjWt0aYX2fLlenAw==", + "integrity": "sha512-L1Ls3ZmnO5U5XUzxd7BMqjrC0blWmatDRBFa+90kmD4M12yOaPGZVPFpgvjUw865c5SQeElAWk9YMvg64YVpeA==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -6886,7 +6906,7 @@ }, "@rush-temp/applicationinsights-analytics-js": { "version": "file:projects\\applicationinsights-analytics-js.tgz", - "integrity": "sha512-D7QmZAloVMb4Nx2KDmtVBGyGS2wGkAk6IDRxe/S4v2L88WXGFfK085EPclOYY/RQC9fWK3/9uv0Dpk98bK9C9A==", + "integrity": "sha512-kKCGW2YVPzdzQfLksEnUfi/woOyFA2WARlJcj781dO1IixMyu+T+ESSGO3N6MHPWgS0cB1kcoasrXQ9mJse2Sw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -6913,7 +6933,7 @@ }, "@rush-temp/applicationinsights-cfgsync-js": { "version": "file:projects\\applicationinsights-cfgsync-js.tgz", - "integrity": "sha512-UrHqRpHwpLfcD+LXkXQ+Dy5Ijo9Zo/JlkVUMB1WlG3KBpXD+6uWL8pIdr6Wy0LNzBjt+CRvR5OmhKjI/NAsAHA==", + "integrity": "sha512-qaLzVxfD6qv/HH7PwzgpPtpBqqkkNqve9Nb9V6vQ8gasZorDk1ajq9PCwfhxbbFLb5eV+JawVSg9hVXMseTYxQ==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -6941,7 +6961,7 @@ }, "@rush-temp/applicationinsights-channel-js": { "version": "file:projects\\applicationinsights-channel-js.tgz", - "integrity": "sha512-I4U51YESjEcahlK0pG99Bq53iZy+oqOMrpXJQ6QvoX5A3rgKNi6IEOMnZJ4arerXti+PvsLcEupxUAgTiHEYXg==", + "integrity": "sha512-Ys5qVVv0xOUN+AFhljOWxX0cCcIvShCaCB0kGQ5CPkjKpGOkE38m8pecsons54SygjpGjtJ4INnAvsS/4FVy+Q==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -6967,7 +6987,7 @@ }, "@rush-temp/applicationinsights-chrome-debug-extension": { "version": "file:projects\\applicationinsights-chrome-debug-extension.tgz", - "integrity": "sha512-4961+3MKLBirvRr6A90kPQdEFyegO6ZqadLWTpBgtZtiBlKJ2oF89WLk/qJeOyuBxbsocF7XmvwHLUa4vdCjIw==", + "integrity": "sha512-3SK5xT/YElrj5kS3lo3c08lt817OO27mca/TmCzXUQcTtRb5jG6DhqEj1w6nUbdNekf66A5BFtPyWCevpqBcyA==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -7000,7 +7020,7 @@ }, "@rush-temp/applicationinsights-clickanalytics-js": { "version": "file:projects\\applicationinsights-clickanalytics-js.tgz", - "integrity": "sha512-bakEPrSTUj1jwRSoSz+wlH/XDnj3ft0adNR+OLzYsfFX6rGqdKXdwpBoPRjucY8/RyN+K8gaCYaliZnc+ndf9Q==", + "integrity": "sha512-FuR/dIFfELgLwYqgooh+bdmFyn7XzZGH9/VcfduyVloDV4b+biLCx/Rxpp9+SN8Iw8wSS24lKrTOvUgtJ/BH9g==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7024,7 +7044,7 @@ }, "@rush-temp/applicationinsights-common": { "version": "file:projects\\applicationinsights-common.tgz", - "integrity": "sha512-CGXlOx9IoispIZDPWWi6B/oau7byOUeo1ZjL3XuFVDp8Od3UptLDZEdSLh3LGKH+mDp8UoQ17bh9dx7gacoseg==", + "integrity": "sha512-4kn58bOc/OOwGryQJxt3wf6CM2HHaFAKZoIwgXp2Fl1g5tHiR55w7JANbjF+U70MbHldfE9w/NMEopXAdH97Yw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7049,7 +7069,7 @@ }, "@rush-temp/applicationinsights-core-js": { "version": "file:projects\\applicationinsights-core-js.tgz", - "integrity": "sha512-KcYyMYx1D7x3XmsDaBMB72q1kuq6MnARerVLZFWIs9dgoXVIZMiLRthtlQMh7q0KFI4Gm1SBK/7GP8OL2XcS2Q==", + "integrity": "sha512-yKwjYgnxASjCijhu+e7AZdfNDCywDjDBSn9JpMgzz/XUl28f20ORO1+1trACfoUWbetuwrPlFmlq91OSrgAAfA==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7077,7 +7097,7 @@ }, "@rush-temp/applicationinsights-debugplugin-js": { "version": "file:projects\\applicationinsights-debugplugin-js.tgz", - "integrity": "sha512-a6zzF5ZRk57NQICg2eXWE9SC5SKF3txv0FmzVeWoQBKXtNz1WA+hz+rcJ3ogMy2sS5pEYcg3BXbunanqJTUI0g==", + "integrity": "sha512-Us6V+j5P2PYMaYBdcuFp9VTlwP/VyUZeI4v9BEYwJ1hkQ7mGpQM69D8rxV53lq8C5DqiUML7kj8Wu7YMh7rFMg==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7101,7 +7121,7 @@ }, "@rush-temp/applicationinsights-dependencies-js": { "version": "file:projects\\applicationinsights-dependencies-js.tgz", - "integrity": "sha512-UDBi+juobpOPZuR4oI8KR1iVLl/EZKeMwuwQnmWTIqMfcJGpD6/2ONTgWN2AWngcilxsouVBIvfmZeuPUJ1q8Q==", + "integrity": "sha512-lUsChhJd/wwzIqva0Snw/elTyLuMM+8rRJukjFtQpKGSUtRRn6wPEX/lEl62B7Ar0NRboCTJG7IeotP9dbJTFA==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7128,7 +7148,7 @@ }, "@rush-temp/applicationinsights-example-aisku": { "version": "file:projects\\applicationinsights-example-aisku.tgz", - "integrity": "sha512-bgeFiFqCs92GlSFcxqxk8eRiz9wpUydaYd+lrn8/zv00BnZqry7ONhxPXxzCpkpqNHBThfShTpl8TT+K9ACFmg==", + "integrity": "sha512-HbhJCmEC5pZxhYlaWCRPbce7pKSmJO83gY0AVxDxw1NGppdJUH8VgPRp7SQEFYh7rqMmPQInV/Tet+7CyYy/Mw==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.3 < 2.x", @@ -7145,7 +7165,7 @@ }, "@rush-temp/applicationinsights-example-cfgsync": { "version": "file:projects\\applicationinsights-example-cfgsync.tgz", - "integrity": "sha512-0BMAio69kExJcPokkZDbg7qc+0D2Y2Ol25Klk9W8k+zg09NlVKsNh5jdOBj2LFEVWMCvLK3CXwlQqqmqQ8q2Kg==", + "integrity": "sha512-NW2DaF1jenvbNosBbuG4bBZCfpbFfXQYnLvnT5pClsZhzRfU7c1esRRJQBKHvhEoL3G1SdtjWjqVNXh1RmaVjA==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -7170,7 +7190,7 @@ }, "@rush-temp/applicationinsights-example-dependencies": { "version": "file:projects\\applicationinsights-example-dependencies.tgz", - "integrity": "sha512-QMfBgh+mJN+daVppg+Y8bciWj0H8GjPAoMAHlmElU6ljrBzyAxC6nGraawRBmAUA9sJb1Enoht8tI5wfacTgYw==", + "integrity": "sha512-EFpqhd4fwmbc+CKoTyk9NX2fymPKPBHSNqHG3UenVKQSEsbAn+Pw3L13zAihlb9LObXtEj3SzPYCo1fUUfUM7A==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.3 < 2.x", @@ -7187,7 +7207,7 @@ }, "@rush-temp/applicationinsights-example-shared-worker": { "version": "file:projects\\applicationinsights-example-shared-worker.tgz", - "integrity": "sha512-5YSeDBZJR4WmoXgFeXRByfMxLBzOL+XIZIY7iOGXIQcSYnI6N5WhsieTw5DYX6r/DkYz3VVcBAYoYEnGcWh8AA==", + "integrity": "sha512-oQgUep80iErzVYXOfI3A8JehVCl2koVSP6Kq+DxgSLB6MIN+9JBH14lq1r7H7yeNcczZ06/afvy7GUNY/uJJgw==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -7212,7 +7232,7 @@ }, "@rush-temp/applicationinsights-js-release-tools": { "version": "file:projects\\applicationinsights-js-release-tools.tgz", - "integrity": "sha512-e9jw61D/jeRuLlSL+dQ2bFp8iqw6Q9ZMeboqX0CX0iYwjAPRiN/59ZK66D0UOgggNkqYgSEqgDi+ycw9XRtGnA==", + "integrity": "sha512-6sVB5NMzKj/P9v9UvZlA/IjQSkGeupaDliSt2IZqy+SlR59Hv335Ekz/5f54xMHu+QiARXJATbjX7lDfCMG8qw==", "requires": { "globby": "^11.0.0", "grunt": "^1.5.3" @@ -7220,7 +7240,7 @@ }, "@rush-temp/applicationinsights-offlinechannel-js": { "version": "file:projects\\applicationinsights-offlinechannel-js.tgz", - "integrity": "sha512-Gw6e+zYIprHmV+p9Nuvgoh5R9d4smpvnKbmCqmek62nGDYx+OjwPr9/4sQFa6su2QJ3WgqNHuhhMq9IYY1jvDA==", + "integrity": "sha512-v3SX78V7+6z374XgtKNwGRN7K4MSSnvcONXPPbZv963DYYLoYK9zhOhP0bNpf4V+lgl4HCXmdsNIoswkjDl9PQ==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7246,7 +7266,7 @@ }, "@rush-temp/applicationinsights-osplugin-js": { "version": "file:projects\\applicationinsights-osplugin-js.tgz", - "integrity": "sha512-xt1A7kEubVFgGTILWzFgN6RVeCE2TvOaGWuShNRnTW65B21oBg8MwJnxF1/W7YD6EWMG8kgxP9dAyA9gueR9Lw==", + "integrity": "sha512-M5MLZsz0BMpVL/4isIJqc39gTPyGAeQM1FhUTqfXblW/QT1fPr8KgMKuugmPnlZq4dl5BFrdxFRrfxTiHGNSGA==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7267,7 +7287,7 @@ }, "@rush-temp/applicationinsights-perfmarkmeasure-js": { "version": "file:projects\\applicationinsights-perfmarkmeasure-js.tgz", - "integrity": "sha512-DBYKkwnuXKwznZa1JdQIQafTwotVeGVd8t/51bkbOQf0HxBmbj8mk+ZiYmAfb/EWxoLv9xpQ+oRlRXTXFlA7Vw==", + "integrity": "sha512-MUS9o0Imdp0dDeu69HIaLPgxmaUd++U7IWjKYw8xyYDD79B+Wc3iPZ133NIrMezNTKddmT3kzg6+PkatAcll7w==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7291,7 +7311,7 @@ }, "@rush-temp/applicationinsights-properties-js": { "version": "file:projects\\applicationinsights-properties-js.tgz", - "integrity": "sha512-2iU8/W7Jv8GhnLmggraDTyRNXZpSte8yCobwTRDHulwyILYPXcxFTuO8BD819OXrcVd5ACFRdxggWDwl4+6JrQ==", + "integrity": "sha512-QfnpHo6PXbAZIk6kbKI2Wg92l5V8mfFd1k99avfnQpF9M8dW9oH0s8720rlOwyWiZB8YvZKSPvz3oDUqy6p07Q==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7318,7 +7338,7 @@ }, "@rush-temp/applicationinsights-rollup-es5": { "version": "file:projects\\applicationinsights-rollup-es5.tgz", - "integrity": "sha512-1Yw2QKlul+WlTRAHhchUxteaSDaeZjskW1H4R3BT7xv7yGZPi0dp4KtKdKAJZQ+/Z+Zxg4XXOWpuDmv/FYmFtQ==", + "integrity": "sha512-pZV3ytRYW9T6XrXLTRqAt5c23vrywlwfWQ1rrGVh78hlig+Ns/ZJw+jM4JwgSyvce8hcZiR+z1rm0xpKju+oJA==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -7341,7 +7361,7 @@ }, "@rush-temp/applicationinsights-rollup-plugin-uglify3-js": { "version": "file:projects\\applicationinsights-rollup-plugin-uglify3-js.tgz", - "integrity": "sha512-gp8gJ52kIbJpkT406+PBS7rtyCSUnc72otGxnwywqWCuBJvO1O+qaOCIJBYL/wYk1lDpMKejDqG94vPSSQtnFg==", + "integrity": "sha512-WtYrHtc+6IgVGmHIahhl2aYUGuloDq9xCX6VuwObLmccrAqmYq0LYbCanjHi8ugorx/zwwQB37yY3y2WfaDGmw==", "requires": { "@nevware21/grunt-eslint-ts": "^0.2.2", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -7361,7 +7381,7 @@ }, "@rush-temp/applicationinsights-shims": { "version": "file:projects\\applicationinsights-shims.tgz", - "integrity": "sha512-nn1Ba7iM4optvMfCTznHuBTyCG9O5SOucyrAL0+4pxgIW3VKNx+OqBGqhBIUT/D4csiMSK89wImGXayymhTDfQ==", + "integrity": "sha512-EA90BSGIX2gImZZy0eRTYK//78OuAhZsSpjyUqUVwIyVIdgaS3Y1YCMpWPLK3NquzjAP6bfOcY/EoOn+IrZqxQ==", "requires": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -7382,7 +7402,7 @@ }, "@rush-temp/applicationinsights-teechannel-js": { "version": "file:projects\\applicationinsights-teechannel-js.tgz", - "integrity": "sha512-4HO+2GMH65IR6H08L/3JObxBtxsjTZnZElYzKV5AtxgxHht8iYqeYr4NK+GrV7wgkwr8dxeMT9viopjMuatFXw==", + "integrity": "sha512-RmDDpjp2bfyn1JyJqha3uqpaCVY7Tpn7ntV37jf0+x3pTaOwWNPQmtyjlotzw1Fttc/kSYyegqX1cb4zMrenlA==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7408,7 +7428,7 @@ }, "@rush-temp/applicationinsights-test-module-type-check": { "version": "file:projects\\applicationinsights-test-module-type-check.tgz", - "integrity": "sha512-pCRNaf+6boYDVA27F+A/ynwgQ7jUOgqEA2Wi/xpWXgtxLc2ye9BXeHkZSTIG69ispNNHg0ES4XUx4J6eFO524Q==", + "integrity": "sha512-Pz9vbrsfAw4T/jDcr76cMVZDRNlWfhZ/ugnyoUilBt6YEBdpYQUkTBLwMvcZZ2rSEqpWmay/CUOWynDyn0SJcg==", "requires": { "tslib": ">= 1.0.0", "typescript": "^4.9.3" @@ -7416,7 +7436,7 @@ }, "@rush-temp/applicationinsights-web": { "version": "file:projects\\applicationinsights-web.tgz", - "integrity": "sha512-CZFz+t7H53q+aGNHshe76Zqebfvndno1dUPJ8D8Qokyejtpr2pc22utjVL1vwXyorSzJfB2qteqcfPohZjrNvw==", + "integrity": "sha512-bPg0LUKQcAzc8U+Y7STZvfik+pKp0cPwwMAt0kdUPgiN2G1RUQIbf+GrALLPsoeEBqzuV1f7OmYjCgv6NV9Zpw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7447,7 +7467,7 @@ }, "@rush-temp/applicationinsights-web-basic": { "version": "file:projects\\applicationinsights-web-basic.tgz", - "integrity": "sha512-yebr8q8UeF/iVm7PBhzc5ffilOF3mzNN6IZP34PILaRKe11uXBAUOB5++zD1E2Hh0KObPdw78+giM3O8N1AhDg==", + "integrity": "sha512-XaY/PNVw+JxE+gGtjziF+ZFaKiPXwEticQo508WhL2NeDsUTYEckkkzAZpRQkv2YF6oztLkCtMUUs4EufOy7tw==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7473,11 +7493,11 @@ }, "@rush-temp/applicationinsights-web-config": { "version": "file:projects\\applicationinsights-web-config.tgz", - "integrity": "sha512-FwPOZ+esirRqdKg9s7VTxtWqGJ9CQ/gIJ0PfUvTolAF9JZCVw5wQeHD4Tv/KiziZhB50CNaGshnPmLpWGVzo9g==" + "integrity": "sha512-WwlTM/noixyLMqKFBLKa9o88N/2Z3dA9m0R6Qc9UvBNseZqPIpvl1vRMDnmwjMMV6lV3FsmeSmjD7LCJphXF2Q==" }, "@rush-temp/applicationinsights-web-snippet": { "version": "file:projects\\applicationinsights-web-snippet.tgz", - "integrity": "sha512-6ZMLBb5IYvPxsnObebo/C7DbO5lgp9YaFw0is2K6+JII067pA0PRcnRrENiYVhiVktHiaOT/wlkH88M4eKVoJw==", + "integrity": "sha512-nD0rJrtU+viELosW90TRQ+B9MEfEHX4gdqN1IGVy6hFzm31W20LI958iF5XX5WiQslQh4VdytdqUUsEZvBXr0Q==", "requires": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -7556,13 +7576,19 @@ } }, "@shikijs/core": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", - "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.0.tgz", + "integrity": "sha512-7Uy6nAWNdYY8GKVIgsdC1+JK1kMvA7gy3fl0gz0BGbsTrT1ve8VFUz+x3SkW9yWq0XhqjkunITFG6sCCWXbTOA==", "requires": { + "@shikijs/vscode-textmate": "^9.1.1", "@types/hast": "^3.0.4" } }, + "@shikijs/vscode-textmate": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.1.1.tgz", + "integrity": "sha512-K/Xw/+uLXHtEp9bwTRbcwSB05du8J0k+O/n8nU7Z+J84BS9C+x6dWRUh3q2Pn8F19p+wPV1GU1xWSSimHlk9nA==" + }, "@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -7785,16 +7811,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", - "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.3.0.tgz", + "integrity": "sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==", "peer": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/type-utils": "8.2.0", - "@typescript-eslint/utils": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/type-utils": "8.3.0", + "@typescript-eslint/utils": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7802,56 +7828,56 @@ } }, "@typescript-eslint/parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", - "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.3.0.tgz", + "integrity": "sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==", "peer": true, "requires": { - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", - "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", + "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", "peer": true, "requires": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0" + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0" } }, "@typescript-eslint/type-utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", - "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.3.0.tgz", + "integrity": "sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==", "peer": true, "requires": { - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/typescript-estree": "8.3.0", + "@typescript-eslint/utils": "8.3.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", - "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", + "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", "peer": true }, "@typescript-eslint/typescript-estree": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", - "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", + "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", "peer": true, "requires": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/visitor-keys": "8.3.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -7885,24 +7911,24 @@ } }, "@typescript-eslint/utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", - "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", + "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0" + "@typescript-eslint/scope-manager": "8.3.0", + "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/typescript-estree": "8.3.0" } }, "@typescript-eslint/visitor-keys": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", - "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", + "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", "peer": true, "requires": { - "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/types": "8.3.0", "eslint-visitor-keys": "^3.4.3" } }, @@ -8204,9 +8230,9 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==" + "version": "1.0.30001655", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", + "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==" }, "chalk": { "version": "4.1.2", @@ -8518,9 +8544,9 @@ } }, "escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-html": { "version": "1.0.3", @@ -8534,16 +8560,16 @@ "peer": true }, "eslint": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", - "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.17.1", + "@eslint/config-array": "^0.18.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.9.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -8955,6 +8981,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -10819,11 +10851,12 @@ "peer": true }, "shiki": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", - "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.0.tgz", + "integrity": "sha512-GZGG99Ft3wwuO2cAHExfPEtL5p+iQSDqGPhXako6kjW/dYyFikZi+6eKggZ8554wQatpADkwA+lUOlfl76KBng==", "requires": { - "@shikijs/core": "1.14.1", + "@shikijs/core": "1.16.0", + "@shikijs/vscode-textmate": "^9.1.1", "@types/hast": "^3.0.4" } }, From 72b962117199c3556ce805951bc07d39ac512b8e Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 3 Sep 2024 12:16:54 -0700 Subject: [PATCH 2/7] update --- .../offline-channel-js/src/OfflineChannel.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index 1ad225bb4..2f77ce0c8 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -194,7 +194,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // inMemo is full if (!added) { _flushInMemoItems(); - let retry = _addEvtToMap(item) + let retry = _addEvtToMap(item); if (!retry) { _evtDropNotification([evt], EventsDiscardedReason.QueueFull); _throwInternal(_diagLogger, @@ -737,20 +737,18 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // transfer previous events to new buffer arrForEach(PersistenceKeys, (key) => { // when init map, we will initize a in memo batch for each EventPersistence key - // previous evts - let curEvts = null; // evts to be transferred to new inMemo map let evts = null; - let inMemoBatch = null; if ( _inMemoMap && _inMemoMap[key]) { let inMemoBatch = _inMemoMap[key]; - curEvts = inMemoBatch && inMemoBatch.getItems(); - } - if (curEvts && curEvts.length) { - evts = curEvts.slice(0); - inMemoBatch && inMemoBatch.clear(); + let curEvts = inMemoBatch && inMemoBatch.getItems(); + if (curEvts && curEvts.length) { + evts = curEvts.slice(0); + inMemoBatch && inMemoBatch.clear(); + } } + _inMemoMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); }); From 9e1efa59425fc41c96c29988e39e2863aa807359 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Wed, 4 Sep 2024 16:17:02 -0700 Subject: [PATCH 3/7] update --- AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts | 4 ++-- channels/offline-channel-js/src/OfflineChannel.ts | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index 6055b0c41..ce845d33e 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -2,7 +2,7 @@ import { AITestClass, Assert, PollingAssert, EventValidator, TraceValidator, Exc import { SinonSpy } from 'sinon'; import { ApplicationInsights } from '../../../src/applicationinsights-web' import { Sender } from '@microsoft/applicationinsights-channel-js'; -import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig } from '@microsoft/applicationinsights-common'; +import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig, EventPersistence } from '@microsoft/applicationinsights-common'; import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus, FeatureOptInMode } from "@microsoft/applicationinsights-core-js"; import { TelemetryContext } from '@microsoft/applicationinsights-properties-js'; import { createAsyncResolvedPromise } from '@nevware21/ts-async'; @@ -677,7 +677,7 @@ export class ApplicationInsightsTests extends AITestClass { this._ai.trackEvent({ name: "offline event", properties: { "prop2": "value2" }, measurements: { "measurement2": 200 } }); inMemoTimer = offlineChannel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer, "in memo timer should not be null"); - let inMemoBatch = offlineChannel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = offlineChannel["_getDbgPlgTargets"]()[1][EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one event"); return true diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index 2f77ce0c8..05279b19f 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -13,7 +13,7 @@ import { eLoggingSeverity, mergeEvtNamespace, onConfigChange, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise, ITaskScheduler, createAsyncPromise, createTaskScheduler } from "@nevware21/ts-async"; -import { ITimerHandler, isFunction, isString, objDeepFreeze, objForEachKey, scheduleTimeout } from "@nevware21/ts-utils"; +import { ITimerHandler, arrSlice, isFunction, isString, objDeepFreeze, objForEachKey, scheduleTimeout } from "@nevware21/ts-utils"; import { EVT_DISCARD_STR, EVT_SENT_STR, EVT_STORE_STR, batchDropNotification, callNotification, isGreaterThanZero, isValidPersistenceLevel } from "./Helpers/Utils"; @@ -734,6 +734,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr }; _evtsLimitInMemo = storageConfig.eventsLimitInMem; _inMemoMap = _inMemoMap || {}; + let newMap = {}; // transfer previous events to new buffer arrForEach(PersistenceKeys, (key) => { // when init map, we will initize a in memo batch for each EventPersistence key @@ -744,14 +745,17 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr let inMemoBatch = _inMemoMap[key]; let curEvts = inMemoBatch && inMemoBatch.getItems(); if (curEvts && curEvts.length) { - evts = curEvts.slice(0); + evts = arrSlice(curEvts); inMemoBatch && inMemoBatch.clear(); } } + newMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); + - _inMemoMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); + //_inMemoMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); }); + _inMemoMap = newMap; // let curEvts = _inMemoBatch && _inMemoBatch.getItems(); // if (curEvts && curEvts.length) { // evts = curEvts.slice(0); From 116d51fe80b5b962606b11d007ad885edd39c87c Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Wed, 4 Sep 2024 17:19:15 -0700 Subject: [PATCH 4/7] update --- .../Tests/Unit/src/channel.tests.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts index 863cb3ad4..c6e20e79b 100644 --- a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts @@ -224,10 +224,12 @@ export class ChannelTests extends AITestClass { offlineListener.setOnlineState(2); channel.processTelemetry(evt); // inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process"); this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); @@ -254,6 +256,7 @@ export class ChannelTests extends AITestClass { let request = requests[0]; this.sendJsonResponse(request, {}, 200); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in memo should not have item"); @@ -379,6 +382,7 @@ export class ChannelTests extends AITestClass { Assert.equal(inMemoBatch.count(), 1, "offline should process"); this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); @@ -470,6 +474,8 @@ export class ChannelTests extends AITestClass { // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 1, "online should process evt1"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; channel.processTelemetry(evt2); Assert.equal(inMemoBatch.count(), 1, "online should process evt2"); @@ -487,6 +493,8 @@ export class ChannelTests extends AITestClass { let invalidEvt = mockTelemetryItem(); channel.processTelemetry(invalidEvt); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "online should not process invalid item"); this.clock.tick(1); Assert.equal(this.evtDiscard, 1, "discard listener notification should be called once test2"); @@ -546,6 +554,7 @@ export class ChannelTests extends AITestClass { channel.processTelemetry(evt); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "should not process evt"); @@ -625,11 +634,13 @@ export class ChannelTests extends AITestClass { channel.processTelemetry(evt); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); this.clock.tick(300); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in Memo should have no events remaining"); let storage = AITestClass.orgLocalStorage; @@ -691,6 +702,7 @@ export class ChannelTests extends AITestClass { let evt = mockTelemetryItem(); channel.processTelemetry(evt); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); @@ -701,6 +713,7 @@ export class ChannelTests extends AITestClass { this.core.config.instrumentationKey = "test1"; this.clock.tick(1); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl, "in memo has expected url"); @@ -715,6 +728,7 @@ export class ChannelTests extends AITestClass { this.core.config.endpointUrl = expectedUrl1; this.clock.tick(1); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl1, "in memo has expected url test1"); @@ -731,6 +745,7 @@ export class ChannelTests extends AITestClass { this.core.config.extensionConfig[sendChannel.identifier].endpointUrl = expectedUrl2; this.clock.tick(1); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); Assert.equal(inMemoBatch.endpoint(), expectedUrl2, "in memo has expected url test1"); From 0b03722cf940449a0bcb2cbb5de669c8f8e4769b Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Thu, 5 Sep 2024 13:18:42 -0700 Subject: [PATCH 5/7] update --- .../offline-channel-js/src/Interfaces/IOfflineProvider.ts | 3 ++- channels/offline-channel-js/src/OfflineChannel.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts index 121a1b6b0..f984a9bd8 100644 --- a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts +++ b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts @@ -149,9 +149,10 @@ export interface IOfflineChannelConfiguration { * Identifies when saving events into the persistent storage, events will be batched and saved separately based on persistence level * this is useful to help reduce the loss of critical events during cleaning process * but it will result in more frequest storage implementations. + * If it is set to false, all events will be saved into single in memory batch * Default: false */ - splitEvtsWithPersistenceLevel?: boolean; + splitEvts?: boolean; //TODO: add do sampling diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index 05279b19f..f320630b5 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -64,7 +64,7 @@ const defaultOfflineChannelConfig: IConfigDefaults primaryOnlineChannelId: [BreezeChannelIdentifier, PostChannelIdentifier], overrideInstrumentationKey: undefValue, senderCfg: {} as IOfflineSenderConfig, - splitEvtsWithPersistenceLevel: false + splitEvts: false }); //TODO: add tests for sharedAnanlytics @@ -769,7 +769,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _setRetryTime(); _maxBatchInterval = storageConfig.maxSentBatchInterval; _maxBatchSize = storageConfig.maxBatchsize; - _splitEvts = storageConfig.splitEvtsWithPersistenceLevel; + _splitEvts = storageConfig.splitEvts; } _urlCfg = urlConfig; _endpoint = curUrl; From 669f55bf8e5798ef2896bde213efcf05197dbec3 Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Sat, 7 Sep 2024 13:08:10 -0700 Subject: [PATCH 6/7] update --- .../Tests/Unit/src/channel.tests.ts | 204 ++++++++++++++++++ .../Tests/Unit/src/offlinetimer.tests.ts | 118 ++++++++++ .../src/Interfaces/IOfflineProvider.ts | 4 +- .../offline-channel-js/src/OfflineChannel.ts | 19 +- 4 files changed, 339 insertions(+), 6 deletions(-) diff --git a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts index c6e20e79b..56861dd32 100644 --- a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts @@ -310,6 +310,105 @@ export class ChannelTests extends AITestClass { } }); + this.testCase({ + name: "Channel: Process Telemetry with web provider when splitevts is set to true ", + useFakeTimers: true, + test: () => { + let window = getGlobalInst("window"); + let fakeXMLHttpRequest = (window as any).XMLHttpRequest; + this.coreConfig.extensionConfig = {["OfflineChannel"]: {inMemoMaxTime: 2000, splitEvts: true} as IOfflineChannelConfiguration}; + let sendChannel = new TestChannel(); + let storedEvts:any[] = []; + let expectedStoreId: any[] = []; + + this.core.initialize(this.coreConfig, [sendChannel]); + this.core.addNotificationListener({ + eventsDiscarded: (evts, reason) => { + this.evtDiscard += 1; + }, + offlineEventsStored: (evts) => { + this.evtStore += 1; + arrForEach(evts, (item) => { + storedEvts.push(item.ver); + }) + + }, + offlineBatchDrop(cnt, reason) { + this.batchDrop += 1; + } + }); + + let channel = new OfflineChannel(); + + channel.initialize(this.coreConfig, this.core,[]); + this.onDone(() => { + channel.teardown(); + }); + + this.clock.tick(1); + let offlineListener = channel.getOfflineListener() as any; + offlineListener.setOnlineState(1); + let evt = mockTelemetryItem(); + expectedStoreId.push(evt.ver); + channel.processTelemetry(evt); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + Assert.ok(inMemoMap, "inMemoMap should exist"); + arrForEach(this.levelKeys, (key) => { + let inMemoBatch = inMemoMap[key]; + Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); + }); + + Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); + Assert.equal(this.evtStore, 0, "store listener notification should not be called"); + Assert.equal(this.batchDrop, 0, "batch drop listener notification should not be called"); + + offlineListener.setOnlineState(2); + // process EventPersistence.Normal event + channel.processTelemetry(evt); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch.count(), 1, "offline should process normal event"); + // process ventPersistence.Critical event + let criticalEvt = mockTelemetryItem(2); + channel.processTelemetry(criticalEvt); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch.count(), 1, "offline should process critical event"); + + + this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch.count(), 0, "provider should store normal item"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch.count(), 0, "provider should store critical normal item"); + let storage = AITestClass.orgLocalStorage; + let storageKey = "AIOffline_1_dc.services.visualstudio.com"; + let storageStr = storage.getItem(storageKey) as any; + Assert.ok(storageStr.indexOf("header1") > -1, "should contain expeceted header"); + + let storageObj = JSON.parse(storageStr); + let evts = storageObj.evts; + Assert.deepEqual(Object.keys(evts).length, 2, "storage should have two events"); + + let normalCnt = '"criticalCnt":0'; + let criticalCnt = '"criticalCnt":1'; + Assert.ok(storageStr.indexOf(normalCnt) > -1, "should contain expeceted critical count for normal event batches"); + Assert.ok(storageStr.indexOf(criticalCnt) > -1, "should contain expeceted critical count for critical event batches"); + + this.clock.tick(1); + + Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called test1"); + Assert.equal(this.evtStore, 2, "store listener notification should be called two times test1"); + Assert.equal(this.batchDrop, 0, "batch drop listener notification should not be called test1"); + + channel.teardown(); + (window as any).XMLHttpRequest = fakeXMLHttpRequest; + } + }); + this.testCaseAsync({ name: "Channel: Process Telemetry with indexed db provider", @@ -474,6 +573,7 @@ export class ChannelTests extends AITestClass { // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 1, "online should process evt1"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; channel.processTelemetry(evt2); @@ -509,6 +609,110 @@ export class ChannelTests extends AITestClass { }); + this.testCase({ + name: "Channel: add event when in Memory batch is full with splitEvts set to true", + useFakeTimers: true, + test: () => { + let channel = new OfflineChannel(); + let sendChannel = new TestChannel(); + // make sure in memo time is long enough + this.coreConfig.extensionConfig = {["OfflineChannel"]: {providers:[eStorageProviders.LocalStorage], inMemoMaxTime: 200000000, eventsLimitInMem: 1, splitEvts: true} as IOfflineChannelConfiguration}; + this.core.initialize(this.coreConfig,[channel, sendChannel]); + this.core.addNotificationListener({ + eventsDiscarded: (evts, reason) => { + this.evtDiscard += 1; + }, + offlineEventsStored: (evts) => { + this.evtStore += 1; + }, + offlineBatchSent: (batch) => { + this.evtSent += 1; + }, + offlineBatchDrop(cnt, reason) { + this.batchDrop += 1; + } + }); + + this.clock.tick(1); + + Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); + Assert.equal(this.evtStore, 0, "store listener notification should not be called"); + Assert.equal(this.evtSent, 0, "sent listener notification should not be called"); + Assert.equal(this.batchDrop, 0, "batch drop listener notification should not be called"); + + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + Assert.ok(inMemoMap, "inMemoMap should exist"); + let mapKeys = objKeys(inMemoMap); + Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); + + let offlineListener = channel.getOfflineListener() as any; + offlineListener.setOnlineState(2); + + // eventsLimitInMem = 1, means for each persistent level, max number allowed for in memory events is 1 + + // process one critical event and one normal event (inMemoMap[nomral] should have 1 event and inMemoMap[critical] should have 1 event) + // then process another normal event (one normal event should be saved, inMemoMap[nomral] should have 1 event and inMemoMap[critical] should have 1 event) + let normalEvt1 = mockTelemetryItem(); + let ver1 = normalEvt1.ver; + let normalEvt2 = mockTelemetryItem(); + let criticalEvt1 = mockTelemetryItem(2); + let cVer1 = criticalEvt1.ver; + channel.processTelemetry(normalEvt1); + channel.processTelemetry(criticalEvt1); + + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch.count(), 1, "online should process normal evt"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch.count(), 1, "online should process critical evt2"); + channel.processTelemetry(normalEvt2); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch.count(), 1, "normal event batch should have one event"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch.count(), 1, "critical event batch should have one event"); + + let storage = AITestClass.orgLocalStorage; + let storageKey = "AIOffline_1_dc.services.visualstudio.com"; + let storageStr = storage.getItem(storageKey) as any; + let storageObj = JSON.parse(storageStr); + let evts = storageObj.evts; + Assert.equal(evts && Object.keys(evts).length, 1, "should have one events"); + Assert.ok(storageStr.indexOf(ver1) > -1, "should contain only the first event"); + this.clock.tick(1); + Assert.equal(this.evtDiscard, 0, "discard listener notification should not called test1"); + Assert.equal(this.evtStore, 1, "store listener notification should be called once test1"); + Assert.equal(this.evtSent, 0, "sent listener notification should not be called test1"); + + // process another critical event + let criticalEvt2 = mockTelemetryItem(2); + channel.processTelemetry(criticalEvt2); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch.count(), 1, "normal event batch should have one event test1"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch.count(), 1, "critical event batch should have one event test1"); + + storage = AITestClass.orgLocalStorage; + storageKey = "AIOffline_1_dc.services.visualstudio.com"; + storageStr = storage.getItem(storageKey) as any; + storageObj = JSON.parse(storageStr); + evts = storageObj.evts; + Assert.equal(evts && Object.keys(evts).length, 2, "should have two events"); + Assert.ok(storageStr.indexOf(ver1) > -1, "should contain the first normal event"); + Assert.ok(storageStr.indexOf(cVer1) > -1, "should contain the first critical event"); + this.clock.tick(1); + Assert.equal(this.evtDiscard, 0, "discard listener notification should not called test2"); + Assert.equal(this.evtStore, 2, "store listener notification should be called twice test2"); + Assert.equal(this.evtSent, 0, "sent listener notification should not be called test2"); + + + channel.teardown(); + + } + + }); + this.testCase({ name: "Channel: drop batch notification should be handled with inMemo batch", useFakeTimers: true, diff --git a/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts b/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts index eeb02fc6c..7474951ec 100644 --- a/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/offlinetimer.tests.ts @@ -88,6 +88,7 @@ export class Offlinetimer extends AITestClass { // offline, flush all events in memory, and processTelemetry is not called again this.clock.tick(2000); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; @@ -95,6 +96,7 @@ export class Offlinetimer extends AITestClass { this.clock.tick(2000); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; @@ -106,11 +108,13 @@ export class Offlinetimer extends AITestClass { channel.processTelemetry(validEvt); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one event left after flush"); this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); @@ -122,12 +126,14 @@ export class Offlinetimer extends AITestClass { inMemoTimer = channel["_getDbgPlgTargets"]()[3]; Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one event left after flush"); offlineListener.setOnlineState(1); this.clock.tick(2000); //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; + inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left"); inMemoTimer = channel["_getDbgPlgTargets"]()[3]; @@ -143,6 +149,118 @@ export class Offlinetimer extends AITestClass { } }); + this.testCase({ + name: "InMemo Timer: Handle in memory timer with splitEvts set to true", + useFakeTimers: true, + test: () => { + this.coreConfig.extensionConfig = {["OfflineChannel"]: {providers:[eStorageProviders.LocalStorage], inMemoMaxTime: 2000, eventsLimitInMem: 1, splitEvts: true } as IOfflineChannelConfiguration}; + let channel = new OfflineChannel(); + let onlineChannel = new TestChannel(); + this.core.initialize(this.coreConfig,[channel, onlineChannel]); + + this.clock.tick(1); + let offlineListener = channel.getOfflineListener() as any; + + // online, processTelemetry is not called + offlineListener.setOnlineState(1); + let inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer, "in memo timer should be null"); + + // offline, processTelemetry is not called + offlineListener.setOnlineState(2); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer, "in memo timer should be null test1"); + + // online, processTelemetry is called + offlineListener.setOnlineState(1); + let evt = mockTelemetryItem(); + channel.processTelemetry(evt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer, "in memo timer should be null test2"); + + // offline, processTelemetry is called with normal event + offlineListener.setOnlineState(2); + evt = mockTelemetryItem(); + channel.processTelemetry(evt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(inMemoTimer, "in memo timer should be created test3"); + Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled test1"); + let inMemoMap = channel["_getDbgPlgTargets"]()[1]; + let inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one normal event"); + + // offline, processTelemetry is called with critical event + offlineListener.setOnlineState(2); + let criticalEvt = mockTelemetryItem(2) as IPostTransmissionTelemetryItem; + channel.processTelemetry(criticalEvt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(inMemoTimer, "in memo timer should be not null"); + Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled test2"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one critical event"); + + // offline, processTelemetry is called with normal event again + offlineListener.setOnlineState(2); + evt = mockTelemetryItem(); + channel.processTelemetry(evt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(inMemoTimer, "in memo timer should not be null test1"); + Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled test2"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one normal event test1"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one critical event test1"); + + // offline, flush all events in memory, and processTelemetry is not called again + this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no noraml event left"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no critical event left"); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer.enabled, "in memo timer enabled should be false with no events in memory"); + + this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no noraml event left test1"); + inMemoBatch = inMemoMap[EventPersistence.Critical]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no critical event left tes1 "); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer.enabled, "in memo timer enabled should be false with no events in memory"); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer.enabled, "in memo timer enabled should be false with no events in memory and no processTelemtry is called"); + + + // offline with one normal event saved in memory, and then online with processTelemetry called + channel.processTelemetry(evt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(inMemoTimer.enabled, "in memo timer should be enabled"); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 1, "should have one normal event left test1"); + + offlineListener.setOnlineState(1); + this.clock.tick(2000); + inMemoMap = channel["_getDbgPlgTargets"]()[1]; + inMemoBatch = inMemoMap[EventPersistence.Normal]; + Assert.equal(inMemoBatch && inMemoBatch.count(), 0, "should have no event left test1"); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer.enabled, "in memo timer should be canceld with no events in memory test2"); + + channel.processTelemetry(evt); + inMemoTimer = channel["_getDbgPlgTargets"]()[3]; + Assert.ok(!inMemoTimer.enabled, "in memo timer should be canceld when back online"); + + + channel.teardown(); + + } + }); + this.testCase({ name: "SendNextBatch Timer: Handle sendNextBatch timer", useFakeTimers: true, diff --git a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts index f984a9bd8..82eda4edf 100644 --- a/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts +++ b/channels/offline-channel-js/src/Interfaces/IOfflineProvider.ts @@ -75,7 +75,9 @@ export interface IOfflineChannelConfiguration { indexedDbName?: string; /** - * [Optional] Identifies the maximum number of events to store in memory before sending to persistent storage. + * [Optional] Identifies the maximum number of events to store in each memory batch before sending to persistent storage. + * For versions > 3.3.2, new config splitEvts is added + * If splitEvts is set true, eventsLimitInMem will be applied to each persistent level batch */ eventsLimitInMem?: number; diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index f320630b5..1a7e4b28d 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -18,7 +18,7 @@ import { EVT_DISCARD_STR, EVT_SENT_STR, EVT_STORE_STR, batchDropNotification, callNotification, isGreaterThanZero, isValidPersistenceLevel } from "./Helpers/Utils"; import { InMemoryBatch } from "./InMemoryBatch"; -import { IInMemoryBatch, IPostTransmissionTelemetryItem } from "./Interfaces/IInMemoryBatch"; +import { IPostTransmissionTelemetryItem } from "./Interfaces/IInMemoryBatch"; import { IOfflineBatchHandler, OfflineBatchCallback, OfflineBatchStoreCallback, eBatchSendStatus, eBatchStoreStatus } from "./Interfaces/IOfflineBatch"; @@ -193,7 +193,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr let added = _addEvtToMap(item); // inMemo is full if (!added) { - _flushInMemoItems(); + _flushInMemoItems(false, item.persistence); let retry = _addEvtToMap(item); if (!retry) { _evtDropNotification([evt], EventsDiscardedReason.QueueFull); @@ -346,17 +346,25 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr //flush only flush max batch size event, may still have events lefts // ********************************************************************************** // do you need to add function to flush each individual batch (for addevent process) - function _flushInMemoItems(unload?: boolean) { + function _flushInMemoItems(unload?: boolean, mapKey?: number | EventPersistence) { try { // TODO: add while loop to flush everything let hasEvts = false; - objForEachKey(_inMemoMap, (key) => { - let inMemoBatch: IInMemoryBatch = _inMemoMap[key]; + // can use objForEachKey(_inMemoMap, (key)), but keys returned by this function is always string + arrForEach(PersistenceKeys, (key) => { + let inMemoBatch: InMemoryBatch = _inMemoMap[key]; let inMemo = inMemoBatch; let evts = inMemo && inMemo.getItems(); if (!evts || !evts.length) { return; } + if (_splitEvts && mapKey && mapKey !== key) { + // if split evts is set to true + // specific mapkey is defined + // for key !== mapkey, only check if there are any events left in order to refresh timer + hasEvts = !!evts.length; + return; + } let payloadArr:string[] = []; let size = 0; let idx = -1; @@ -429,6 +437,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr } }); + // this is outside loop if (!hasEvts) { _inMemoFlushTimer && _inMemoFlushTimer.cancel(); } From 142afabde80b8a876ffc39a9761203fed216d25d Mon Sep 17 00:00:00 2001 From: Karlie Li Date: Tue, 10 Sep 2024 13:28:58 -0700 Subject: [PATCH 7/7] update --- .../Tests/Unit/src/channel.tests.ts | 30 ------ .../offline-channel-js/src/OfflineChannel.ts | 101 +----------------- 2 files changed, 2 insertions(+), 129 deletions(-) diff --git a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts index 56861dd32..63b97d9d7 100644 --- a/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/channel.tests.ts @@ -97,9 +97,6 @@ export class ChannelTests extends AITestClass { let inMemoBatch = inMemoMap[key]; Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); }); - - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); @@ -149,8 +146,6 @@ export class ChannelTests extends AITestClass { let inMemoBatch = inMemoMap[key]; Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); }); - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); @@ -215,15 +210,12 @@ export class ChannelTests extends AITestClass { let inMemoBatch = inMemoMap[EventPersistence.Normal]; - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "online should process next"); Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); Assert.equal(this.batchDrop, 0, "batch drop listener notification should not be called"); offlineListener.setOnlineState(2); channel.processTelemetry(evt); - // inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process"); @@ -231,7 +223,6 @@ export class ChannelTests extends AITestClass { this.clock.tick(2000); inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); let storage = AITestClass.orgLocalStorage; let storageKey = "AIOffline_1_dc.services.visualstudio.com"; @@ -254,8 +245,6 @@ export class ChannelTests extends AITestClass { evts = storageObj.evts; Assert.deepEqual(Object.keys(evts).length, 0, "storage should not have one event"); let request = requests[0]; - this.sendJsonResponse(request, {}, 200); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in memo should not have item"); @@ -468,22 +457,17 @@ export class ChannelTests extends AITestClass { Assert.equal(inMemoBatch.count(), 0, key + " in memo batch should exist"); }); - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "online should process next"); - let inMemoBatch = inMemoMap[EventPersistence.Normal]; offlineListener.setOnlineState(2); channel.processTelemetry(evt); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process"); this.clock.tick(2000); inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 0, "provider should store item"); this.clock.tick(10); @@ -570,7 +554,6 @@ export class ChannelTests extends AITestClass { Assert.deepEqual(mapKeys.length, this.levelKeys.length, "in memo map should have expected keys"); Assert.ok(inMemoMap, "inMemoMap should exist"); let inMemoBatch = inMemoMap[EventPersistence.Normal]; - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; Assert.equal(inMemoBatch.count(), 1, "online should process evt1"); @@ -740,7 +723,6 @@ export class ChannelTests extends AITestClass { this.clock.tick(1); let inMemoMap = channel["_getDbgPlgTargets"]()[1]; let inMemoBatch = inMemoMap[EventPersistence.Normal]; - //let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; this.sandbox.stub((inMemoBatch) as any, "addEvent").callsFake((evt) => { return false; }); @@ -757,7 +739,6 @@ export class ChannelTests extends AITestClass { let evt = mockTelemetryItem(); channel.processTelemetry(evt); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "should not process evt"); @@ -822,9 +803,6 @@ export class ChannelTests extends AITestClass { let inMemoBatch = inMemoMap[EventPersistence.Normal]; - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); - Assert.equal(this.evtDiscard, 0, "discard listener notification should not be called"); Assert.equal(this.evtStore, 0, "store listener notification should not be called"); Assert.equal(this.evtSent, 0, "sent listener notification should not be called"); @@ -837,13 +815,11 @@ export class ChannelTests extends AITestClass { let evt = mockTelemetryItem(); channel.processTelemetry(evt); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); this.clock.tick(300); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 0, "in Memo should have no events remaining"); @@ -897,15 +873,12 @@ export class ChannelTests extends AITestClass { let inMemoBatch = inMemoMap[EventPersistence.Normal]; - // let inMemoBatch = channel["_getDbgPlgTargets"]()[1]; - // Assert.equal(inMemoBatch.count(), 0, "in memo has no events"); let config = channel["_getDbgPlgTargets"]()[0]; Assert.ok(config, "should have config"); Assert.equal(config.url, DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH, "should have expected url"); let evt = mockTelemetryItem(); channel.processTelemetry(evt); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "offline should process evt"); @@ -916,7 +889,6 @@ export class ChannelTests extends AITestClass { this.core.config.endpointUrl = expectedUrl; this.core.config.instrumentationKey = "test1"; this.clock.tick(1); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); @@ -931,7 +903,6 @@ export class ChannelTests extends AITestClass { this.core.config.instrumentationKey = "test2"; this.core.config.endpointUrl = expectedUrl1; this.clock.tick(1); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); @@ -948,7 +919,6 @@ export class ChannelTests extends AITestClass { this.core.config.endpointUrl = expectedUrl2; this.core.config.extensionConfig[sendChannel.identifier].endpointUrl = expectedUrl2; this.clock.tick(1); - //inMemoBatch = channel["_getDbgPlgTargets"]()[1]; inMemoMap = channel["_getDbgPlgTargets"]()[1]; inMemoBatch = inMemoMap[EventPersistence.Normal]; Assert.equal(inMemoBatch.count(), 1, "in memo has one events"); diff --git a/channels/offline-channel-js/src/OfflineChannel.ts b/channels/offline-channel-js/src/OfflineChannel.ts index 1a7e4b28d..cebb6211d 100644 --- a/channels/offline-channel-js/src/OfflineChannel.ts +++ b/channels/offline-channel-js/src/OfflineChannel.ts @@ -82,7 +82,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // Internal properties used for tracking the current state, these are "true" internal/private properties for this instance let _hasInitialized; let _paused; - //let _inMemoBatch: InMemoryBatch; let _sender: Sender; let _urlCfg: IUrlLocalStorageConfig; let _offlineListener: IOfflineListener; @@ -189,7 +188,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr if (_overrideIkey) { item.iKey = _overrideIkey; } - //let added = _inMemoBatch.addEvent(evt); let added = _addEvtToMap(item); // inMemo is full if (!added) { @@ -248,9 +246,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr while (_hasEvts()) { _flushInMemoItems(true); } - // while (_inMemoBatch && _inMemoBatch.count()) { - // _flushInMemoItems(true); - // } // TODO: unloadprovider might send events out of order } }; @@ -293,7 +288,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _offlineListener = null; _diagLogger = null; _endpoint = null; - //_inMemoBatch = null; _convertUndefined = undefValue; _maxBatchSize = null; _sendNextBatchTimer = null; @@ -328,11 +322,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr let hasEvts = _hasEvts(); if (hasEvts && _inMemoFlushTimer) { _inMemoFlushTimer.refresh(); - } - // if (_inMemoBatch && _inMemoBatch.count() && _inMemoFlushTimer) { - // _inMemoFlushTimer.refresh(); - // } _setSendNextTimer(); }, _inMemoTimerOut); @@ -344,8 +334,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr } //flush only flush max batch size event, may still have events lefts - // ********************************************************************************** - // do you need to add function to flush each individual batch (for addevent process) function _flushInMemoItems(unload?: boolean, mapKey?: number | EventPersistence) { try { // TODO: add while loop to flush everything @@ -362,7 +350,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // if split evts is set to true // specific mapkey is defined // for key !== mapkey, only check if there are any events left in order to refresh timer - hasEvts = !!evts.length; + hasEvts = hasEvts || !!evts.length; return; } let payloadArr:string[] = []; @@ -393,7 +381,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr // keep track if there is any remaining events hasEvts = true; } - _inMemoMap[key] = inMemoBatch.createNew(_endpoint, inMemo.getItems().slice(idx + 1), _evtsLimitInMemo); + _inMemoMap[key] = inMemoBatch.createNew(_endpoint, arrSlice(inMemo.getItems(),idx + 1), _evtsLimitInMemo); let payloadData: IStorageTelemetryItem = null; if (_offineSupport && _offineSupport.createOneDSPayload) { @@ -442,83 +430,6 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr _inMemoFlushTimer && _inMemoFlushTimer.cancel(); } - - // let inMemo = inMemoBatch; - // let evts = inMemo && inMemo.getItems(); - // if (!evts || !evts.length) { - // return; - // } - // let payloadArr:string[] = []; - // let size = 0; - // let idx = -1; - // let criticalCnt = 0; - // arrForEach(evts, (evt, index) => { - // let curEvt = evt as IPostTransmissionTelemetryItem - // idx = index; - // let payload = _getPayload(curEvt); - // size += payload.length; - // if (size > _maxBatchSize) { - // return; - // } - // if(curEvt.persistence == EventPersistence.Critical) { - // criticalCnt ++; - // } - // idx = index; - // payloadArr.push(payload); - - // }); - // if (!payloadArr.length) { - // return; - // } - - // let sentItems = evts.slice(0, idx + 1); - // inMemoBatch = inMemoBatch.createNew(_endpoint, inMemo.getItems().slice(idx + 1), _evtsLimitInMemo); - - // let payloadData: IStorageTelemetryItem = null; - // if (_offineSupport && _offineSupport.createOneDSPayload) { - // payloadData = _offineSupport.createOneDSPayload(sentItems); - // if (payloadData) { - // payloadData.criticalCnt = criticalCnt; - // } - - // } else { - // payloadData = _constructPayloadData(payloadArr, criticalCnt); - // } - - - // let callback: OfflineBatchStoreCallback = (res) => { - // if (!res || !res.state) { - // return null; - // } - // let state = res.state; - - // if (state == eBatchStoreStatus.Failure) { - // if (!unload) { - // // for unload, just try to add each batch once - // arrForEach(sentItems, (item) => { - // inMemoBatch.addEvent(item); - // }); - // _setupInMemoTimer(); - - // } else { - // // unload, drop events - // _evtDropNotification(sentItems, EventsDiscardedReason.NonRetryableStatus); - // } - - // } else { - // // if eBatchStoreStatus is success - // _storeNotification(sentItems); - // } - // }; - // if (payloadData && _urlCfg && _urlCfg.batchHandler) { - // let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload); - // _queueStorageEvent("storeBatch", promise); - // } - - // if (_inMemoBatch && !_inMemoBatch.count()) { - // _inMemoFlushTimer && _inMemoFlushTimer.cancel(); - // } - } catch (e) { // eslint-disable-next-line no-empty @@ -760,17 +671,9 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr } newMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); - - //_inMemoMap[key] = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); }); _inMemoMap = newMap; - // let curEvts = _inMemoBatch && _inMemoBatch.getItems(); - // if (curEvts && curEvts.length) { - // evts = curEvts.slice(0); - // _inMemoBatch.clear(); - // } - // _inMemoBatch = new InMemoryBatch(_self.diagLog(), curUrl, evts, _evtsLimitInMemo); _inMemoTimerOut = storageConfig.inMemoMaxTime; let onlineConfig = ctx.getExtCfg(_primaryChannelId, {}) || {}; _convertUndefined = onlineConfig.convertUndefined;