From e7a3d48088e7a5ca357742c54bb9e8f10c3c74d1 Mon Sep 17 00:00:00 2001 From: Nev <54870357+MSNev@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:44:58 -0700 Subject: [PATCH] [release-3.0] [main->cherrypick] [BUG] Excessive memory usage for SPA where unload hooks keep accumulating #2311 (#2312) - Rework Asynchronous notification handling --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 8 +- AISKU/Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + AISKU/Tests/Unit/src/aiskuunittests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/aiskuliteunittests.ts | 2 + .../test/Unit/src/GlobalTestHooks.Test.ts | 13 + .../test/Unit/src/post.unittests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/aichannel.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/teechannel.tests.ts | 2 + common/config/rush/npm-shrinkwrap.json | 318 +++++++++--------- .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Unit/src/appinsights-analytics.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/cfgsync.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../src/appinsights-clickanalytics.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/dependencies.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../src/appinsights-perfmarkmeasure.tests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/prop.tests.ts | 2 + shared/1ds-core-js/src/Index.ts | 5 +- .../test/Unit/src/FileSizeCheckTest.ts | 4 +- .../test/Unit/src/GlobalTestHooks.Test.ts | 13 + .../test/Unit/src/core.unittests.ts | 2 + .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Unit/src/appinsights-common.tests.ts | 2 + .../Unit/src/ApplicationInsightsCore.Tests.ts | 25 +- .../Tests/Unit/src/GlobalTestHooks.Test.ts | 13 + .../Tests/Unit/src/aiunittests.ts | 2 + .../src/Config/DynamicConfig.ts | 2 + .../src/JavaScriptSDK.Enums/LoggingEnums.ts | 1 + .../src/JavaScriptSDK/AppInsightsCore.ts | 105 +++--- .../src/JavaScriptSDK/NotificationManager.ts | 59 +++- .../src/JavaScriptSDK/UnloadHookContainer.ts | 21 ++ .../src/applicationinsights-core-js.ts | 2 +- tools/chrome-debug-extension/manifest.json | 4 +- 41 files changed, 549 insertions(+), 228 deletions(-) create mode 100644 AISKU/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 AISKULight/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 channels/1ds-post-js/test/Unit/src/GlobalTestHooks.Test.ts create mode 100644 channels/applicationinsights-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 channels/offline-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 channels/tee-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-analytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-cfgsync-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-dependencies-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 extensions/applicationinsights-properties-js/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 shared/1ds-core-js/test/Unit/src/GlobalTestHooks.Test.ts create mode 100644 shared/AppInsightsCommon/Tests/Unit/src/GlobalTestHooks.Test.ts create mode 100644 shared/AppInsightsCore/Tests/Unit/src/GlobalTestHooks.Test.ts diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index d211a93b4..f670e0ea0 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -5,10 +5,10 @@ import { Snippet } from "../../../src/Snippet"; import { utlRemoveSessionStorage } from "@microsoft/applicationinsights-common"; export class AISKUSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 135; - private readonly MAX_BUNDLE_SIZE = 135; - private readonly MAX_RAW_DEFLATE_SIZE = 54; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 54; + private readonly MAX_RAW_SIZE = 140; + private readonly MAX_BUNDLE_SIZE = 140; + private readonly MAX_RAW_DEFLATE_SIZE = 56; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 56; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; // Automatically updated by version scripts private readonly currentVer = "3.0.9"; diff --git a/AISKU/Tests/Unit/src/GlobalTestHooks.Test.ts b/AISKU/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/AISKU/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/AISKU/Tests/Unit/src/aiskuunittests.ts b/AISKU/Tests/Unit/src/aiskuunittests.ts index d2056151e..39a168f4e 100644 --- a/AISKU/Tests/Unit/src/aiskuunittests.ts +++ b/AISKU/Tests/Unit/src/aiskuunittests.ts @@ -2,6 +2,7 @@ import { AISKUSizeCheck } from "./AISKUSize.Tests"; import { ApplicationInsightsTests } from './applicationinsights.e2e.tests'; import { ApplicationInsightsFetchTests } from './applicationinsights.e2e.fetch.tests'; import { CdnPackagingChecks } from './CdnPackaging.tests'; +import { GlobalTestHooks } from './GlobalTestHooks.Test'; import { SanitizerE2ETests } from './sanitizer.e2e.tests'; import { ValidateE2ETests } from './validate.e2e.tests'; import { SenderE2ETests } from './sender.e2e.tests'; @@ -10,6 +11,7 @@ import { CdnThrottle} from "./CdnThrottle.tests"; import { ThrottleSentMessage } from "./ThrottleSentMessage.tests"; export function runTests() { + new GlobalTestHooks().registerTests(); new AISKUSizeCheck().registerTests(); new ApplicationInsightsTests().registerTests(); new ApplicationInsightsFetchTests().registerTests(); diff --git a/AISKULight/Tests/Unit/src/GlobalTestHooks.Test.ts b/AISKULight/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/AISKULight/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/AISKULight/Tests/Unit/src/aiskuliteunittests.ts b/AISKULight/Tests/Unit/src/aiskuliteunittests.ts index 8b8a878cc..f1a132879 100644 --- a/AISKULight/Tests/Unit/src/aiskuliteunittests.ts +++ b/AISKULight/Tests/Unit/src/aiskuliteunittests.ts @@ -1,8 +1,10 @@ import { AISKULightSizeCheck } from "./AISKULightSize.Tests"; import { ApplicationInsightsDynamicConfigTests } from "./dynamicconfig.tests"; import { ApplicationInsightsConfigTests } from "./config.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new AISKULightSizeCheck().registerTests(); new ApplicationInsightsDynamicConfigTests().registerTests(); new ApplicationInsightsConfigTests().registerTests(); diff --git a/channels/1ds-post-js/test/Unit/src/GlobalTestHooks.Test.ts b/channels/1ds-post-js/test/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..730f8f2cd --- /dev/null +++ b/channels/1ds-post-js/test/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { _testHookMaxUnloadHooksCb } from "@microsoft/1ds-core-js"; +import { Assert } from "@microsoft/ai-test-framework"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/channels/1ds-post-js/test/Unit/src/post.unittests.ts b/channels/1ds-post-js/test/Unit/src/post.unittests.ts index d4b1b2f91..7ca5a404c 100644 --- a/channels/1ds-post-js/test/Unit/src/post.unittests.ts +++ b/channels/1ds-post-js/test/Unit/src/post.unittests.ts @@ -3,8 +3,10 @@ import { HttpManagerTest } from './HttpManagerTest'; import { KillSwitchTest } from './KillSwitchTest'; import { SerializerTest } from './SerializerTest'; import { FileSizeCheckTest } from "./FileSizeCheckTest" +import { GlobalTestHooks } from './GlobalTestHooks.Test'; export function registerTests() { + new GlobalTestHooks().registerTests(); new PostChannelTest("PostChannelTest").registerTests(); new HttpManagerTest("HttpManagerTest").registerTests(); new HttpManagerTest("HttpManagerTest", true).registerTests(); diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts index 807b0d875..b4dd43ee5 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts @@ -1,7 +1,9 @@ import { SenderTests } from "./Sender.tests"; import { SampleTests } from "./Sample.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new SenderTests().registerTests(); new SampleTests().registerTests(); } \ No newline at end of file diff --git a/channels/offline-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/channels/offline-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/channels/offline-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/channels/tee-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/channels/tee-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/channels/tee-channel-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/channels/tee-channel-js/Tests/Unit/src/teechannel.tests.ts b/channels/tee-channel-js/Tests/Unit/src/teechannel.tests.ts index 5ccef728d..0b215eedc 100644 --- a/channels/tee-channel-js/Tests/Unit/src/teechannel.tests.ts +++ b/channels/tee-channel-js/Tests/Unit/src/teechannel.tests.ts @@ -1,5 +1,7 @@ import { TeeChannelCoreTests } from "./TeeChannelCore.Tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new TeeChannelCoreTests().registerTests(); } \ No newline at end of file diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 222c9233f..546be511d 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -111,13 +111,14 @@ } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -294,9 +295,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@microsoft/api-extractor": { - "version": "7.42.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.42.3.tgz", - "integrity": "sha512-JNLJFpGHz6ekjS6bvYXxUBeRGnSHeCMFNvRbCQ+7XXB/ZFrgLSMPwWtEq40AiWAy+oyG5a4RSNwdJTp0B2USvQ==", + "version": "7.43.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", + "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", "dependencies": { "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", @@ -310,7 +311,7 @@ "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", - "typescript": "5.3.3" + "typescript": "5.4.2" }, "bin": { "api-extractor": "bin/api-extractor" @@ -327,9 +328,9 @@ } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -414,9 +415,9 @@ } }, "node_modules/@nevware21/ts-utils": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.10.5.tgz", - "integrity": "sha512-+TEvP0+l/VBR5bJZoYFV+o6aQQ1O6y80uys5AVyyCKeWvrgWu/yNydqSBQNsk4BuEfkayg7R9+HCJRRRIvptTA==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.0.tgz", + "integrity": "sha512-3yrohCSKYBLKrW41fYkZorN2rf9GYr/4Cb4Xu9fWCyXgVDyt1uLgMaCinhx0kEkEUfME3Smqs+2itJRhXgCo8Q==" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -1460,9 +1461,9 @@ "integrity": "sha512-gVB+rxvxmbyPFWa6yjjKgcumWal3hyqoTXI0Oil161uWfo1OCzWZ/rnEumsx+6uVgrwPrCrhpQbLkzfildkSbg==" }, "node_modules/@types/react": { - "version": "16.14.57", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.57.tgz", - "integrity": "sha512-fuNq/GV1a6GgqSuVuC457vYeTbm4E1CUBQVZwSPxqYnRhIzSXCJ1gGqyv+PKhqLyfbKCga9dXHJDzv+4XE41fw==", + "version": "16.14.59", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.59.tgz", + "integrity": "sha512-tOV7Za9TpBGi0jyi/fjsUmuFM1svfInVsBCkpQcwNDkVL8MEN1aV3FxjI4wYaASMlVE6NZXXx06zaN4rtRPwyQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1516,16 +1517,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", - "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz", + "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/type-utils": "7.2.0", - "@typescript-eslint/utils": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/type-utils": "7.3.1", + "@typescript-eslint/utils": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1534,7 +1535,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1551,19 +1552,19 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", - "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1579,16 +1580,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", - "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0" + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1596,18 +1597,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", - "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1623,12 +1624,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", - "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", "peer": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1636,13 +1637,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", - "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1651,7 +1652,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1688,21 +1689,21 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", - "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1713,16 +1714,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", - "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", "peer": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/types": "7.3.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -2151,9 +2152,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001597", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", - "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", "funding": [ { "type": "opencollective", @@ -2547,9 +2548,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.702", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.702.tgz", - "integrity": "sha512-LYLXyEUsZ3nNSwiOWjI88N1PJUAMU2QphQSgGLVkFnb3FxZxNui2Vzi2PaKPgPWbsWbZstZnh6BMf/VQJamjiQ==" + "version": "1.4.713", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.713.tgz", + "integrity": "sha512-vDarADhwntXiULEdmWd77g2dV6FrNGa8ecAC29MZ4TwPut2fvosD0/5sJd1qWNNe8HcJFAC+F5Lf9jW1NPtWmw==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -3484,7 +3485,7 @@ "version": "9.1.1", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz", "integrity": "sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==", - "deprecated": "< 21.5.0 is no longer supported", + "deprecated": "< 21.8.0 is no longer supported", "hasInstallScript": true, "dependencies": { "debug": "^4.1.0", @@ -4758,9 +4759,9 @@ } }, "node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4853,6 +4854,11 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" }, + "node_modules/postcss/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4901,7 +4907,7 @@ "version": "19.2.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.2.0.tgz", "integrity": "sha512-rhr5ery8htpOTikmm/wrDU707wtmJ7ccX2WLkBf0A8eYYpscck5/iz04/fHOiIRWMFfnYOvaO9wNb4jcO3Mjyg==", - "deprecated": "< 21.5.0 is no longer supported", + "deprecated": "< 21.8.0 is no longer supported", "hasInstallScript": true, "dependencies": { "cosmiconfig": "7.0.1", @@ -6029,11 +6035,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/update-browserslist-db/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6276,13 +6277,14 @@ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "requires": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "dependencies": { "ansi-styles": { @@ -6414,9 +6416,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@microsoft/api-extractor": { - "version": "7.42.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.42.3.tgz", - "integrity": "sha512-JNLJFpGHz6ekjS6bvYXxUBeRGnSHeCMFNvRbCQ+7XXB/ZFrgLSMPwWtEq40AiWAy+oyG5a4RSNwdJTp0B2USvQ==", + "version": "7.43.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.43.0.tgz", + "integrity": "sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==", "requires": { "@microsoft/api-extractor-model": "7.28.13", "@microsoft/tsdoc": "0.14.2", @@ -6430,13 +6432,13 @@ "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", - "typescript": "5.3.3" + "typescript": "5.4.2" }, "dependencies": { "typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==" + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==" } } }, @@ -6508,9 +6510,9 @@ } }, "@nevware21/ts-utils": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.10.5.tgz", - "integrity": "sha512-+TEvP0+l/VBR5bJZoYFV+o6aQQ1O6y80uys5AVyyCKeWvrgWu/yNydqSBQNsk4BuEfkayg7R9+HCJRRRIvptTA==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.0.tgz", + "integrity": "sha512-3yrohCSKYBLKrW41fYkZorN2rf9GYr/4Cb4Xu9fWCyXgVDyt1uLgMaCinhx0kEkEUfME3Smqs+2itJRhXgCo8Q==" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -7446,9 +7448,9 @@ "integrity": "sha512-gVB+rxvxmbyPFWa6yjjKgcumWal3hyqoTXI0Oil161uWfo1OCzWZ/rnEumsx+6uVgrwPrCrhpQbLkzfildkSbg==" }, "@types/react": { - "version": "16.14.57", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.57.tgz", - "integrity": "sha512-fuNq/GV1a6GgqSuVuC457vYeTbm4E1CUBQVZwSPxqYnRhIzSXCJ1gGqyv+PKhqLyfbKCga9dXHJDzv+4XE41fw==", + "version": "16.14.59", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.59.tgz", + "integrity": "sha512-tOV7Za9TpBGi0jyi/fjsUmuFM1svfInVsBCkpQcwNDkVL8MEN1aV3FxjI4wYaASMlVE6NZXXx06zaN4rtRPwyQ==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -7502,16 +7504,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", - "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz", + "integrity": "sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==", "peer": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/type-utils": "7.2.0", - "@typescript-eslint/utils": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/type-utils": "7.3.1", + "@typescript-eslint/utils": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7521,54 +7523,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", - "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.3.1.tgz", + "integrity": "sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==", "peer": true, "requires": { - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", - "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz", + "integrity": "sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==", "peer": true, "requires": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0" + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1" } }, "@typescript-eslint/type-utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", - "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz", + "integrity": "sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==", "peer": true, "requires": { - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/typescript-estree": "7.3.1", + "@typescript-eslint/utils": "7.3.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", - "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.3.1.tgz", + "integrity": "sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==", "peer": true }, "@typescript-eslint/typescript-estree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", - "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz", + "integrity": "sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==", "peer": true, "requires": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/visitor-keys": "7.3.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7598,27 +7600,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", - "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.3.1.tgz", + "integrity": "sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==", "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/scope-manager": "7.3.1", + "@typescript-eslint/types": "7.3.1", + "@typescript-eslint/typescript-estree": "7.3.1", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", - "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz", + "integrity": "sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==", "peer": true, "requires": { - "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/types": "7.3.1", "eslint-visitor-keys": "^3.4.1" } }, @@ -7917,9 +7919,9 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "caniuse-lite": { - "version": "1.0.30001597", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", - "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==" + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==" }, "chalk": { "version": "4.1.2", @@ -8209,9 +8211,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.702", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.702.tgz", - "integrity": "sha512-LYLXyEUsZ3nNSwiOWjI88N1PJUAMU2QphQSgGLVkFnb3FxZxNui2Vzi2PaKPgPWbsWbZstZnh6BMf/VQJamjiQ==" + "version": "1.4.713", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.713.tgz", + "integrity": "sha512-vDarADhwntXiULEdmWd77g2dV6FrNGa8ecAC29MZ4TwPut2fvosD0/5sJd1qWNNe8HcJFAC+F5Lf9jW1NPtWmw==" }, "encodeurl": { "version": "1.0.2", @@ -9893,9 +9895,9 @@ "integrity": "sha512-L7MXxUDtqr4PUaLFCDCXBfGV/6KLIuSEccizDI7JxT+c9x1G1v04BQ4+4oag84SHaCdrBgQAIs/Cqn+flwFPng==" }, "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { "version": "2.3.1", @@ -9952,6 +9954,13 @@ "requires": { "picocolors": "^0.2.1", "source-map": "^0.6.1" + }, + "dependencies": { + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + } } }, "postcss-value-parser": { @@ -10813,13 +10822,6 @@ "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" - }, - "dependencies": { - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - } } }, "uri-js": { diff --git a/extensions/applicationinsights-analytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-analytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-analytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-analytics-js/Tests/Unit/src/appinsights-analytics.tests.ts b/extensions/applicationinsights-analytics-js/Tests/Unit/src/appinsights-analytics.tests.ts index ae3bb504c..3e4b83ca7 100644 --- a/extensions/applicationinsights-analytics-js/Tests/Unit/src/appinsights-analytics.tests.ts +++ b/extensions/applicationinsights-analytics-js/Tests/Unit/src/appinsights-analytics.tests.ts @@ -1,8 +1,10 @@ import { AnalyticsPluginTests } from './AnalyticsPlugin.tests'; import { TelemetryItemCreatorTests } from './TelemetryItemCreator.tests'; import { AnalyticsExtensionSizeCheck } from "./AnalyticsExtensionSize.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new AnalyticsPluginTests().registerTests(); new TelemetryItemCreatorTests().registerTests(); new AnalyticsExtensionSizeCheck().registerTests(); diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsync.tests.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsync.tests.ts index 92792bdcf..4afb1b311 100644 --- a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsync.tests.ts +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsync.tests.ts @@ -1,7 +1,9 @@ import { CfgSyncHelperTests } from "./cfgsynchelper.tests"; import {CfgSyncPluginTests} from "./cfgsyncplugin.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new CfgSyncPluginTests().registerTests(); new CfgSyncHelperTests().registerTests(); } diff --git a/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/appinsights-clickanalytics.tests.ts b/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/appinsights-clickanalytics.tests.ts index 04374873b..ce06a18ae 100644 --- a/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/appinsights-clickanalytics.tests.ts +++ b/extensions/applicationinsights-clickanalytics-js/Tests/Unit/src/appinsights-clickanalytics.tests.ts @@ -1,5 +1,7 @@ import { ClickEventTest } from './ClickEventTest'; +import { GlobalTestHooks } from './GlobalTestHooks.Test'; export function runTests() { + new GlobalTestHooks().registerTests(); new ClickEventTest().registerTests(); } diff --git a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/dependencies.tests.ts b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/dependencies.tests.ts index 3938bebb8..386bbfb16 100644 --- a/extensions/applicationinsights-dependencies-js/Tests/Unit/src/dependencies.tests.ts +++ b/extensions/applicationinsights-dependencies-js/Tests/Unit/src/dependencies.tests.ts @@ -1,6 +1,8 @@ import { AjaxTests, AjaxPerfTrackTests, AjaxFrozenTests } from "./ajax.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new AjaxTests().registerTests(); new AjaxPerfTrackTests().registerTests(); new AjaxFrozenTests().registerTests(); diff --git a/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/appinsights-perfmarkmeasure.tests.ts b/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/appinsights-perfmarkmeasure.tests.ts index 5a2d0c191..a5d266f63 100644 --- a/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/appinsights-perfmarkmeasure.tests.ts +++ b/extensions/applicationinsights-perfmarkmeasure-js/Tests/Unit/src/appinsights-perfmarkmeasure.tests.ts @@ -1,5 +1,7 @@ import { MarkMeasureTests } from './MarkMeasureTests'; +import { GlobalTestHooks } from './GlobalTestHooks.Test'; export function runTests() { + new GlobalTestHooks().registerTests(); new MarkMeasureTests().registerTests(); } diff --git a/extensions/applicationinsights-properties-js/Tests/Unit/src/GlobalTestHooks.Test.ts b/extensions/applicationinsights-properties-js/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/extensions/applicationinsights-properties-js/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/extensions/applicationinsights-properties-js/Tests/Unit/src/prop.tests.ts b/extensions/applicationinsights-properties-js/Tests/Unit/src/prop.tests.ts index b81d1977e..be2a55a3f 100644 --- a/extensions/applicationinsights-properties-js/Tests/Unit/src/prop.tests.ts +++ b/extensions/applicationinsights-properties-js/Tests/Unit/src/prop.tests.ts @@ -3,8 +3,10 @@ import { PropertiesTests } from "./properties.tests"; import { SessionManagerTests } from "./SessionManager.Tests"; import { PropertiesExtensionSizeCheck } from "./propertiesSize.tests"; import { TelemetryContextTests } from "./TelemetryContext.Tests"; +import { GlobalTestHooks } from './GlobalTestHooks.Test'; export function runTests() { + new GlobalTestHooks().registerTests(); new PropertiesTests().registerTests(); new SessionManagerTests(false).registerTests(); new SessionManagerTests(true).registerTests(); diff --git a/shared/1ds-core-js/src/Index.ts b/shared/1ds-core-js/src/Index.ts index be973c9b9..ace9ce569 100644 --- a/shared/1ds-core-js/src/Index.ts +++ b/shared/1ds-core-js/src/Index.ts @@ -67,7 +67,10 @@ export { IConfigCheckFn, IConfigDefaultCheck, IConfigDefaults, IConfigSetFn, IDynamicConfigHandler, IDynamicPropertyHandler, IWatchDetails, IWatcherHandler, WatcherFunction, createDynamicConfig, onConfigChange, getDynamicConfigHandler, blockDynamicConversion, forceDynamicConversion, - IPayloadData, IXHROverride, OnCompleteCallback, SendPOSTFunction + IPayloadData, IXHROverride, OnCompleteCallback, SendPOSTFunction, + + // Test Hooks + _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; export { diff --git a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts index 5f7c0839d..2e1f35752 100644 --- a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts +++ b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts @@ -2,8 +2,8 @@ import { AITestClass } from "@microsoft/ai-test-framework"; import * as pako from 'pako'; export class FileSizeCheckTest extends AITestClass { - private readonly MAX_BUNDLE_SIZE = 60; - private readonly MAX_DEFLATE_SIZE = 26; + private readonly MAX_BUNDLE_SIZE = 66; + private readonly MAX_DEFLATE_SIZE = 28; private readonly bundleFilePath = "../bundle/es5/ms.core.min.js"; public testInitialize() { diff --git a/shared/1ds-core-js/test/Unit/src/GlobalTestHooks.Test.ts b/shared/1ds-core-js/test/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/shared/1ds-core-js/test/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/shared/1ds-core-js/test/Unit/src/core.unittests.ts b/shared/1ds-core-js/test/Unit/src/core.unittests.ts index 727a0db05..faa21219d 100644 --- a/shared/1ds-core-js/test/Unit/src/core.unittests.ts +++ b/shared/1ds-core-js/test/Unit/src/core.unittests.ts @@ -5,10 +5,12 @@ import { DynamicProtoTests } from './DynamicProtoTests'; import { UtilsTest } from './UtilsTest'; import { ValueSanitizerTests } from './ValueSanitizerTests'; import {FileSizeCheckTest} from './FileSizeCheckTest' +import { GlobalTestHooks } from './GlobalTestHooks.Test'; export function registerTests() { + new GlobalTestHooks().registerTests(); new CoreTest('CoreTest').registerTests(); new ESPromiseTests('ESPromiseTests').registerTests(); new ESPromiseSchedulerTests('ESPromiseSchedulerTests').registerTests(); diff --git a/shared/AppInsightsCommon/Tests/Unit/src/GlobalTestHooks.Test.ts b/shared/AppInsightsCommon/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..b67bf2fe7 --- /dev/null +++ b/shared/AppInsightsCommon/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "@microsoft/applicationinsights-core-js"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/shared/AppInsightsCommon/Tests/Unit/src/appinsights-common.tests.ts b/shared/AppInsightsCommon/Tests/Unit/src/appinsights-common.tests.ts index a05ddf193..f9ef32c0d 100644 --- a/shared/AppInsightsCommon/Tests/Unit/src/appinsights-common.tests.ts +++ b/shared/AppInsightsCommon/Tests/Unit/src/appinsights-common.tests.ts @@ -5,8 +5,10 @@ import { ConnectionStringParserTests } from "./ConnectionStringParser.tests"; import { SeverityLevelTests } from "./SeverityLevel.tests"; import { RequestHeadersTests } from "./RequestHeaders.tests"; import { ThrottleMgrTest } from "./ThrottleMgr.tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; export function runTests() { + new GlobalTestHooks().registerTests(); new ThrottleMgrTest().registerTests(); new ApplicationInsightsTests().registerTests(); new ExceptionTests().registerTests(); diff --git a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts index 16a1c62f7..9865cf02e 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/ApplicationInsightsCore.Tests.ts @@ -19,7 +19,6 @@ export class ApplicationInsightsCoreTests extends AITestClass { } public registerTests() { - this.testCase({ name: "ApplicationInsightsCore: Initialization validates input", test: () => { @@ -849,6 +848,30 @@ export class ApplicationInsightsCoreTests extends AITestClass { } }); + this.testCase({ + name: 'Test Excessive unload hook detection - make sure calling getPerfMgr() does not cause excessive unload hook detection', + test: () => { + const appInsightsCore = new AppInsightsCore(); + const channelPlugin1 = new ChannelPlugin(); + channelPlugin1.priority = 1001; + + const theConfig = { + channels: [[channelPlugin1]], + endpointUrl: "https://dc.services.visualstudio.com/v2/track", + instrumentationKey: "", + extensionConfig: {} + }; + + appInsightsCore.initialize(theConfig, []); + Assert.equal(true, appInsightsCore.isInitialized(), "Core is initialized"); + + // Send lots of notifications + for (let lp = 0; lp < 100; lp++) { + Assert.equal(null, appInsightsCore.getPerfMgr()); + } + } + }); + function _createBuckets(num: number) { // Using helper function as TypeScript 2.5.3 is complaining about new Array(100).fill(0); let buckets: number[] = []; diff --git a/shared/AppInsightsCore/Tests/Unit/src/GlobalTestHooks.Test.ts b/shared/AppInsightsCore/Tests/Unit/src/GlobalTestHooks.Test.ts new file mode 100644 index 000000000..99e370c4a --- /dev/null +++ b/shared/AppInsightsCore/Tests/Unit/src/GlobalTestHooks.Test.ts @@ -0,0 +1,13 @@ +import { Assert } from "@microsoft/ai-test-framework"; +import { _testHookMaxUnloadHooksCb } from "../../../src/JavaScriptSDK/UnloadHookContainer"; +import { dumpObj } from "@nevware21/ts-utils"; + +export class GlobalTestHooks { + + public registerTests() { + // Set a global maximum + _testHookMaxUnloadHooksCb(20, (state: string, hooks: Array) => { + Assert.ok(false, "Max unload hooks exceeded [" + hooks.length + "] - " + state + " - " + dumpObj(hooks)); + }); + } +} diff --git a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts index bf7b3a679..6fc31aebc 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts @@ -1,6 +1,7 @@ import '@microsoft/applicationinsights-shims'; import { ApplicationInsightsCoreTests } from "./ApplicationInsightsCore.Tests"; import { CookieManagerTests } from "./CookieManager.Tests"; +import { GlobalTestHooks } from "./GlobalTestHooks.Test"; import { HelperFuncTests } from './HelperFunc.Tests'; import { AppInsightsCoreSizeCheck } from "./AppInsightsCoreSize.Tests"; import { EventHelperTests } from "./EventHelper.Tests"; @@ -12,6 +13,7 @@ import { W3cTraceParentTests } from "./W3cTraceParentTests"; import { DynamicConfigTests } from "./DynamicConfig.Tests"; export function runTests() { + new GlobalTestHooks().registerTests(); new DynamicTests().registerTests(); new DynamicConfigTests().registerTests(); new ApplicationInsightsCoreTests().registerTests(); diff --git a/shared/AppInsightsCore/src/Config/DynamicConfig.ts b/shared/AppInsightsCore/src/Config/DynamicConfig.ts index ba5b4c8af..c10a85350 100644 --- a/shared/AppInsightsCore/src/Config/DynamicConfig.ts +++ b/shared/AppInsightsCore/src/Config/DynamicConfig.ts @@ -36,6 +36,8 @@ function _createAndUseHandler(state: _IDynamicConfigHandlerState, configHa } }; + objDefine(handler, "toJSON", { v: () => "WatcherHandler" + (handler.fn ? "" : "[X]") }); + state.use(handler, configHandler); return handler; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts index 5906bcd04..abe98b4c0 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Enums/LoggingEnums.ts @@ -84,6 +84,7 @@ export const enum _eInternalMessageId { InvalidDurationValue = 45, TelemetryEnvelopeInvalid = 46, CreateEnvelopeError = 47, + MaxUnloadHookExceeded = 48, // User actionable CannotSerializeObject = 48, diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index aa7dbb85d..c0ef2bc4d 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -181,7 +181,7 @@ function _addDelayedCfgListener(listeners: { rm: () => void, w: WatcherFunction< let theListener = _findWatcher(listeners, newWatcher).l; if (!theListener) { - theListener ={ + theListener = { w: newWatcher, rm: () => { let fnd = _findWatcher(listeners, newWatcher); @@ -207,6 +207,36 @@ function _registerDelayedCfgListener(config: IConfiguration, listeners: { rm: () }); } +// Moved this outside of the closure to reduce the retained memory footprint +function _initDebugListener(configHandler: IDynamicConfigHandler, unloadContainer: IUnloadHookContainer, notificationManager: INotificationManager, debugListener: INotificationListener) { + // Will get recalled if any referenced config values are changed + unloadContainer.add(configHandler.watch((details) => { + let disableDbgExt = details.cfg.disableDbgExt; + + if (disableDbgExt === true && debugListener) { + // Remove any previously loaded debug listener + notificationManager.removeNotificationListener(debugListener); + debugListener = null; + } + + if (notificationManager && !debugListener && disableDbgExt !== true) { + debugListener = getDebugListener(details.cfg); + notificationManager.addNotificationListener(debugListener); + } + })); + + return debugListener +} + +// Moved this outside of the closure to reduce the retained memory footprint +function _createUnloadHook(unloadHook: IUnloadHook): IUnloadHook { + return objDefine({ + rm: () => { + unloadHook.rm(); + } + }, "toJSON", { v: () => "aicore::onCfgChange<" + JSON.stringify(unloadHook) + ">" }); +} + /** * @group Classes * @group Entrypoint @@ -317,7 +347,8 @@ export class AppInsightsCore im _notificationManager = notificationManager; - _initDebugListener(); + // Initialize the debug listener outside of the closure to reduce the retained memory footprint + _debugListener = _initDebugListener(_configHandler, _hookContainer, _notificationManager && _self.getNotifyMgr(), _debugListener); _initPerfManager(); _self.logger = logger; @@ -444,17 +475,6 @@ export class AppInsightsCore im }; _self.getPerfMgr = (): IPerfManager => { - if (!_perfManager && !_cfgPerfManager) { - _addUnloadHook(_configHandler.watch((details) => { - if (details.cfg.enablePerfMgr) { - let createPerfMgr = details.cfg.createPerfMgr; - if (isFunction(createPerfMgr)) { - _cfgPerfManager = createPerfMgr(_self, _self.getNotifyMgr()); - } - } - })); - } - return _perfManager || _cfgPerfManager || getGblPerfMgr(); }; @@ -726,11 +746,7 @@ export class AppInsightsCore im unloadHook = onConfigChange(_configHandler.cfg, handler, _self.logger); } - return { - rm: () => { - unloadHook.rm(); - } - } + return _createUnloadHook(unloadHook); }; _self.getWParam = () => { @@ -854,6 +870,8 @@ export class AppInsightsCore im _pluginVersionString = null; _pluginVersionStringArr = null; _forceStopInternalLogPoller = false; + _internalLogPoller = null; + _internalLogPollerListening = false; } function _createTelCtx(): IProcessTelemetryContext { @@ -1106,40 +1124,39 @@ export class AppInsightsCore im return true; } - function _initDebugListener() { - // Lazily ensure that the notification manager is created - !_notificationManager && _self.getNotifyMgr(); + function _initPerfManager() { + // Save the previous config based performance manager creator to avoid creating new perf manager instances if unchanged + let prevCfgPerfMgr: (core: IAppInsightsCore, notificationManager: INotificationManager) => IPerfManager; // Will get recalled if any referenced config values are changed _addUnloadHook(_configHandler.watch((details) => { - let disableDbgExt = details.cfg.disableDbgExt; + let enablePerfMgr = details.cfg.enablePerfMgr; + if (enablePerfMgr) { + let createPerfMgr = details.cfg.createPerfMgr; + if (prevCfgPerfMgr !== createPerfMgr) { + if (!createPerfMgr) { + createPerfMgr = _createPerfManager; + } - if (disableDbgExt === true && _debugListener) { - // Remove any previously loaded debug listener - _notificationManager.removeNotificationListener(_debugListener); - _debugListener = null; - } - - if (_notificationManager && !_debugListener && disableDbgExt !== true) { - _debugListener = getDebugListener(details.cfg); - _notificationManager.addNotificationListener(_debugListener); - } - })); - } + // Set the performance manager creation function if not defined + getSetValue(details.cfg, STR_CREATE_PERF_MGR, createPerfMgr); + prevCfgPerfMgr = createPerfMgr; - function _initPerfManager() { - // Will get recalled if any referenced config values are changed - _addUnloadHook(_configHandler.watch((details) => { - let enablePerfMgr = details.cfg.enablePerfMgr; + // Remove any existing config based performance manager + _cfgPerfManager = null; + } - if (!enablePerfMgr && _cfgPerfManager) { + // Only create the performance manager if it's not already created or manually set + if (!_perfManager && !_cfgPerfManager && isFunction(createPerfMgr)) { + // Create a new config based performance manager + _cfgPerfManager = createPerfMgr(_self, _self.getNotifyMgr()); + } + } else { // Remove any existing config based performance manager _cfgPerfManager = null; - } - - if (enablePerfMgr) { - // Set the performance manager creation function if not defined - getSetValue(details.cfg, STR_CREATE_PERF_MGR, _createPerfManager); + + // Clear the previous cached value so it can be GC'd + prevCfgPerfMgr = null; } })); } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NotificationManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NotificationManager.ts index 2e4377d7b..ef10fe78f 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NotificationManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NotificationManager.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import dynamicProto from "@microsoft/dynamicproto-js"; import { IPromise, createAllPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async"; -import { arrForEach, arrIndexOf, objDefine, scheduleTimeout } from "@nevware21/ts-utils"; +import { ITimerHandler, arrForEach, arrIndexOf, objDefine, safe, scheduleTimeout } from "@nevware21/ts-utils"; import { createDynamicConfig } from "../Config/DynamicConfig"; import { IConfiguration } from "../JavaScriptSDK.Interfaces/IConfiguration"; import { INotificationListener } from "../JavaScriptSDK.Interfaces/INotificationListener"; @@ -16,17 +16,37 @@ const defaultValues = { perfEvtsSendAll: false }; -function _runListeners(listeners: INotificationListener[], name: string, isAsync: boolean, callback: (listener: INotificationListener) => void) { +interface IAsyncNotifications { + h: ITimerHandler; + cb: Array<{ fn: (listener: INotificationListener) => void, arg: INotificationListener }> +} + +function _runScheduledListeners(asyncNotifications: IAsyncNotifications) { + asyncNotifications.h = null; + let callbacks = asyncNotifications.cb; + asyncNotifications.cb = []; + arrForEach(callbacks, (cb) => { + // Run the listener in a try-catch to ensure that a single listener failing doesn't prevent the others from running + safe(cb.fn, [cb.arg]); + }); +} + +// This function is used to combine the logic of running the listeners and handling the async notifications so that they don't +// create multiple timers if there are multiple async listeners. +function _runListeners(listeners: INotificationListener[], name: string, asyncNotifications: IAsyncNotifications | null, callback: (listener: INotificationListener) => void) { arrForEach(listeners, (listener) => { if (listener && listener[name]) { - if (isAsync) { - scheduleTimeout(() => callback(listener), 0); + if (asyncNotifications) { + // Schedule the callback to be called after the current call stack has cleared. + asyncNotifications.cb.push({ + fn: callback, + arg: listener + }); + + asyncNotifications.h = asyncNotifications.h || scheduleTimeout(_runScheduledListeners, 0, asyncNotifications); } else { - try { - callback(listener); - } catch (e) { - // Catch errors to ensure we don't block sending the requests - } + // Run the listener in a try-catch to ensure that a single listener failing doesn't prevent the others from running + safe(callback, [listener]); } } }); @@ -42,7 +62,11 @@ export class NotificationManager implements INotificationManager { let perfEvtsSendAll: boolean; let unloadHandler: IUnloadHook; let _listeners: INotificationListener[] = []; - + let _asyncNotifications: IAsyncNotifications = { + h: null, + cb: [] + }; + let cfgHandler = createDynamicConfig(config, defaultValues); unloadHandler = cfgHandler.watch((details) => { @@ -75,7 +99,7 @@ export class NotificationManager implements INotificationManager { * @param events - The array of events that have been sent. */ _self.eventsSent = (events: ITelemetryItem[]): void => { - _runListeners(_listeners, STR_EVENTS_SENT, true, (listener) => { + _runListeners(_listeners, STR_EVENTS_SENT, _asyncNotifications, (listener) => { listener.eventsSent(events); }); }; @@ -87,7 +111,7 @@ export class NotificationManager implements INotificationManager { * constant should be used to check the different values. */ _self.eventsDiscarded = (events: ITelemetryItem[], reason: number): void => { - _runListeners(_listeners, STR_EVENTS_DISCARDED, true, (listener) => { + _runListeners(_listeners, STR_EVENTS_DISCARDED, _asyncNotifications, (listener) => { listener.eventsDiscarded(events, reason); }); }; @@ -98,7 +122,7 @@ export class NotificationManager implements INotificationManager { * @param isAsync - A flag which identifies whether the requests are being sent in an async or sync manner. */ _self.eventsSendRequest = (sendReason: number, isAsync: boolean): void => { - _runListeners(_listeners, STR_EVENTS_SEND_REQUEST, isAsync, (listener) => { + _runListeners(_listeners, STR_EVENTS_SEND_REQUEST, isAsync ? _asyncNotifications : null, (listener) => { listener.eventsSendRequest(sendReason, isAsync); }); }; @@ -108,7 +132,7 @@ export class NotificationManager implements INotificationManager { // Send all events or only parent events if (perfEvtsSendAll || !perfEvent.isChildEvt()) { - _runListeners(_listeners, STR_PERF_EVENT, false, (listener) => { + _runListeners(_listeners, STR_PERF_EVENT, null, (listener) => { if (perfEvent.isAsync) { scheduleTimeout(() => listener.perfEvent(perfEvent), 0); } else { @@ -125,10 +149,15 @@ export class NotificationManager implements INotificationManager { unloadHandler && unloadHandler.rm(); unloadHandler = null; _listeners = []; + + // Clear any async listener + _asyncNotifications.h && _asyncNotifications.h.cancel(); + _asyncNotifications.h = null; + _asyncNotifications.cb = []; }; let waiting: IPromise[]; - _runListeners(_listeners, "unload", false, (listener) => { + _runListeners(_listeners, "unload", null, (listener) => { let asyncUnload = listener.unload(isAsync); if (asyncUnload) { if (!waiting) { diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/UnloadHookContainer.ts b/shared/AppInsightsCore/src/JavaScriptSDK/UnloadHookContainer.ts index 6afbd7b6b..32895ed0f 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/UnloadHookContainer.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/UnloadHookContainer.ts @@ -7,6 +7,9 @@ import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger import { ILegacyUnloadHook, IUnloadHook } from "../JavaScriptSDK.Interfaces/IUnloadHook"; import { _throwInternal } from "./DiagnosticLogger"; +let _maxHooks: number | undefined; +let _hookAddMonitor: (state: string, hooks: Array) => void | undefined; + /** * Interface which identifiesAdd this hook so that it is automatically removed during unloading * @param hooks - The single hook or an array of IInstrumentHook objects @@ -16,6 +19,17 @@ export interface IUnloadHookContainer { run: (logger?: IDiagnosticLogger) => void; } +/** + * Test hook for setting the maximum number of unload hooks and calling a monitor function when the hooks are added or removed + * This allows for automatic test failure when the maximum number of unload hooks is exceeded + * @param maxHooks - The maximum number of unload hooks + * @param addMonitor - The monitor function to call when hooks are added or removed + */ +export function _testHookMaxUnloadHooksCb(maxHooks?: number, addMonitor?: (state: string, hooks: Array) => void) { + _maxHooks = maxHooks; + _hookAddMonitor = addMonitor; +} + /** * Create a IUnloadHookContainer which can be used to remember unload hook functions to be executed during the component unloading * process. @@ -37,11 +51,18 @@ export function createUnloadHookContainer(): IUnloadHookContainer { _throwInternal(logger, eLoggingSeverity.WARNING, _eInternalMessageId.PluginException, "Unloading:" + dumpObj(e)); } }); + + if (_maxHooks && oldHooks.length > _maxHooks) { + _hookAddMonitor ? _hookAddMonitor("doUnload", oldHooks) : _throwInternal(null, eLoggingSeverity.CRITICAL, _eInternalMessageId.MaxUnloadHookExceeded, "Max unload hooks exceeded. An excessive number of unload hooks has been detected."); + } } function _addHook(hooks: IUnloadHook | IUnloadHook[] | Iterator | ILegacyUnloadHook | ILegacyUnloadHook[] | Iterator) { if (hooks) { arrAppend(_hooks, hooks); + if (_maxHooks && _hooks.length > _maxHooks) { + _hookAddMonitor ? _hookAddMonitor("Add", _hooks) : _throwInternal(null, eLoggingSeverity.CRITICAL, _eInternalMessageId.MaxUnloadHookExceeded, "Max unload hooks exceeded. An excessive number of unload hooks has been detected."); + } } } diff --git a/shared/AppInsightsCore/src/applicationinsights-core-js.ts b/shared/AppInsightsCore/src/applicationinsights-core-js.ts index 781ebac73..926a06b5e 100644 --- a/shared/AppInsightsCore/src/applicationinsights-core-js.ts +++ b/shared/AppInsightsCore/src/applicationinsights-core-js.ts @@ -81,7 +81,7 @@ export { getDebugListener, getDebugExt } from "./JavaScriptSDK/DbgExtensionUtils export { TelemetryInitializerFunction, ITelemetryInitializerHandler, ITelemetryInitializerContainer } from "./JavaScriptSDK.Interfaces/ITelemetryInitializers"; export { createUniqueNamespace } from "./JavaScriptSDK/DataCacheHelper"; export { UnloadHandler, IUnloadHandlerContainer, createUnloadHandlerContainer } from "./JavaScriptSDK/UnloadHandlerContainer"; -export { IUnloadHookContainer, createUnloadHookContainer } from "./JavaScriptSDK/UnloadHookContainer"; +export { IUnloadHookContainer, createUnloadHookContainer, _testHookMaxUnloadHooksCb } from "./JavaScriptSDK/UnloadHookContainer"; export { ITelemetryUpdateState } from "./JavaScriptSDK.Interfaces/ITelemetryUpdateState"; export { ITelemetryUnloadState } from "./JavaScriptSDK.Interfaces/ITelemetryUnloadState"; export { IDistributedTraceContext } from "./JavaScriptSDK.Interfaces/IDistributedTraceContext"; diff --git a/tools/chrome-debug-extension/manifest.json b/tools/chrome-debug-extension/manifest.json index e8c241d10..d9696577d 100644 --- a/tools/chrome-debug-extension/manifest.json +++ b/tools/chrome-debug-extension/manifest.json @@ -2,8 +2,8 @@ "name": "Telemetry Viewer", "short_name": "Telemetry Viewer", "description": "A browser extension that provides a real time view of what's happening in Application Insights including what telemetry is being logged by the web application", - "version": "0.4.8", - "version_name": "0.4.8", + "version": "0.4.9", + "version_name": "0.4.9", "manifest_version": 2, "icons": { "16": "images/icon-16.png",