From 870a7ecf3cd251d88c207d9815c2f16c6e9a6883 Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:21:18 +0530 Subject: [PATCH 01/17] fix: remove data residency feature (#1748) --- .../src/types/DataResidency.ts | 9 - .../src/types/LoadOptions.ts | 2 - .../analytics-js-common/src/types/Source.ts | 3 - .../configManager/ConfigManager.test.ts | 1 - .../configManager/dataPlaneResolver.test.ts | 163 ------------------ .../components/configManager/ConfigManager.ts | 20 +-- .../src/components/configManager/types.ts | 5 - .../configManager/util/dataPlaneResolver.ts | 79 --------- .../analytics-js/src/constants/logMessages.ts | 10 -- packages/analytics-js/src/index.ts | 1 - packages/sanity-suite/.env.example | 5 - .../sanity-suite/src/testBook/TestBook.js | 73 +++++--- 12 files changed, 52 insertions(+), 319 deletions(-) delete mode 100644 packages/analytics-js-common/src/types/DataResidency.ts delete mode 100644 packages/analytics-js/__tests__/components/configManager/dataPlaneResolver.test.ts delete mode 100644 packages/analytics-js/src/components/configManager/util/dataPlaneResolver.ts diff --git a/packages/analytics-js-common/src/types/DataResidency.ts b/packages/analytics-js-common/src/types/DataResidency.ts deleted file mode 100644 index e38fa159f..000000000 --- a/packages/analytics-js-common/src/types/DataResidency.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type RegionDetails = { - url: string; - default: boolean; -}; - -/** - * Represents residency server input the options - */ -export type ResidencyServerRegion = 'US' | 'EU'; diff --git a/packages/analytics-js-common/src/types/LoadOptions.ts b/packages/analytics-js-common/src/types/LoadOptions.ts index 1686ef378..4378f91db 100644 --- a/packages/analytics-js-common/src/types/LoadOptions.ts +++ b/packages/analytics-js-common/src/types/LoadOptions.ts @@ -1,5 +1,4 @@ import type { LogLevel } from './Logger'; -import type { ResidencyServerRegion } from './DataResidency'; import type { Nullable } from './Nullable'; import type { PluginName } from './PluginsManager'; import type { IntegrationOpts } from './Integration'; @@ -132,7 +131,6 @@ export type LoadOptions = { polyfillIfRequired?: boolean; // defaults to true. Controls whether the SDK should polyfill unsupported browser API's if they are detected as missing onLoaded?: OnLoadedCallback; uaChTrackLevel?: UaChTrackLevel; - residencyServer?: ResidencyServerRegion; // TODO: define type for sourceConfig once the trimmed response is implemented getSourceConfig?: () => string | ApiObject | Promise | Promise; sendAdblockPage?: boolean; diff --git a/packages/analytics-js-common/src/types/Source.ts b/packages/analytics-js-common/src/types/Source.ts index 21b1483b4..ec5a8e698 100644 --- a/packages/analytics-js-common/src/types/Source.ts +++ b/packages/analytics-js-common/src/types/Source.ts @@ -1,5 +1,3 @@ -import type { RegionDetails, ResidencyServerRegion } from './DataResidency'; - export type StatsCollection = { errors: { enabled: boolean; @@ -17,6 +15,5 @@ export type SourceConfig = { export type Source = { id: string; config?: SourceConfig; - dataplanes?: Record; workspaceId: string; }; diff --git a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts index 4cf623046..538d62794 100644 --- a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts +++ b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts @@ -172,7 +172,6 @@ describe('ConfigManager', () => { configManagerInstance.processConfig(dummySourceConfigResponse); expect(state.source.value).toStrictEqual(expectedSourceState); - expect(state.lifecycle.activeDataplaneUrl.value).toBe(sampleDataPlaneUrl); expect(state.lifecycle.status.value).toBe('configured'); expect(state.reporting.isErrorReportingEnabled.value).toBe( dummySourceConfigResponse.source.config.statsCollection.errors.enabled, diff --git a/packages/analytics-js/__tests__/components/configManager/dataPlaneResolver.test.ts b/packages/analytics-js/__tests__/components/configManager/dataPlaneResolver.test.ts deleted file mode 100644 index 58fa7878d..000000000 --- a/packages/analytics-js/__tests__/components/configManager/dataPlaneResolver.test.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type { - RegionDetails, - ResidencyServerRegion, -} from '@rudderstack/analytics-js-common/types/DataResidency'; -import { resolveDataPlaneUrl } from '../../../src/components/configManager/util/dataPlaneResolver'; - -const usDataplaneUrl = 'https://sample.rudderlabs.com/us'; -const euDataplaneUrl = 'https://sample.rudderlabs.com/eu'; -const serverUrl = 'https://sample.rudderlabs.com'; - -const sourceConfigWithBothDataPlane: Record = { - US: [ - { - url: usDataplaneUrl, - default: true, - }, - ], - EU: [ - { - url: euDataplaneUrl, - default: true, - }, - ], -}; - -const sourceConfigWithUSDataPlane: Record = { - US: [ - { - url: usDataplaneUrl, - default: true, - }, - ], -}; - -const sourceConfigWithEUDataPlane: Record = { - EU: [ - { - url: euDataplaneUrl, - default: true, - }, - ], -}; -const sourceConfigWithEmptyDataPlanes = undefined; - -const validResidencyServerUS = 'US'; -const validResidencyServerEU = 'EU'; - -const testCaseData = [ - { - description: - 'When dataplane is not provided in source config but provided in load API, dataplane Url from load option will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - serverUrl, - }, - output: serverUrl, - }, - { - description: 'When dataplane is provided in source config that dataplane Url will be selected', - input: { - response: sourceConfigWithBothDataPlane, - serverUrl, - }, - output: usDataplaneUrl, - }, - { - description: - 'In case of valid residencyServer(US) option: dataplane is not provided in source config but provided in load API, dataplane Url from load option will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - serverUrl, - options: validResidencyServerUS, - }, - output: serverUrl, - }, - { - description: - 'In case of valid residencyServer(US) option: dataplane is provided in source config that dataplane Url will be selected', - input: { - response: sourceConfigWithBothDataPlane, - serverUrl, - options: validResidencyServerUS, - }, - output: usDataplaneUrl, - }, - { - description: - 'In case of valid residencyServer(US) option: dataplane is provided but US region not available in source config then load API dataplane Url will be selected', - input: { - response: sourceConfigWithEUDataPlane, - serverUrl, - options: validResidencyServerUS, - }, - output: serverUrl, - }, - { - description: - 'In case of valid residencyServer(EU) option: dataplane is not provided in source config but provided in load API, dataplane Url from load option will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - serverUrl, - options: validResidencyServerEU, - }, - output: serverUrl, - }, - { - description: - 'In case of valid residencyServer(EU) option: dataplane is provided in source config that dataplane Url will be selected', - input: { - response: sourceConfigWithBothDataPlane, - serverUrl, - options: validResidencyServerEU, - }, - output: euDataplaneUrl, - }, - { - description: - 'In case of valid residencyServer(EU) option: dataplane is provided only for US region not available in source config then US region dataplane Url will be selected', - input: { - response: sourceConfigWithUSDataPlane, - serverUrl, - options: validResidencyServerEU, - }, - output: usDataplaneUrl, - }, -]; - -const testCaseDataWithInvalidDataplaneUrl = [ - { - description: - 'When dataplane is not provided in source config or in load API, default dataplane Url will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - serverUrl: undefined, - }, - }, - { - description: - 'In case of valid residencyServer(US) option: dataplane is not provided in source config or in load API, default dataplane Url will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - options: validResidencyServerUS, - }, - }, - { - description: - 'In case of valid residencyServer(EU) option: dataplane is not provided in source config or in load API, default dataplane Url will be selected', - input: { - response: sourceConfigWithEmptyDataPlanes, - options: validResidencyServerEU, - }, - }, -]; - -test.each(testCaseData)('$description', ({ input, output }) => { - const url = resolveDataPlaneUrl(input.response, input.serverUrl, input.options); - expect(url).toEqual(output); -}); - -test.each(testCaseDataWithInvalidDataplaneUrl)('$description', ({ input }) => { - const url = resolveDataPlaneUrl(input.response, input.serverUrl, input.options); - expect(url).toBe(undefined); -}); diff --git a/packages/analytics-js/src/components/configManager/ConfigManager.ts b/packages/analytics-js/src/components/configManager/ConfigManager.ts index d9becc882..576886a92 100644 --- a/packages/analytics-js/src/components/configManager/ConfigManager.ts +++ b/packages/analytics-js/src/components/configManager/ConfigManager.ts @@ -11,7 +11,6 @@ import type { ILogger } from '@rudderstack/analytics-js-common/types/Logger'; import { CONFIG_MANAGER } from '@rudderstack/analytics-js-common/constants/loggerContexts'; import { isValidSourceConfig, validateLoadArgs } from './util/validate'; import { - DATA_PLANE_URL_ERROR, SOURCE_CONFIG_FETCH_ERROR, SOURCE_CONFIG_OPTION_ERROR, SOURCE_CONFIG_RESOLUTION_ERROR, @@ -21,7 +20,6 @@ import { filterEnabledDestination } from '../utilities/destinations'; import { removeTrailingSlashes } from '../utilities/url'; import { APP_VERSION } from '../../constants/app'; import { state } from '../../state'; -import { resolveDataPlaneUrl } from './util/dataPlaneResolver'; import { getIntegrationsCDNPath, getPluginsCDNPath } from './util/cdnPaths'; import type { IConfigManager, SourceConfigResponse } from './types'; import { @@ -64,6 +62,10 @@ class ConfigManager implements IConfigManager { validateLoadArgs(state.lifecycle.writeKey.value, state.lifecycle.dataPlaneUrl.value); + state.lifecycle.activeDataplaneUrl.value = removeTrailingSlashes( + state.lifecycle.dataPlaneUrl.value, + ) as string; + const lockIntegrationsVersion = state.loadOptions.value.lockIntegrationsVersion as boolean; // determine the path to fetch integration SDK from @@ -150,18 +152,6 @@ class ConfigManager implements IConfigManager { // set the values in state for reporting slice updateReportingState(res, this.logger); - // determine the dataPlane url - const dataPlaneUrl = resolveDataPlaneUrl( - res.source.dataplanes, - state.lifecycle.dataPlaneUrl.value, - state.loadOptions.value.residencyServer, - this.logger, - ); - - if (!dataPlaneUrl) { - this.onError(new Error(DATA_PLANE_URL_ERROR), undefined, true); - return; - } const nativeDestinations: Destination[] = res.source.destinations.length > 0 ? filterEnabledDestination(res.source.destinations) : []; @@ -183,8 +173,6 @@ class ConfigManager implements IConfigManager { updateConsentsState(res); // set application lifecycle state - // Cast to string as we are sure that the value is not undefined - state.lifecycle.activeDataplaneUrl.value = removeTrailingSlashes(dataPlaneUrl) as string; state.lifecycle.status.value = 'configured'; }); } diff --git a/packages/analytics-js/src/components/configManager/types.ts b/packages/analytics-js/src/components/configManager/types.ts index 26eb94ad2..c097829bf 100644 --- a/packages/analytics-js/src/components/configManager/types.ts +++ b/packages/analytics-js/src/components/configManager/types.ts @@ -1,10 +1,6 @@ import type { DestinationConfig } from '@rudderstack/analytics-js-common/types/Destination'; import type { Nullable } from '@rudderstack/analytics-js-common/types/Nullable'; import type { StatsCollection } from '@rudderstack/analytics-js-common/types/Source'; -import type { - RegionDetails, - ResidencyServerRegion, -} from '@rudderstack/analytics-js-common/types/DataResidency'; import type { IHttpClient } from '@rudderstack/analytics-js-common/types/HttpClient'; import type { IErrorHandler } from '@rudderstack/analytics-js-common/types/ErrorHandler'; import type { ILogger } from '@rudderstack/analytics-js-common/types/Logger'; @@ -76,7 +72,6 @@ export type SourceConfigResponse = { createdAt: string; createdBy: string; deleted: boolean; - dataplanes?: Record; }; }; diff --git a/packages/analytics-js/src/components/configManager/util/dataPlaneResolver.ts b/packages/analytics-js/src/components/configManager/util/dataPlaneResolver.ts deleted file mode 100644 index 567e90b3a..000000000 --- a/packages/analytics-js/src/components/configManager/util/dataPlaneResolver.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { - RegionDetails, - ResidencyServerRegion, -} from '@rudderstack/analytics-js-common/types/DataResidency'; -import type { ILogger } from '@rudderstack/analytics-js-common/types/Logger'; -import { CONFIG_MANAGER } from '@rudderstack/analytics-js-common/constants/loggerContexts'; -import { isValidURL } from '@rudderstack/analytics-js-common/utilities/url'; -import { UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING } from '../../../constants/logMessages'; - -const DEFAULT_REGION = 'US'; - -/** - * A function to get url from source config response - * @param {array} urls An array of objects containing urls - * @returns - */ -const getDefaultUrlOfRegion = (urls?: RegionDetails[]) => { - let url; - if (Array.isArray(urls) && urls.length > 0) { - const obj = urls.find(elem => elem.default === true); - if (obj && isValidURL(obj.url)) { - return obj.url; - } - } - return url; -}; - -const validateResidencyServerRegion = ( - residencyServerRegion?: ResidencyServerRegion, - logger?: ILogger, -) => { - const residencyServerRegions = ['US', 'EU']; - if (residencyServerRegion && !residencyServerRegions.includes(residencyServerRegion)) { - logger?.warn( - UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING( - CONFIG_MANAGER, - residencyServerRegion, - DEFAULT_REGION, - ), - ); - return undefined; - } - return residencyServerRegion; -}; - -/** - * A function to determine the dataPlaneUrl - * @param {Object} dataplanes An object containing dataPlaneUrl for different region - * @param {String} serverUrl dataPlaneUrl provided in the load call - * @param {String} residencyServerRegion User provided residency server region - * @param {Logger} logger logger instance - * @returns The data plane URL string to use - */ -const resolveDataPlaneUrl = ( - dataplanes?: Record, - serverUrl?: string, - residencyServerRegion?: ResidencyServerRegion, - logger?: ILogger, -) => { - // Check if dataPlanes object is present in source config - if (dataplanes && Object.keys(dataplanes).length > 0) { - const region = validateResidencyServerRegion(residencyServerRegion, logger) ?? DEFAULT_REGION; - const regionUrlArr: RegionDetails[] = dataplanes[region] || dataplanes[DEFAULT_REGION]; - - const defaultUrl = getDefaultUrlOfRegion(regionUrlArr); - if (defaultUrl) { - return defaultUrl; - } - } - // return the dataPlaneUrl provided in load API(if available) - if (serverUrl) { - return serverUrl; - } - - // return undefined if data plane url can not be determined - return undefined; -}; - -export { resolveDataPlaneUrl }; diff --git a/packages/analytics-js/src/constants/logMessages.ts b/packages/analytics-js/src/constants/logMessages.ts index 6fea94cf2..7cd5897e5 100644 --- a/packages/analytics-js/src/constants/logMessages.ts +++ b/packages/analytics-js/src/constants/logMessages.ts @@ -13,7 +13,6 @@ import type { const SOURCE_CONFIG_OPTION_ERROR = `"getSourceConfig" must be a function. Please make sure that it is defined and returns a valid source configuration object.`; const INTG_CDN_BASE_URL_ERROR = `Failed to load the SDK as the CDN base URL for integrations is not valid.`; const PLUGINS_CDN_BASE_URL_ERROR = `Failed to load the SDK as the CDN base URL for plugins is not valid.`; -const DATA_PLANE_URL_ERROR = `Failed to load the SDK as the data plane URL could not be determined. Please check that the data plane URL is set correctly and try again.`; const SOURCE_CONFIG_RESOLUTION_ERROR = `Unable to process/parse source configuration response.`; const SOURCE_DISABLED_ERROR = `The source is disabled. Please enable the source in the dashboard to send events.`; const XHR_PAYLOAD_PREP_ERROR = `Failed to prepare data for the request.`; @@ -136,13 +135,6 @@ const STORAGE_DATA_MIGRATION_OVERRIDE_WARNING = ( ): string => `${context}${LOG_CONTEXT_SEPARATOR}The storage data migration has been disabled because the configured storage encryption version (${storageEncryptionVersion}) is not the latest (${defaultVersion}). To enable storage data migration, please update the storage encryption version to the latest version.`; -const UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING = ( - context: string, - selectedResidencyServerRegion: string | undefined, - defaultRegion: string, -): string => - `${context}${LOG_CONTEXT_SEPARATOR}The residency server region "${selectedResidencyServerRegion}" is not supported. Please choose one of the following supported regions: "US, EU". The default region "${defaultRegion}" will be used instead.`; - const RESERVED_KEYWORD_WARNING = ( context: string, property: string, @@ -260,7 +252,6 @@ export { UNSUPPORTED_ERROR_REPORTING_PROVIDER_WARNING, UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING, STORAGE_DATA_MIGRATION_OVERRIDE_WARNING, - UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING, RESERVED_KEYWORD_WARNING, INVALID_CONTEXT_OBJECT_WARNING, UNSUPPORTED_BEACON_API_WARNING, @@ -283,7 +274,6 @@ export { SOURCE_CONFIG_OPTION_ERROR, INTG_CDN_BASE_URL_ERROR, PLUGINS_CDN_BASE_URL_ERROR, - DATA_PLANE_URL_ERROR, WRITE_KEY_VALIDATION_ERROR, DATA_PLANE_URL_VALIDATION_ERROR, READY_API_CALLBACK_ERROR, diff --git a/packages/analytics-js/src/index.ts b/packages/analytics-js/src/index.ts index e154818e9..14d1e510f 100644 --- a/packages/analytics-js/src/index.ts +++ b/packages/analytics-js/src/index.ts @@ -15,7 +15,6 @@ export { type CookieSameSite } from '@rudderstack/analytics-js-common/types/Stor export { type ApiCallback, type ApiOptions } from '@rudderstack/analytics-js-common/types/EventApi'; export { type ApiObject } from '@rudderstack/analytics-js-common/types/ApiObject'; export { type IntegrationOpts } from '@rudderstack/analytics-js-common/types/Integration'; -export { type ResidencyServerRegion } from '@rudderstack/analytics-js-common/types/DataResidency'; export { type LogLevel } from '@rudderstack/analytics-js-common/types/Logger'; export { type PluginName } from '@rudderstack/analytics-js-common/types/PluginsManager'; export { type IdentifyTraits } from '@rudderstack/analytics-js-common/types/traits'; diff --git a/packages/sanity-suite/.env.example b/packages/sanity-suite/.env.example index ee46fb792..e019822c9 100644 --- a/packages/sanity-suite/.env.example +++ b/packages/sanity-suite/.env.example @@ -29,11 +29,6 @@ STAGING=false #WRITE_KEY= #DATAPLANE_URL= -# Data Residency -#WRITE_KEY= -#DATA_RESIDENCY_US_DATAPLANE= -#DATA_RESIDENCY_EU_DATAPLANE= - # GCM #WRITE_KEY= #DATAPLANE_URL= diff --git a/packages/sanity-suite/src/testBook/TestBook.js b/packages/sanity-suite/src/testBook/TestBook.js index 5c6de7579..3e7abd97a 100644 --- a/packages/sanity-suite/src/testBook/TestBook.js +++ b/packages/sanity-suite/src/testBook/TestBook.js @@ -6,7 +6,10 @@ class TestBook { this.markupItems = []; this.container = document.getElementById(containerId); this.executionDelay = executionDelay; + this.currentExecutionIndex = 0; + this.nextTestCaseTimeoutId = undefined; this.createTestBook(testBookData); + this.suiteRunInProgress = false; } // eslint-disable-next-line class-methods-use-this @@ -95,7 +98,7 @@ class TestBook {
${JSON.stringify(testCase.inputData, undefined, 2)}
- pending
@@ -106,20 +109,18 @@ class TestBook {
${JSON.stringify(testCase.expectedResult, undefined, 2)}
-

-                          
                         
                     
@@ -178,7 +179,7 @@ class TestBook {
                             ${menuItemText}
                         
                         
                     

@@ -328,6 +329,10 @@ class TestBook { viewDiffElement.href = `https://jsondiff.com/#left=data:base64,${toBase64(sanitizedExpectedResultData)}&right=data:base64,${toBase64(sanitizedResultData)}`; } + + if (this.suiteRunInProgress) { + this.executeNextTestCase(); + } }); observer.observe(resultContainerElement, { @@ -346,25 +351,43 @@ class TestBook { resultSummaryElement.classList.add('bg-warning', 'summary-complete'); } - executeSuites() { + executeNextTestCase() { + clearTimeout(this.nextTestCaseTimeoutId); + const testCaseTriggers = document.getElementsByClassName('testCaseTrigger'); + const totalTestCases = document.getElementsByClassName('testCaseStatus'); const testCaseTriggersCount = testCaseTriggers.length; - let currentExecutionIndex = 0; - const delay = this.executionDelay; - - const executeTestCase = () => { - setTimeout(() => { - if (currentExecutionIndex < testCaseTriggersCount) { - testCaseTriggers[currentExecutionIndex].click(); - currentExecutionIndex++; - executeTestCase(); - } else { - this.resultStatusSummary(); + if (this.currentExecutionIndex < testCaseTriggersCount) { + testCaseTriggers[this.currentExecutionIndex].click(); + this.currentExecutionIndex++; + + // Move to next test case in case the current test case is + // stuck in pending state + this.nextTestCaseTimeoutId = setTimeout(() => { + if (totalTestCases[this.currentExecutionIndex - 1].textContent === 'pending') { + this.executeNextTestCase(); } - }, delay); - }; + }, this.executionDelay); + } else { + this.suiteRunInProgress = false; + this.resultStatusSummary(); + } + } + + executeSuites() { + const totalTestCases = document.getElementsByClassName('testCaseStatus'); + for (const totalTestCase of totalTestCases) { + totalTestCase.textContent = 'pending'; + totalTestCase.className = 'badge badge-warning'; + } + + const resultSummaryElement = document.getElementById('resultSummary'); + resultSummaryElement.innerHTML = 'N/A'; + resultSummaryElement.classList.remove('bg-warning', 'summary-complete'); - executeTestCase(); + this.currentExecutionIndex = 0; + this.suiteRunInProgress = true; + this.executeNextTestCase(); } createTestBook(testSuitesData) { From e2e1620677c90169fca35ed3e9057ced3b88a299 Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:00:09 +0530 Subject: [PATCH 02/17] feat: add the ability to lock plugins version (#1749) * feat: add ability to lock plugins version * chore: fix workflows to mark slack steps as non-blockers --- .github/workflows/deploy-npm.yml | 14 ++- .github/workflows/deploy-sanity-suite.yml | 1 + .github/workflows/deploy.yml | 11 +- .github/workflows/draft-new-release.yml | 1 - .github/workflows/publish-new-release.yml | 2 +- .../src/types/LoadOptions.ts | 1 + .../configManager/ConfigManager.test.ts | 10 +- .../components/configManager/cdnPaths.test.ts | 49 +++++--- .../configManager/commonUtil.test.ts | 24 ++-- packages/analytics-js/public/index.html | 20 ++- .../components/configManager/ConfigManager.ts | 26 ++-- .../components/configManager/util/cdnPaths.ts | 118 ++++++++++-------- .../configManager/util/commonUtil.ts | 2 + .../src/components/utilities/loadOptions.ts | 2 + .../analytics-js/src/constants/logMessages.ts | 10 +- .../src/state/slices/loadOptions.ts | 1 + 16 files changed, 187 insertions(+), 105 deletions(-) diff --git a/.github/workflows/deploy-npm.yml b/.github/workflows/deploy-npm.yml index 1f59892fa..fbe84bdf0 100644 --- a/.github/workflows/deploy-npm.yml +++ b/.github/workflows/deploy-npm.yml @@ -98,9 +98,18 @@ jobs: new_npm_version_sw=$(npm show @rudderstack/analytics-js-service-worker version 2>/dev/null || echo "not found") echo "NEW_NPM_VERSION_SW=$new_npm_version_sw" >> $GITHUB_ENV + - name: Debug environment variables + continue-on-error: true + run: | + echo "CURRENT_NPM_VERSION=${{ env.CURRENT_NPM_VERSION }}" + echo "NEW_NPM_VERSION=${{ env.NEW_NPM_VERSION }}" + echo "CURRENT_NPM_VERSION_SW=${{ env.CURRENT_NPM_VERSION_SW }}" + echo "NEW_NPM_VERSION_SW=${{ env.NEW_NPM_VERSION_SW }}" + - name: Send message to Slack channel - if: ${{ env.CURRENT_NPM_VERSION != env.NEW_NPM_VERSION && env.NEW_NPM_VERSION != 'not found'}} + if: env.CURRENT_NPM_VERSION != env.NEW_NPM_VERSION && env.NEW_NPM_VERSION != 'not found' id: slack + continue-on-error: true uses: slackapi/slack-github-action@v1.26.0 env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} @@ -148,8 +157,9 @@ jobs: } - name: Send message to Slack channel for Service Worker - if: ${{ env.CURRENT_NPM_VERSION_SW != env.NEW_NPM_VERSION_SW && env.NEW_NPM_VERSION_SW != 'not found'}} + if: env.CURRENT_NPM_VERSION_SW != env.NEW_NPM_VERSION_SW && env.NEW_NPM_VERSION_SW != 'not found' id: slackSw + continue-on-error: true uses: slackapi/slack-github-action@v1.26.0 env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/deploy-sanity-suite.yml b/.github/workflows/deploy-sanity-suite.yml index 92df0d7f5..3b6b0a7a5 100644 --- a/.github/workflows/deploy-sanity-suite.yml +++ b/.github/workflows/deploy-sanity-suite.yml @@ -141,6 +141,7 @@ jobs: - name: Send message to Slack channel id: slack uses: slackapi/slack-github-action@v1.26.0 + continue-on-error: true env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} PROJECT_NAME: 'Sanity suite - ${{ inputs.environment }}' diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 454691d6b..6db4fbb54 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -171,13 +171,14 @@ jobs: - name: Send message to Slack channel id: slack + continue-on-error: true uses: slackapi/slack-github-action@v1.26.0 env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} - PROJECT_NAME: 'JS SDK Browser Package${{ inputs.action_type }} - ${{ inputs.environment }}' - CDN_URL: 'https://cdn.rudderlabs.com/${{ inputs.s3_dir_path }}/modern/rsa.min.js' + PROJECT_NAME: ${{ format('JS SDK Browser Package {0} - {1}', inputs.action_type, inputs.environment) }} + CDN_URL: ${{ format('https://cdn.rudderlabs.com/{0}/modern/rsa.min.js', inputs.s3_dir_path) }} RELEASES_URL: 'https://github.com/rudderlabs/rudder-sdk-js/releases/tag/@rudderstack/analytics-js@' - LINK_TEXT: ${{ inputs.environment == 'development' && 'Development' || ((inputs.environment == 'staging' && format('v{0} - Staging', env.CURRENT_VERSION_VALUE)) || format('v{0}', env.CURRENT_VERSION_VALUE)) }} + LINK_TEXT: ${{ (inputs.environment == 'development' && 'Development') || (inputs.environment == 'staging' && format('v{0} - Staging', env.CURRENT_VERSION_VALUE)) || format('v{0}', env.CURRENT_VERSION_VALUE) }} with: channel-id: ${{ secrets.SLACK_RELEASE_CHANNEL_ID }} payload: | @@ -206,9 +207,9 @@ jobs: "alt_text": "JavaScript Icon" } } - ${{ inputs.environment == 'production' && format(',{"type": "context", "elements": [{"type": "mrkdwn", "text": "For more details, check the full release notes <{0}{1}|here>."}]}', env.RELEASES_URL, env.CURRENT_VERSION_VALUE) || '' }} + ${{ inputs.environment == 'production' && format(',{{"type": "context", "elements": [{{"type": "mrkdwn", "text": "For more details, check the full release notes <{0}{1}|here>."}}]}}', env.RELEASES_URL, env.CURRENT_VERSION_VALUE) || '' }} ] - } + } # Below steps are for v1.1 SDK (legacy) diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index bdf523f58..85da00d5e 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -100,4 +100,3 @@ jobs: github_token: ${{ secrets.PAT }} pr_title: 'chore(release): pull ${{ steps.create-release.outputs.branch_name }} into main' pr_body: ':crown: *An automated PR*' - pr_reviewer: 'MoumitaM,saikumarrs' diff --git a/.github/workflows/publish-new-release.yml b/.github/workflows/publish-new-release.yml index 47ea755cf..a3f9458aa 100644 --- a/.github/workflows/publish-new-release.yml +++ b/.github/workflows/publish-new-release.yml @@ -98,7 +98,6 @@ jobs: github_token: ${{ secrets.PAT }} pr_title: 'chore(release): pull main into develop post release v${{ steps.extract-version.outputs.release_version }}' pr_body: ':crown: *An automated PR*' - pr_reviewer: 'MoumitaM,saikumarrs' - name: Delete hotfix release branch uses: koj-co/delete-merged-action@master @@ -118,6 +117,7 @@ jobs: - name: Send message to Slack channel id: slack + continue-on-error: true uses: slackapi/slack-github-action@v1.26.0 env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/packages/analytics-js-common/src/types/LoadOptions.ts b/packages/analytics-js-common/src/types/LoadOptions.ts index 4378f91db..25b559c3e 100644 --- a/packages/analytics-js-common/src/types/LoadOptions.ts +++ b/packages/analytics-js-common/src/types/LoadOptions.ts @@ -128,6 +128,7 @@ export type LoadOptions = { setCookieDomain?: string; // defaults to current domain. sameSiteCookie?: CookieSameSite; // defaults to Lax. lockIntegrationsVersion?: boolean; // defaults to false. + lockPluginsVersion?: boolean; // defaults to false. polyfillIfRequired?: boolean; // defaults to true. Controls whether the SDK should polyfill unsupported browser API's if they are detected as missing onLoaded?: OnLoadedCallback; uaChTrackLevel?: UaChTrackLevel; diff --git a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts index 538d62794..72a02c601 100644 --- a/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts +++ b/packages/analytics-js/__tests__/components/configManager/ConfigManager.test.ts @@ -61,6 +61,7 @@ describe('ConfigManager', () => { const sampleConfigUrl = 'https://dummy.dataplane.host.com'; const sampleScriptURL = 'https://www.dummy.url/fromScript/v3/rsa.min.js'; const lockIntegrationsVersion = false; + const lockPluginsVersion = false; beforeAll(() => { server.listen(); @@ -106,12 +107,13 @@ describe('ConfigManager', () => { state.lifecycle.writeKey.value = sampleWriteKey; state.lifecycle.dataPlaneUrl.value = sampleDataPlaneUrl; - state.loadOptions.value.lockIntegrationsVersion = false; state.loadOptions.value.destSDKBaseURL = sampleDestSDKUrl; state.loadOptions.value.logLevel = 'DEBUG'; state.loadOptions.value.configUrl = sampleConfigUrl; state.loadOptions.value.lockIntegrationsVersion = lockIntegrationsVersion; - const expectedConfigUrl = `${sampleConfigUrl}/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}`; + state.loadOptions.value.lockPluginsVersion = lockPluginsVersion; + + const expectedConfigUrl = `${sampleConfigUrl}/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}&lockPluginsVersion=${lockPluginsVersion}`; configManagerInstance.getConfig = jest.fn(); configManagerInstance.init(); @@ -122,7 +124,7 @@ describe('ConfigManager', () => { expect(configManagerInstance.getConfig).toHaveBeenCalled(); }); it('should fetch configurations using sourceConfig endpoint', done => { - state.lifecycle.sourceConfigUrl.value = `${sampleConfigUrl}/sourceConfigClone/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}`; + state.lifecycle.sourceConfigUrl.value = `${sampleConfigUrl}/sourceConfigClone/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}&lockPluginsVersion=${lockPluginsVersion}`; configManagerInstance.processConfig = jest.fn(); const counter = signal(0); @@ -224,7 +226,7 @@ describe('ConfigManager', () => { }); it('should fetch the source config and process the response', done => { - state.lifecycle.sourceConfigUrl.value = `${sampleConfigUrl}/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}`; + state.lifecycle.sourceConfigUrl.value = `${sampleConfigUrl}/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=${sampleWriteKey}&lockIntegrationsVersion=${lockIntegrationsVersion}&lockPluginsVersion=${lockPluginsVersion}`; configManagerInstance.processConfig = jest.fn(); configManagerInstance.getConfig(); setTimeout(() => { diff --git a/packages/analytics-js/__tests__/components/configManager/cdnPaths.test.ts b/packages/analytics-js/__tests__/components/configManager/cdnPaths.test.ts index 005aaa2f9..1f2e91288 100644 --- a/packages/analytics-js/__tests__/components/configManager/cdnPaths.test.ts +++ b/packages/analytics-js/__tests__/components/configManager/cdnPaths.test.ts @@ -21,7 +21,7 @@ jest.mock('../../../src/components/configManager/util/commonUtil.ts', () => { describe('CDN path utilities', () => { describe('getIntegrationsCDNPath', () => { const dummyCustomURL = 'https://www.dummy.url/integrations'; - const dummyScriptURL = 'https://www.dummy.url/fromScript/v3/rsa.min.js'; + const dummyScriptURL = 'https://www.dummy.url/fromScript/v3/modern/rsa.min.js'; const dummyVersion = '3.x.x'; beforeEach(() => { @@ -40,18 +40,22 @@ describe('CDN path utilities', () => { it('should throw error if invalid custom url is provided', () => { const integrationsCDNPath = () => getIntegrationsCDNPath(dummyVersion, false, '/'); expect(integrationsCDNPath).toThrow( - 'Failed to load the SDK as the CDN base URL for integrations is not valid.', + 'Failed to load the SDK as the base URL for integrations is not valid.', ); }); it('should return script src path if script src exists and integrations version is not locked', () => { const integrationsCDNPath = getIntegrationsCDNPath(dummyVersion, false, undefined); - expect(integrationsCDNPath).toBe('https://www.dummy.url/fromScript/v3/js-integrations'); + expect(integrationsCDNPath).toBe( + 'https://www.dummy.url/fromScript/v3/modern/js-integrations', + ); }); it('should return script src path with versioned folder if script src exists and integrations version is locked', () => { const integrationsCDNPath = getIntegrationsCDNPath(dummyVersion, true, undefined); - expect(integrationsCDNPath).toBe('https://www.dummy.url/fromScript/3.x.x/js-integrations'); + expect(integrationsCDNPath).toBe( + 'https://www.dummy.url/fromScript/3.x.x/modern/js-integrations', + ); }); it('should return default path if no script src exists and integrations version is not locked', () => { @@ -71,34 +75,51 @@ describe('CDN path utilities', () => { describe('getPluginsCDNPath', () => { const dummyCustomURL = 'https://www.dummy.url/plugins/'; - const dummyScriptURL = 'https://www.dummy.url/fromScript/v3/rsa.min.js'; + const dummyScriptURL = 'https://www.dummy.url/fromScript/v3/modern/rsa.min.js'; + const dummyVersion = '3.x.x'; + + beforeEach(() => { + getSDKUrl.mockImplementation(() => dummyScriptURL); + }); afterEach(() => { jest.resetAllMocks(); }); it('should return plugins CDN URL if a valid custom URL is provided', () => { - const pluginsCDNPath = getPluginsCDNPath(dummyCustomURL); + const pluginsCDNPath = getPluginsCDNPath(dummyVersion, false, dummyCustomURL); expect(pluginsCDNPath).toBe('https://www.dummy.url/plugins'); }); it('should throw error if invalid custom url is provided', () => { - const pluginsCDNPath = () => getPluginsCDNPath('htp:/some.broken.url'); + const pluginsCDNPath = () => getPluginsCDNPath(dummyVersion, false, 'htp:/some.broken.url'); expect(pluginsCDNPath).toThrow( - 'Failed to load the SDK as the CDN base URL for plugins is not valid.', + 'Failed to load the SDK as the base URL for plugins is not valid.', ); }); - it('should return default plugins CDN URL if no custom URL is provided and no script src exists', () => { - const pluginsCDNPath = getPluginsCDNPath(undefined); + it('should return script src path if script src exists and plugins version is not locked', () => { + const pluginsCDNPath = getPluginsCDNPath(dummyVersion, false); + expect(pluginsCDNPath).toBe('https://www.dummy.url/fromScript/v3/modern/plugins'); + }); + + it('should return script src path with versioned folder if script src exists and plugins version is locked', () => { + const pluginsCDNPath = getPluginsCDNPath(dummyVersion, true); + expect(pluginsCDNPath).toBe('https://www.dummy.url/fromScript/3.x.x/modern/plugins'); + }); + + it('should return default path if no script src exists and plugins version is not locked', () => { + getSDKUrl.mockImplementation(() => undefined); + + const pluginsCDNPath = getPluginsCDNPath(dummyVersion, false, undefined); expect(pluginsCDNPath).toBe('https://cdn.rudderlabs.com/v3/modern/plugins'); }); - it('should return plugins CDN URL if core SDK script is loaded', () => { - getSDKUrl.mockImplementation(() => dummyScriptURL); + it('should return default path if no script src exists but plugins version is locked', () => { + getSDKUrl.mockImplementation(() => undefined); - const pluginsCDNPath = getPluginsCDNPath(undefined); - expect(pluginsCDNPath).toBe('https://www.dummy.url/fromScript/v3/plugins'); + const pluginsCDNPath = getPluginsCDNPath(dummyVersion, true, undefined); + expect(pluginsCDNPath).toBe('https://cdn.rudderlabs.com/3.x.x/modern/plugins'); }); }); }); diff --git a/packages/analytics-js/__tests__/components/configManager/commonUtil.test.ts b/packages/analytics-js/__tests__/components/configManager/commonUtil.test.ts index 3d923ce8f..fba844d3c 100644 --- a/packages/analytics-js/__tests__/components/configManager/commonUtil.test.ts +++ b/packages/analytics-js/__tests__/components/configManager/commonUtil.test.ts @@ -565,10 +565,10 @@ describe('Config Manager Common Utilities', () => { describe('getSourceConfigURL', () => { it('should return default source config URL if invalid source config URL is provided', () => { - const sourceConfigURL = getSourceConfigURL('invalid-url', 'writekey', true, mockLogger); + const sourceConfigURL = getSourceConfigURL('invalid-url', 'writekey', true, true, mockLogger); expect(sourceConfigURL).toBe( - 'https://api.rudderstack.com/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=true', + 'https://api.rudderstack.com/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=true&lockPluginsVersion=true', ); expect(mockLogger.warn).toHaveBeenCalledWith( @@ -580,20 +580,20 @@ describe('Config Manager Common Utilities', () => { // Mock console.warn const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation(() => {}); - const sourceConfigURL = getSourceConfigURL('invalid-url', 'writekey', true); + const sourceConfigURL = getSourceConfigURL('invalid-url', 'writekey', true, true); expect(sourceConfigURL).toBe( - 'https://api.rudderstack.com/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=true', + 'https://api.rudderstack.com/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=true&lockPluginsVersion=true', ); expect(consoleWarnMock).not.toHaveBeenCalled(); }); it('should return the source config URL with default endpoint appended if no endpoint is present', () => { - const sourceConfigURL = getSourceConfigURL('https://www.dummy.url', 'writekey', false); + const sourceConfigURL = getSourceConfigURL('https://www.dummy.url', 'writekey', false, false); expect(sourceConfigURL).toBe( - 'https://www.dummy.url/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false', + 'https://www.dummy.url/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false&lockPluginsVersion=false', ); }); @@ -602,10 +602,11 @@ describe('Config Manager Common Utilities', () => { 'https://www.dummy.url/some/path', 'writekey', false, + false, ); expect(sourceConfigURL).toBe( - 'https://www.dummy.url/some/path/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false', + 'https://www.dummy.url/some/path/sourceConfig/?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false&lockPluginsVersion=false', ); }); @@ -614,10 +615,11 @@ describe('Config Manager Common Utilities', () => { 'https://www.dummy.url/sourceConfig', 'writekey', false, + false, ); expect(sourceConfigURL).toBe( - 'https://www.dummy.url/sourceConfig?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false', + 'https://www.dummy.url/sourceConfig?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false&lockPluginsVersion=false', ); }); @@ -626,10 +628,11 @@ describe('Config Manager Common Utilities', () => { 'https://www.dummy.url//sourceConfig', 'writekey', false, + false, ); expect(sourceConfigURL).toBe( - 'https://www.dummy.url/sourceConfig?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false', + 'https://www.dummy.url/sourceConfig?p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false&lockPluginsVersion=false', ); }); @@ -638,10 +641,11 @@ describe('Config Manager Common Utilities', () => { 'https://www.dummy.url/some/path/?abc=def#blog', 'writekey', false, + false, ); expect(sourceConfigURL).toBe( - 'https://www.dummy.url/some/path/sourceConfig/?abc=def&p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false#blog', + 'https://www.dummy.url/some/path/sourceConfig/?abc=def&p=__MODULE_TYPE__&v=__PACKAGE_VERSION__&build=modern&writeKey=writekey&lockIntegrationsVersion=false&lockPluginsVersion=false#blog', ); }); }); diff --git a/packages/analytics-js/public/index.html b/packages/analytics-js/public/index.html index 26a7f56da..fadeedcbe 100644 --- a/packages/analytics-js/public/index.html +++ b/packages/analytics-js/public/index.html @@ -68,7 +68,10 @@ __globalThis_magic__.globalThis = __globalThis_magic__; delete Object.prototype.__globalThis_magic__; } - window.rudderAnalyticsAddScript("".concat(sdkBaseUrl, "/").concat(window.rudderAnalyticsBuildType, "/").concat(sdkName), "data-rsa-write-key", "__WRITE_KEY__"); + + // Commented out SDK script addition + // as the build process automatically adds the script + // window.rudderAnalyticsAddScript("".concat(sdkBaseUrl, "/").concat(window.rudderAnalyticsBuildType, "/").concat(sdkName), "data-rsa-write-key", "__WRITE_KEY__"); }; if (typeof Promise === "undefined" || typeof globalThis === "undefined") { window.rudderAnalyticsAddScript("https://polyfill-fastly.io/v3/polyfill.min.js?version=3.111.0&features=Symbol%2CPromise&callback=rudderAnalyticsMount"); @@ -148,6 +151,7 @@ } })(); + const localRudderAnalyticsRef = window.rudderanalytics; rudderanalytics.identify( 'customUserID', @@ -222,6 +226,20 @@ rudderanalytics.ready(function () { console.log('All ready!!!'); + + // Once the SDK is ready, fire an event from a cached reference to + // window.rudderanalytics + localRudderAnalyticsRef.track( + 'Test track event with cached RS reference', + { + revenue: 10003, + currency: 'EUR', + user_actual_id: 5678, + }, + function (message) { + console.log('in track call 4', message); + } + ); }); document.addEventListener('RSA_Initialised', function (e) { diff --git a/packages/analytics-js/src/components/configManager/ConfigManager.ts b/packages/analytics-js/src/components/configManager/ConfigManager.ts index 576886a92..d580149b3 100644 --- a/packages/analytics-js/src/components/configManager/ConfigManager.ts +++ b/packages/analytics-js/src/components/configManager/ConfigManager.ts @@ -62,27 +62,36 @@ class ConfigManager implements IConfigManager { validateLoadArgs(state.lifecycle.writeKey.value, state.lifecycle.dataPlaneUrl.value); + const { + logLevel, + configUrl, + lockIntegrationsVersion, + lockPluginsVersion, + destSDKBaseURL, + pluginsSDKBaseURL, + } = state.loadOptions.value; + state.lifecycle.activeDataplaneUrl.value = removeTrailingSlashes( state.lifecycle.dataPlaneUrl.value, ) as string; - const lockIntegrationsVersion = state.loadOptions.value.lockIntegrationsVersion as boolean; - // determine the path to fetch integration SDK from const intgCdnUrl = getIntegrationsCDNPath( APP_VERSION, - lockIntegrationsVersion, - state.loadOptions.value.destSDKBaseURL, + lockIntegrationsVersion as boolean, + destSDKBaseURL, ); // determine the path to fetch remote plugins from - const pluginsCDNPath = getPluginsCDNPath(state.loadOptions.value.pluginsSDKBaseURL); + const pluginsCDNPath = getPluginsCDNPath( + APP_VERSION, + lockPluginsVersion as boolean, + pluginsSDKBaseURL, + ); updateStorageStateFromLoadOptions(this.logger); updateConsentsStateFromLoadOptions(this.logger); updateDataPlaneEventsStateFromLoadOptions(this.logger); - const { logLevel, configUrl } = state.loadOptions.value; - // set application lifecycle state in global state batch(() => { state.lifecycle.integrationsCDNPath.value = intgCdnUrl; @@ -95,7 +104,8 @@ class ConfigManager implements IConfigManager { state.lifecycle.sourceConfigUrl.value = getSourceConfigURL( configUrl, state.lifecycle.writeKey.value as string, - lockIntegrationsVersion, + lockIntegrationsVersion as boolean, + lockPluginsVersion as boolean, this.logger, ); }); diff --git a/packages/analytics-js/src/components/configManager/util/cdnPaths.ts b/packages/analytics-js/src/components/configManager/util/cdnPaths.ts index dec550b54..0cc0070b1 100644 --- a/packages/analytics-js/src/components/configManager/util/cdnPaths.ts +++ b/packages/analytics-js/src/components/configManager/util/cdnPaths.ts @@ -1,78 +1,86 @@ import { CDN_INT_DIR, CDN_PLUGINS_DIR } from '@rudderstack/analytics-js-common/constants/urls'; import { isValidURL } from '@rudderstack/analytics-js-common/utilities/url'; -import { CDN_ARCH_VERSION_DIR, DEST_SDK_BASE_URL, PLUGINS_BASE_URL } from '../../../constants/urls'; import { - INTG_CDN_BASE_URL_ERROR, - PLUGINS_CDN_BASE_URL_ERROR, -} from '../../../constants/logMessages'; + BUILD_TYPE, + CDN_ARCH_VERSION_DIR, + DEST_SDK_BASE_URL, + PLUGINS_BASE_URL, +} from '../../../constants/urls'; +import { COMPONENT_BASE_URL_ERROR } from '../../../constants/logMessages'; import { removeTrailingSlashes } from '../../utilities/url'; import { getSDKUrl } from './commonUtil'; -/** - * A function that determines integration SDK loading path - * @param requiredVersion - * @param lockIntegrationsVersion - * @param customIntegrationsCDNPath - * @returns - */ -const getIntegrationsCDNPath = ( - requiredVersion: string, - lockIntegrationsVersion: boolean, - customIntegrationsCDNPath?: string, -): string => { - let integrationsCDNPath = ''; +const getSDKComponentBaseURL = ( + componentType: string, + pathSuffix: string, + baseURL: string, + currentVersion: string, + lockVersion: boolean, + customURL?: string, +) => { + let sdkComponentURL = ''; - // Get the CDN base URL from the user provided URL if any - if (customIntegrationsCDNPath) { - integrationsCDNPath = removeTrailingSlashes(customIntegrationsCDNPath) as string; - - if (!integrationsCDNPath || !isValidURL(integrationsCDNPath)) { - throw new Error(INTG_CDN_BASE_URL_ERROR); + if (customURL) { + if (!isValidURL(customURL)) { + throw new Error(COMPONENT_BASE_URL_ERROR(componentType)); } - return integrationsCDNPath; + return removeTrailingSlashes(customURL) as string; } - // Get the base path from the SDK script tag src attribute or use the default path const sdkURL = getSDKUrl(); - integrationsCDNPath = sdkURL - ? sdkURL.split('/').slice(0, -1).concat(CDN_INT_DIR).join('/') - : DEST_SDK_BASE_URL; + sdkComponentURL = sdkURL ? sdkURL.split('/').slice(0, -1).concat(pathSuffix).join('/') : baseURL; - // If version is not locked it will always get the latest version of the integrations - if (lockIntegrationsVersion) { - integrationsCDNPath = integrationsCDNPath.replace(CDN_ARCH_VERSION_DIR, requiredVersion); + if (lockVersion) { + sdkComponentURL = sdkComponentURL.replace( + `/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${pathSuffix}`, + `/${currentVersion}/${BUILD_TYPE}/${pathSuffix}`, + ); } - return integrationsCDNPath; + return sdkComponentURL; }; /** - * A function that determines plugins SDK loading path - * @param customPluginsCDNPath + * A function that determines integration SDK loading path + * @param currentVersion + * @param lockIntegrationsVersion + * @param customIntegrationsCDNPath * @returns */ -const getPluginsCDNPath = (customPluginsCDNPath?: string): string => { - let pluginsCDNPath = ''; - - // Get the CDN base URL from the user provided URL if any - if (customPluginsCDNPath) { - pluginsCDNPath = removeTrailingSlashes(customPluginsCDNPath) as string; - - if (!pluginsCDNPath || !isValidURL(pluginsCDNPath)) { - throw new Error(PLUGINS_CDN_BASE_URL_ERROR); - } - - return pluginsCDNPath; - } - - // Get the base path from the SDK script tag src attribute or use the default path - const sdkURL = getSDKUrl(); - pluginsCDNPath = sdkURL - ? sdkURL.split('/').slice(0, -1).concat(CDN_PLUGINS_DIR).join('/') - : PLUGINS_BASE_URL; +const getIntegrationsCDNPath = ( + currentVersion: string, + lockIntegrationsVersion: boolean, + customIntegrationsCDNPath?: string, +): string => + getSDKComponentBaseURL( + 'integrations', + CDN_INT_DIR, + DEST_SDK_BASE_URL, + currentVersion, + lockIntegrationsVersion, + customIntegrationsCDNPath, + ); - return pluginsCDNPath; -}; +/** + * A function that determines plugins SDK loading path + * @param currentVersion Current SDK version + * @param lockPluginsVersion Flag to lock the plugins version + * @param customPluginsCDNPath URL to load the plugins from + * @returns Final plugins CDN path + */ +const getPluginsCDNPath = ( + currentVersion: string, + lockPluginsVersion: boolean, + customPluginsCDNPath?: string, +): string => + getSDKComponentBaseURL( + 'plugins', + CDN_PLUGINS_DIR, + PLUGINS_BASE_URL, + currentVersion, + lockPluginsVersion, + customPluginsCDNPath, + ); export { getIntegrationsCDNPath, getPluginsCDNPath }; diff --git a/packages/analytics-js/src/components/configManager/util/commonUtil.ts b/packages/analytics-js/src/components/configManager/util/commonUtil.ts index 3ff975923..bb2b88fb6 100644 --- a/packages/analytics-js/src/components/configManager/util/commonUtil.ts +++ b/packages/analytics-js/src/components/configManager/util/commonUtil.ts @@ -311,6 +311,7 @@ const getSourceConfigURL = ( configUrl: string | undefined, writeKey: string, lockIntegrationsVersion: boolean, + lockPluginsVersion: boolean, logger?: ILogger, ): string => { const defSearchParams = new URLSearchParams({ @@ -319,6 +320,7 @@ const getSourceConfigURL = ( build: BUILD_TYPE, writeKey, lockIntegrationsVersion: lockIntegrationsVersion.toString(), + lockPluginsVersion: lockPluginsVersion.toString(), }); let origin = DEFAULT_CONFIG_BE_URL; diff --git a/packages/analytics-js/src/components/utilities/loadOptions.ts b/packages/analytics-js/src/components/utilities/loadOptions.ts index 01cd34c56..1d54324a2 100644 --- a/packages/analytics-js/src/components/utilities/loadOptions.ts +++ b/packages/analytics-js/src/components/utilities/loadOptions.ts @@ -101,6 +101,8 @@ const normalizeLoadOptions = ( normalizedLoadOpts.lockIntegrationsVersion = normalizedLoadOpts.lockIntegrationsVersion === true; + normalizedLoadOpts.lockPluginsVersion = normalizedLoadOpts.lockPluginsVersion === true; + if (!isNumber(normalizedLoadOpts.dataPlaneEventsBufferTimeout)) { delete normalizedLoadOpts.dataPlaneEventsBufferTimeout; } diff --git a/packages/analytics-js/src/constants/logMessages.ts b/packages/analytics-js/src/constants/logMessages.ts index 7cd5897e5..927a13ec6 100644 --- a/packages/analytics-js/src/constants/logMessages.ts +++ b/packages/analytics-js/src/constants/logMessages.ts @@ -11,8 +11,7 @@ import type { // CONSTANT const SOURCE_CONFIG_OPTION_ERROR = `"getSourceConfig" must be a function. Please make sure that it is defined and returns a valid source configuration object.`; -const INTG_CDN_BASE_URL_ERROR = `Failed to load the SDK as the CDN base URL for integrations is not valid.`; -const PLUGINS_CDN_BASE_URL_ERROR = `Failed to load the SDK as the CDN base URL for plugins is not valid.`; +const DATA_PLANE_URL_ERROR = `Failed to load the SDK as the data plane URL could not be determined. Please check that the data plane URL is set correctly and try again.`; const SOURCE_CONFIG_RESOLUTION_ERROR = `Unable to process/parse source configuration response.`; const SOURCE_DISABLED_ERROR = `The source is disabled. Please enable the source in the dashboard to send events.`; const XHR_PAYLOAD_PREP_ERROR = `Failed to prepare data for the request.`; @@ -20,6 +19,9 @@ const EVENT_OBJECT_GENERATION_ERROR = `Failed to generate the event object.`; const PLUGIN_EXT_POINT_MISSING_ERROR = `Failed to invoke plugin because the extension point name is missing.`; const PLUGIN_EXT_POINT_INVALID_ERROR = `Failed to invoke plugin because the extension point name is invalid.`; +const COMPONENT_BASE_URL_ERROR = (component: string): string => + `Failed to load the SDK as the base URL for ${component} is not valid.`; + // ERROR const UNSUPPORTED_CONSENT_MANAGER_ERROR = ( context: string, @@ -272,8 +274,7 @@ export { STORAGE_UNAVAILABILITY_ERROR_PREFIX, SOURCE_CONFIG_FETCH_ERROR, SOURCE_CONFIG_OPTION_ERROR, - INTG_CDN_BASE_URL_ERROR, - PLUGINS_CDN_BASE_URL_ERROR, + DATA_PLANE_URL_ERROR, WRITE_KEY_VALIDATION_ERROR, DATA_PLANE_URL_VALIDATION_ERROR, READY_API_CALLBACK_ERROR, @@ -309,4 +310,5 @@ export { generateMisconfiguredPluginsWarning, INVALID_POLYFILL_URL_WARNING, SOURCE_DISABLED_ERROR, + COMPONENT_BASE_URL_ERROR, }; diff --git a/packages/analytics-js/src/state/slices/loadOptions.ts b/packages/analytics-js/src/state/slices/loadOptions.ts index 90a9c1bbb..47bf6d3f5 100644 --- a/packages/analytics-js/src/state/slices/loadOptions.ts +++ b/packages/analytics-js/src/state/slices/loadOptions.ts @@ -25,6 +25,7 @@ const defaultLoadOptions: LoadOptions = { destinationsQueueOptions: {}, queueOptions: {}, lockIntegrationsVersion: false, + lockPluginsVersion: false, uaChTrackLevel: 'none', plugins: [], useGlobalIntegrationsConfigInEvents: false, From 8b25cbea43274f71825986c0ce78919358ce5b15 Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:42:34 +0530 Subject: [PATCH 03/17] fix: debounce cookie requests to server (#1752) * fix: debounce cookie requests to server * fix: debounce logic --- .../UserSessionManager.test.ts | 73 ++++++++++++++----- .../userSessionManager/UserSessionManager.ts | 59 +++++++++------ .../userSessionManager/constants.ts | 8 +- .../src/components/utilities/globals.ts | 6 +- 4 files changed, 103 insertions(+), 43 deletions(-) diff --git a/packages/analytics-js/__tests__/components/userSessionManager/UserSessionManager.test.ts b/packages/analytics-js/__tests__/components/userSessionManager/UserSessionManager.test.ts index f5fe66d6e..7a3e89ea6 100644 --- a/packages/analytics-js/__tests__/components/userSessionManager/UserSessionManager.test.ts +++ b/packages/analytics-js/__tests__/components/userSessionManager/UserSessionManager.test.ts @@ -1501,44 +1501,79 @@ describe('User session manager', () => { }); describe('syncValueToStorage', () => { - it('should not call setServerSideCookie method in case isEnabledServerSideCookies state option is not set', () => { + it('should not call setServerSideCookies method in case isEnabledServerSideCookies state option is not set', () => { state.storage.entries.value = entriesWithOnlyCookieStorage; - const setServerSideCookieSpy = jest.spyOn(userSessionManager, 'setServerSideCookie'); + const setServerSideCookiesSpy = jest.spyOn(userSessionManager, 'setServerSideCookies'); userSessionManager.syncValueToStorage('anonymousId', 'dummy_anonymousId'); - expect(setServerSideCookieSpy).not.toHaveBeenCalled(); + + jest.advanceTimersByTime(1000); + + expect(setServerSideCookiesSpy).not.toHaveBeenCalled(); }); - it('should call setServerSideCookie method in case isEnabledServerSideCookies state option is set to true', done => { + + it('should call setServerSideCookies method in case isEnabledServerSideCookies state option is set to true', done => { state.serverCookies.isEnabledServerSideCookies.value = true; state.storage.entries.value = entriesWithOnlyCookieStorage; state.serverCookies.dataServiceUrl.value = 'https://dummy.dataplane.host.com/rsaRequest'; clientDataStoreCookie.set = jest.fn(); - const setServerSideCookieSpy = jest.spyOn(userSessionManager, 'setServerSideCookie'); + const setServerSideCookiesSpy = jest.spyOn(userSessionManager, 'setServerSideCookies'); userSessionManager.syncValueToStorage('anonymousId', 'dummy_anonymousId'); - expect(setServerSideCookieSpy).toHaveBeenCalledWith( - [{ name: 'rl_anonymous_id', value: 'dummy_anonymousId' }], - expect.any(Function), - expect.any(Object), - ); + setTimeout(() => { + expect(setServerSideCookiesSpy).toHaveBeenCalledWith( + [{ name: 'rl_anonymous_id', value: 'dummy_anonymousId' }], + expect.any(Function), + expect.any(Object), + ); expect(clientDataStoreCookie.set).toHaveBeenCalled(); done(); }, 1000); }); + describe('Cookie should be removed from server side', () => { const testCaseData = [null, undefined, '', {}]; it.each(testCaseData)('if value is "%s"', cookieValue => { + jest.useFakeTimers(); state.serverCookies.isEnabledServerSideCookies.value = true; state.storage.entries.value = entriesWithOnlyCookieStorage; - userSessionManager.setServerSideCookie = jest.fn(); + userSessionManager.setServerSideCookies = jest.fn(); clientDataStoreCookie.remove = jest.fn(); userSessionManager.syncValueToStorage('anonymousId', cookieValue); - expect(userSessionManager.setServerSideCookie).not.toHaveBeenCalled(); + + jest.advanceTimersByTime(1000); + + expect(userSessionManager.setServerSideCookies).not.toHaveBeenCalled(); expect(clientDataStoreCookie.remove).toHaveBeenCalled(); + jest.useRealTimers(); }); }); + + it('should debounce multiple cookie set network requests', done => { + state.serverCookies.isEnabledServerSideCookies.value = true; + state.storage.entries.value = entriesWithOnlyCookieStorage; + state.serverCookies.dataServiceUrl.value = 'https://dummy.dataplane.host.com/rsaRequest'; + clientDataStoreCookie.set = jest.fn(); + const setServerSideCookiesSpy = jest.spyOn(userSessionManager, 'setServerSideCookies'); + + // Even though we are calling syncValueToStorage multiple times in quick succession, only the + // last value should be sent to the server + userSessionManager.syncValueToStorage('anonymousId', 'dummy_anonymousId1'); + userSessionManager.syncValueToStorage('anonymousId', 'dummy_anonymousId2'); + userSessionManager.syncValueToStorage('anonymousId', 'dummy_anonymousId3'); + + setTimeout(() => { + expect(setServerSideCookiesSpy).toHaveBeenCalledTimes(1); + expect(setServerSideCookiesSpy).toHaveBeenCalledWith( + [{ name: 'rl_anonymous_id', value: 'dummy_anonymousId3' }], + expect.any(Function), + expect.any(Object), + ); + done(); + }, 1000); + }); }); - describe('setServerSideCookie', () => { + describe('setServerSideCookies', () => { beforeAll(() => { server.listen(); }); @@ -1561,7 +1596,7 @@ describe('User session manager', () => { const getEncryptedCookieDataSpy = jest.spyOn(userSessionManager, 'getEncryptedCookieData'); const makeRequestToSetCookieSpy = jest.spyOn(userSessionManager, 'makeRequestToSetCookie'); - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [{ name: 'key', value: 'sample_cookie_value_1234' }], () => {}, mockCookieStore, @@ -1586,7 +1621,7 @@ describe('User session manager', () => { domain: 'example.com', samesite: 'Lax', }; - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [ { name: 'key', @@ -1624,7 +1659,7 @@ describe('User session manager', () => { domain: 'example.com', samesite: 'Lax', }; - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [{ name: 'key', value: { prop1: 'sample property' } }], (name, val) => { mockCookieStore.set(name, val); @@ -1653,7 +1688,7 @@ describe('User session manager', () => { domain: 'example.com', samesite: 'Lax', }; - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [{ name: 'key', value: 'sample_cookie_value_1234' }], mockCallback, mockCookieStore, @@ -1673,7 +1708,7 @@ describe('User session manager', () => { domain: 'example.com', samesite: 'Lax', }; - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [{ name: 'key', value: 'sample_cookie_value_1234' }], mockCallback, mockCookieStore, @@ -1696,7 +1731,7 @@ describe('User session manager', () => { domain: 'example.com', samesite: 'Lax', }; - userSessionManager.setServerSideCookie( + userSessionManager.setServerSideCookies( [{ name: 'key', value: 'sample_cookie_value_1234' }], mockCallback, mockCookieStore, diff --git a/packages/analytics-js/src/components/userSessionManager/UserSessionManager.ts b/packages/analytics-js/src/components/userSessionManager/UserSessionManager.ts index a9121dbf8..b51a0bd64 100644 --- a/packages/analytics-js/src/components/userSessionManager/UserSessionManager.ts +++ b/packages/analytics-js/src/components/userSessionManager/UserSessionManager.ts @@ -60,7 +60,11 @@ import { } from './utils'; import { getReferringDomain } from '../utilities/url'; import { getReferrer } from '../utilities/page'; -import { DEFAULT_USER_SESSION_VALUES, USER_SESSION_STORAGE_KEYS } from './constants'; +import { + DEFAULT_USER_SESSION_VALUES, + SERVER_SIDE_COOKIES_DEBOUNCE_TIME, + USER_SESSION_STORAGE_KEYS, +} from './constants'; import type { CallbackFunction, CookieData, @@ -76,6 +80,7 @@ class UserSessionManager implements IUserSessionManager { errorHandler?: IErrorHandler; httpClient?: IHttpClient; logger?: ILogger; + serverSideCookieDebounceFuncs: Record; constructor( errorHandler?: IErrorHandler, @@ -90,6 +95,7 @@ class UserSessionManager implements IUserSessionManager { this.errorHandler = errorHandler; this.httpClient = httpClient; this.onError = this.onError.bind(this); + this.serverSideCookieDebounceFuncs = {} as Record; } /** @@ -288,19 +294,19 @@ class UserSessionManager implements IUserSessionManager { /** * A function to encrypt the cookie value and return the encrypted data - * @param cookieData + * @param cookiesData * @param store * @returns */ - getEncryptedCookieData(cookieData: CookieData[], store?: IStore): EncryptedCookieData[] { + getEncryptedCookieData(cookiesData: CookieData[], store?: IStore): EncryptedCookieData[] { const encryptedCookieData: EncryptedCookieData[] = []; - cookieData.forEach(e => { + cookiesData.forEach(cData => { const encryptedValue = store?.encrypt( - stringifyWithoutCircular(e.value, false, [], this.logger), + stringifyWithoutCircular(cData.value, false, [], this.logger), ); if (isDefinedAndNotNull(encryptedValue)) { encryptedCookieData.push({ - name: e.name, + name: cData.name, value: encryptedValue, }); } @@ -349,30 +355,28 @@ class UserSessionManager implements IUserSessionManager { * @param key cookie name * @param value encrypted cookie value */ - setServerSideCookie(cookieData: CookieData[], cb?: CallbackFunction, store?: IStore): void { + setServerSideCookies(cookiesData: CookieData[], cb?: CallbackFunction, store?: IStore): void { try { // encrypt cookies values - const encryptedCookieData = this.getEncryptedCookieData(cookieData, store); + const encryptedCookieData = this.getEncryptedCookieData(cookiesData, store); if (encryptedCookieData.length > 0) { // make request to data service to set the cookie from server side this.makeRequestToSetCookie(encryptedCookieData, (res, details) => { if (details?.xhr?.status === 200) { - cookieData.forEach(each => { - const cookieValue = store?.get(each.name); - const before = stringifyWithoutCircular(each.value, false, []); + cookiesData.forEach(cData => { + const cookieValue = store?.get(cData.name); + const before = stringifyWithoutCircular(cData.value, false, []); const after = stringifyWithoutCircular(cookieValue, false, []); if (after !== before) { - this.logger?.debug('Cookie value sent to server side', before); - this.logger?.debug('Cookie value set from server side', after); - this.logger?.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(each.name)); + this.logger?.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name)); if (cb) { - cb(each.name, each.value); + cb(cData.name, cData.value); } } }); } else { this.logger?.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status)); - cookieData.forEach(each => { + cookiesData.forEach(each => { if (cb) { cb(each.name, each.value); } @@ -382,7 +386,7 @@ class UserSessionManager implements IUserSessionManager { } } catch (e) { this.onError(e, FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR); - cookieData.forEach(each => { + cookiesData.forEach(each => { if (cb) { cb(each.name, each.value); } @@ -413,12 +417,23 @@ class UserSessionManager implements IUserSessionManager { state.serverCookies.isEnabledServerSideCookies.value && storageType === COOKIE_STORAGE ) { - this.setServerSideCookie( - [{ name: key, value }], - (cookieName, cookieValue) => { - curStore?.set(cookieName, cookieValue); + if (this.serverSideCookieDebounceFuncs[sessionKey]) { + (globalThis as typeof window).clearTimeout( + this.serverSideCookieDebounceFuncs[sessionKey], + ); + } + + this.serverSideCookieDebounceFuncs[sessionKey] = (globalThis as typeof window).setTimeout( + () => { + this.setServerSideCookies( + [{ name: key, value }], + (cookieName, cookieValue) => { + curStore?.set(cookieName, cookieValue); + }, + curStore, + ); }, - curStore, + SERVER_SIDE_COOKIES_DEBOUNCE_TIME, ); } else { curStore?.set(key, value); diff --git a/packages/analytics-js/src/components/userSessionManager/constants.ts b/packages/analytics-js/src/components/userSessionManager/constants.ts index a47f207ae..3463fd3bb 100644 --- a/packages/analytics-js/src/components/userSessionManager/constants.ts +++ b/packages/analytics-js/src/components/userSessionManager/constants.ts @@ -25,4 +25,10 @@ const DEFAULT_USER_SESSION_VALUES = { authToken: null, }; -export { USER_SESSION_STORAGE_KEYS, DEFAULT_USER_SESSION_VALUES }; +const SERVER_SIDE_COOKIES_DEBOUNCE_TIME = 10; // milliseconds + +export { + USER_SESSION_STORAGE_KEYS, + DEFAULT_USER_SESSION_VALUES, + SERVER_SIDE_COOKIES_DEBOUNCE_TIME, +}; diff --git a/packages/analytics-js/src/components/utilities/globals.ts b/packages/analytics-js/src/components/utilities/globals.ts index 1d3ca6d3e..768659f51 100644 --- a/packages/analytics-js/src/components/utilities/globals.ts +++ b/packages/analytics-js/src/components/utilities/globals.ts @@ -39,7 +39,11 @@ const getExposedGlobal = ( ]; }; -function debounce(func: DebouncedFunction, thisArg: any, delay: number = DEBOUNCED_TIMEOUT_MS) { +function debounce( + func: DebouncedFunction, + thisArg: any, + delay: number = DEBOUNCED_TIMEOUT_MS, +): DebouncedFunction { let timeoutId: number; return (...args: any[]) => { From 2eea5a1ff5f44aee82575e76a4e2f7d428740944 Mon Sep 17 00:00:00 2001 From: Mihir Bhalala <77438541+mihir-4116@users.noreply.github.com> Date: Thu, 13 Jun 2024 09:08:20 +0530 Subject: [PATCH 04/17] chore: migrate all lodash usages with ramda in web device mode integrations (#1684) * chore: migrate all lodash usages with ramda in web device mode integrations * chore: address comments * chore: fix test case differences * chore: fix package-lock.json * chore: add test cases * chore: address comments * chore: address comments by coderabbit * chore: address comments --------- Co-authored-by: Sudip Paul <67197965+ItsSudip@users.noreply.github.com> Co-authored-by: ItsSudip --- package-lock.json | 1217 +++++++++-------- .../integrations/AdobeAnalytics/util.test.js | 255 ++++ .../integrations/Braze/browser.test.js | 88 +- .../__tests__/utils/commonUtils.test.js | 102 ++ .../analytics-js-integrations/package.json | 12 +- .../src/integrations/AdobeAnalytics/util.js | 12 +- .../src/integrations/Braze/browser.js | 14 +- .../src/integrations/FacebookPixel/utils.js | 2 +- .../src/utils/commonUtils.js | 33 +- .../src/utils/utils.js | 2 +- .../__tests__/Analytics.test.ts | 42 + .../src/Analytics.ts | 9 +- 12 files changed, 1123 insertions(+), 665 deletions(-) create mode 100644 packages/analytics-js-integrations/__tests__/integrations/AdobeAnalytics/util.test.js diff --git a/package-lock.json b/package-lock.json index 8b04068f8..62bf03b20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -164,12 +164,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", - "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.24.6", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -177,9 +177,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", - "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", "dev": true, "engines": { "node": ">=6.9.0" @@ -234,12 +234,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz", - "integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6", + "@babel/types": "^7.24.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -249,37 +249,38 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz", - "integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.6.tgz", - "integrity": "sha512-+wnfqc5uHiMYtvRX7qu80Toef8BXeh4HHR1SPeonGb1SKPniNEd4a/nlaJJMv/OIEYvIVavvo0yR7u10Gqz0Iw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", - "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.6", - "@babel/helper-validator-option": "^7.24.6", + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -289,19 +290,19 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.6.tgz", - "integrity": "sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", + "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", "semver": "^6.3.1" }, "engines": { @@ -312,12 +313,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.6.tgz", - "integrity": "sha512-C875lFBIWWwyv6MHZUG9HmRrlTDgOsLWZfYR0nW69gaKJNe0/Mpxx5r0EID2ZdHQkdUmQo2t0uNckTL08/1BgA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", + "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", "semver": "^6.3.1" }, @@ -345,74 +346,79 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", - "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.6.tgz", - "integrity": "sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", + "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", - "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", - "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-module-imports": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -422,35 +428,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.6.tgz", - "integrity": "sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz", - "integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.6.tgz", - "integrity": "sha512-1Qursq9ArRZPAMOZf/nuzVW8HgJLkTB9y9LfP4lW2MVp4e9WkLJDovfKBxoDcCk6VuzIxyqWHyBoaCtSRP10yg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-wrap-function": "^7.24.6" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -460,14 +466,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.6.tgz", - "integrity": "sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-member-expression-to-functions": "^7.24.6", - "@babel/helper-optimise-call-expression": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -477,102 +483,105 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", - "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.6.tgz", - "integrity": "sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", - "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", - "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", - "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.6.tgz", - "integrity": "sha512-f1JLrlw/jbiNfxvdrfBgio/gRBk3yTAEJWirpAkiJG2Hb22E7cEYKHWo0dFPTv/niPovzIdPdEDetrv6tC6gPQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.24.6", - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz", - "integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", "dev": true, "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", - "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -582,9 +591,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -594,13 +603,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.6.tgz", - "integrity": "sha512-bYndrJ6Ph6Ar+GaB5VAc0JPoP80bQCm4qon6JEzXfRl5QZyQ8Ur1K6k7htxWmPA5z+k7JQvaMUrtXlqclWYzKw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -610,12 +619,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.6.tgz", - "integrity": "sha512-iVuhb6poq5ikqRq2XWU6OQ+R5o9wF+r/or9CeUyovgptz0UlnK4/seOQ1Istu/XybYjAhQv1FRSSfHHufIku5Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -625,14 +634,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.6.tgz", - "integrity": "sha512-c8TER5xMDYzzFcGqOEp9l4hvB7dcbhcGjcLVwxWfe4P5DOafdwjsBJZKsmv+o3aXh7NhopvayQIovHrh2zSRUQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", - "@babel/plugin-transform-optional-chaining": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -642,13 +651,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.6.tgz", - "integrity": "sha512-z8zEjYmwBUHN/pCF3NuWBhHQjJCrd33qAi8MgANfMrAvn72k2cImT8VjK9LJFu4ysOLJqhfkYYb3MvwANRUNZQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -675,14 +684,14 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.6.tgz", - "integrity": "sha512-8DjR0/DzlBhz2SVi9a19/N2U5+C3y3rseXuyoKL9SP8vnbewscj1eHZtL6kpEn4UCuUmqEo0mvqyDYRFoN2gpA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz", + "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/plugin-syntax-decorators": "^7.24.6" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-decorators": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -779,12 +788,12 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.6.tgz", - "integrity": "sha512-gInH8LEqBp+wkwTVihCd/qf+4s28g81FZyvlIbAurHk9eSiItEKG7E0uNK2UdpgsD79aJVAW3R3c85h0YJ0jsw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz", + "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -818,12 +827,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.6.tgz", - "integrity": "sha512-BE6o2BogJKJImTmGpkmOic4V0hlRRxVtzqxiSPa8TIFxyhi4EFjHm08nq1M4STK4RytuLMgnSz0/wfflvGFNOg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -833,12 +842,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.6.tgz", - "integrity": "sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -872,12 +881,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.6.tgz", - "integrity": "sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -989,12 +998,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.6.tgz", - "integrity": "sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1035,14 +1044,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.6.tgz", - "integrity": "sha512-VEP2o4iR2DqQU6KPgizTW2mnMx6BG5b5O9iQdrW9HesLkv8GIA8x2daXBQxw1MrsIkFQGA/iJ204CKoQ8UcnAA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-remap-async-to-generator": "^7.24.6", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1053,14 +1062,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.6.tgz", - "integrity": "sha512-NTBA2SioI3OsHeIn6sQmhvXleSl9T70YY/hostQLveWs0ic+qvbA3fa0kwAwQ0OA/XGaAerNZRQGJyRfhbJK4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-remap-async-to-generator": "^7.24.6" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1070,12 +1079,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.6.tgz", - "integrity": "sha512-XNW7jolYHW9CwORrZgA/97tL/k05qe/HL0z/qqJq1mdWhwwCM6D4BJBV7wAz9HgFziN5dTOG31znkVIzwxv+vw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1085,12 +1094,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.6.tgz", - "integrity": "sha512-S/t1Xh4ehW7sGA7c1j/hiOBLnEYCp/c2sEG4ZkL8kI1xX9tW2pqJTCHKtdhe/jHKt8nG0pFCrDHUXd4DvjHS9w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1100,13 +1109,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.6.tgz", - "integrity": "sha512-j6dZ0Z2Z2slWLR3kt9aOmSIrBvnntWjMDN/TVcMPxhXMLmJVqX605CBRlcGI4b32GMbfifTEsdEjGjiE+j/c3A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1116,13 +1125,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.6.tgz", - "integrity": "sha512-1QSRfoPI9RoLRa8Mnakc6v3e0gJxiZQTYrMfLn+mD0sz5+ndSzwymp2hDcYJTyT0MOn0yuWzj8phlIvO72gTHA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -1133,18 +1142,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.6.tgz", - "integrity": "sha512-+fN+NO2gh8JtRmDSOB6gaCVo36ha8kfCW1nMq2Gc0DABln0VcHN4PrALDvF5/diLzIRKptC7z/d7Lp64zk92Fg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", + "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", "globals": "^11.1.0" }, "engines": { @@ -1155,13 +1164,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.6.tgz", - "integrity": "sha512-cRzPobcfRP0ZtuIEkA8QzghoUpSB3X3qSH5W2+FzG+VjWbJXExtx0nbRqwumdBN1x/ot2SlTNQLfBCnPdzp6kg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/template": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1171,12 +1180,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.6.tgz", - "integrity": "sha512-YLW6AE5LQpk5npNXL7i/O+U9CE4XsBCuRPgyjl1EICZYKmcitV+ayuuUGMJm2lC1WWjXYszeTnIxF/dq/GhIZQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", + "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1186,13 +1195,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.6.tgz", - "integrity": "sha512-rCXPnSEKvkm/EjzOtLoGvKseK+dS4kZwx1HexO3BtRtgL0fQ34awHn34aeSHuXtZY2F8a1X8xqBBPRtOxDVmcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1202,12 +1211,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.6.tgz", - "integrity": "sha512-/8Odwp/aVkZwPFJMllSbawhDAO3UJi65foB00HYnK/uXvvCPm0TAXSByjz1mpRmp0q6oX2SIxpkUOpPFHk7FLA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1217,12 +1226,12 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.6.tgz", - "integrity": "sha512-vpq8SSLRTBLOHUZHSnBqVo0AKX3PBaoPs2vVzYVWslXDTDIpwAcCDtfhUcHSQQoYoUvcFPTdC8TZYXu9ZnLT/w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -1233,13 +1242,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.6.tgz", - "integrity": "sha512-EemYpHtmz0lHE7hxxxYEuTYOOBZ43WkDgZ4arQ4r+VX9QHuNZC+WH3wUWmRNvR8ECpTRne29aZV6XO22qpOtdA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1249,12 +1258,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.6.tgz", - "integrity": "sha512-inXaTM1SVrIxCkIJ5gqWiozHfFMStuGbGJAxZFBoHcRRdDP0ySLb3jH6JOwmfiinPwyMZqMBX+7NBDCO4z0NSA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -1265,13 +1274,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.6.tgz", - "integrity": "sha512-n3Sf72TnqK4nw/jziSqEl1qaWPbCRw2CziHH+jdRYvw4J6yeCzsj4jdw8hIntOEeDGTmHVe2w4MVL44PN0GMzg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1281,14 +1290,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.6.tgz", - "integrity": "sha512-sOajCu6V0P1KPljWHKiDq6ymgqB+vfo3isUS4McqW1DZtvSVU2v/wuMhmRmkg3sFoq6GMaUUf8W4WtoSLkOV/Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1298,12 +1307,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.6.tgz", - "integrity": "sha512-Uvgd9p2gUnzYJxVdBLcU0KurF8aVhkmVyMKW4MIY1/BByvs3EBpv45q01o7pRTVmTvtQq5zDlytP3dcUgm7v9w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -1314,12 +1323,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.6.tgz", - "integrity": "sha512-f2wHfR2HF6yMj+y+/y07+SLqnOSwRp8KYLpQKOzS58XLVlULhXbiYcygfXQxJlMbhII9+yXDwOUFLf60/TL5tw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1329,12 +1338,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.6.tgz", - "integrity": "sha512-EKaWvnezBCMkRIHxMJSIIylzhqK09YpiJtDbr2wsXTwnO0TxyjMUkaw4RlFIZMIS0iDj0KyIg7H7XCguHu/YDA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1345,12 +1354,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.6.tgz", - "integrity": "sha512-9g8iV146szUo5GWgXpRbq/GALTnY+WnNuRTuRHWWFfWGbP9ukRL0aO/jpu9dmOPikclkxnNsjY8/gsWl6bmZJQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1360,13 +1369,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.6.tgz", - "integrity": "sha512-eAGogjZgcwqAxhyFgqghvoHRr+EYRQPFjUXrTYKBRb5qPnAVxOOglaxc4/byHqjvq/bqO2F3/CGwTHsgKJYHhQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1376,14 +1385,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.6.tgz", - "integrity": "sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", + "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1393,15 +1402,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.6.tgz", - "integrity": "sha512-xg1Z0J5JVYxtpX954XqaaAT6NpAY6LtZXvYFCJmGFJWwtlz2EmJoR8LycFRGNE8dBKizGWkGQZGegtkV8y8s+w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.24.6", - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1411,13 +1420,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.6.tgz", - "integrity": "sha512-esRCC/KsSEUvrSjv5rFYnjZI6qv4R1e/iHQrqwbZIoRJqk7xCvEUiN7L1XrmW5QSmQe3n1XD88wbgDTWLbVSyg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1427,13 +1436,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.6.tgz", - "integrity": "sha512-6DneiCiu91wm3YiNIGDWZsl6GfTTbspuj/toTEqLh9d4cx50UIzSdg+T96p8DuT7aJOBRhFyaE9ZvTHkXrXr6Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1443,12 +1452,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.6.tgz", - "integrity": "sha512-f8liz9JG2Va8A4J5ZBuaSdwfPqN6axfWRK+y66fjKYbwf9VBLuq4WxtinhJhvp1w6lamKUwLG0slK2RxqFgvHA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1458,12 +1467,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.6.tgz", - "integrity": "sha512-+QlAiZBMsBK5NqrBWFXCYeXyiU1y7BQ/OYaiPAcQJMomn5Tyg+r5WuVtyEuvTbpV7L25ZSLfE+2E9ywj4FD48A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -1474,12 +1483,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.6.tgz", - "integrity": "sha512-6voawq8T25Jvvnc4/rXcWZQKKxUNZcKMS8ZNrjxQqoRFernJJKjE3s18Qo6VFaatG5aiX5JV1oPD7DbJhn0a4Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -1505,15 +1514,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.6.tgz", - "integrity": "sha512-OKmi5wiMoRW5Smttne7BwHM8s/fb5JFs+bVGNSeHWzwZkWXWValR1M30jyXo1s/RaqgwwhEC62u4rFH/FBcBPg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.6" + "@babel/plugin-transform-parameters": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1523,13 +1532,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.6.tgz", - "integrity": "sha512-N/C76ihFKlZgKfdkEYKtaRUtXZAgK7sOY4h2qrbVbVTXPrKGIi8aww5WGe/+Wmg8onn8sr2ut6FXlsbu/j6JHg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-replace-supers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1539,12 +1548,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.6.tgz", - "integrity": "sha512-L5pZ+b3O1mSzJ71HmxSCmTVd03VOT2GXOigug6vDYJzE5awLI7P1g0wFcdmGuwSDSrQ0L2rDOe/hHws8J1rv3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -1555,13 +1564,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.6.tgz", - "integrity": "sha512-cHbqF6l1QP11OkYTYQ+hhVx1E017O5ZcSPXk9oODpqhcAD1htsWG2NpHrrhthEO2qZomLK0FXS+u7NfrkF5aOQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", + "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -1572,12 +1581,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.6.tgz", - "integrity": "sha512-ST7guE8vLV+vI70wmAxuZpIKzVjvFX9Qs8bl5w6tN/6gOypPWUmMQL2p7LJz5E63vEGrDhAiYetniJFyBH1RkA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1587,13 +1596,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.6.tgz", - "integrity": "sha512-T9LtDI0BgwXOzyXrvgLTT8DFjCC/XgWLjflczTLXyvxbnSR/gpv0hbmzlHE/kmh9nOvlygbamLKRo6Op4yB6aw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1603,14 +1612,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.6.tgz", - "integrity": "sha512-Qu/ypFxCY5NkAnEhCF86Mvg3NSabKsh/TPpBVswEdkGl7+FbsYHy1ziRqJpwGH4thBdQHh8zx+z7vMYmcJ7iaQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -1621,12 +1630,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.6.tgz", - "integrity": "sha512-oARaglxhRsN18OYsnPTpb8TcKQWDYNsPNmTnx5++WOAsUJ0cSC/FZVlIJCKvPbU4yn/UXsS0551CFKJhN0CaMw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1636,12 +1645,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.6.tgz", - "integrity": "sha512-SMDxO95I8WXRtXhTAc8t/NFQUT7VYbIWwJCJgEli9ml4MhqUMh4S6hxgH6SmAC3eAQNWCDJFxcFeEt9w2sDdXg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", + "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1652,12 +1661,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.6.tgz", - "integrity": "sha512-DcrgFXRRlK64dGE0ZFBPD5egM2uM8mgfrvTMOSB2yKzOtjpGegVYkzh3s1zZg1bBck3nkXiaOamJUqK3Syk+4A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1687,12 +1696,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.6.tgz", - "integrity": "sha512-xnEUvHSMr9eOWS5Al2YPfc32ten7CXdH7Zwyyk7IqITg4nX61oHj+GxpNvl+y5JHjfN3KXE2IV55wAWowBYMVw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1702,13 +1711,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.6.tgz", - "integrity": "sha512-h/2j7oIUDjS+ULsIrNZ6/TKG97FgmEk1PXryk/HQq6op4XUUUwif2f69fJrzK0wza2zjCS1xhXmouACaWV5uPA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1718,12 +1727,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.6.tgz", - "integrity": "sha512-fN8OcTLfGmYv7FnDrsjodYBo1DhPL3Pze/9mIIE2MGCT1KgADYIOD7rEglpLHZj8PZlC/JFX5WcD+85FLAQusw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1733,12 +1742,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.6.tgz", - "integrity": "sha512-BJbEqJIcKwrqUP+KfUIkxz3q8VzXe2R8Wv8TaNgO1cx+nNavxn/2+H8kp9tgFSOL6wYPPEgFvU6IKS4qoGqhmg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1748,12 +1757,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.6.tgz", - "integrity": "sha512-IshCXQ+G9JIFJI7bUpxTE/oA2lgVLAIK8q1KdJNoPXOpvRaNjMySGuvLfBw/Xi2/1lLo953uE8hyYSDW3TSYig==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", + "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1763,15 +1772,15 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.6.tgz", - "integrity": "sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.7.tgz", + "integrity": "sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.6", - "@babel/helper-create-class-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6", - "@babel/plugin-syntax-typescript": "^7.24.6" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1781,12 +1790,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.6.tgz", - "integrity": "sha512-bKl3xxcPbkQQo5eX9LjjDpU2xYHeEeNQbOhj0iPvetSzA+Tu9q/o5lujF4Sek60CM6MgYvOS/DJuwGbiEYAnLw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1796,13 +1805,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.6.tgz", - "integrity": "sha512-8EIgImzVUxy15cZiPii9GvLZwsy7Vxc+8meSlR3cXFmBIl5W5Tn9LGBf7CDKkHj4uVfNXCJB8RsVfnmY61iedA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1812,13 +1821,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.6.tgz", - "integrity": "sha512-pssN6ExsvxaKU638qcWb81RrvvgZom3jDgU/r5xFZ7TONkZGFf4MhI2ltMb8OcQWhHyxgIavEU+hgqtbKOmsPA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1828,13 +1837,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.6.tgz", - "integrity": "sha512-quiMsb28oXWIDK0gXLALOJRXLgICLiulqdZGOaPPd0vRT7fQp74NtdADAVu+D8s00C+0Xs0MxVP0VKF/sZEUgw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.6", - "@babel/helper-plugin-utils": "^7.24.6" + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1990,9 +1999,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", - "integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -2002,33 +2011,33 @@ } }, "node_modules/@babel/template": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", - "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz", - "integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/generator": "^7.24.6", - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-function-name": "^7.24.6", - "@babel/helper-hoist-variables": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2037,13 +2046,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", - "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2600,9 +2609,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2788,28 +2797,28 @@ } }, "node_modules/@inquirer/confirm": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.8.tgz", - "integrity": "sha512-f3INZ+ca4dQdn+MQiq1yP/mOIR/Oc8BLRYuDh6ciToWd6z4W8yArfzjBCMQ0BPY8PcJKwZxGIt8Z6yNT32eSTw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.9.tgz", + "integrity": "sha512-UF09aejxCi4Xqm6N/jJAiFXArXfi9al52AFaSD+2uIHnhZGtd1d6lIGTRMPouVSJxbGEi+HkOWSYaiEY/+szUw==", "dev": true, "dependencies": { - "@inquirer/core": "^8.2.1", - "@inquirer/type": "^1.3.2" + "@inquirer/core": "^8.2.2", + "@inquirer/type": "^1.3.3" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/core": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.2.1.tgz", - "integrity": "sha512-TIcuQMn2qrtyYe0j136UpHeYpk7AcR/trKeT/7YY0vRgcS9YSfJuQ2+PudPhSofLLsHNnRYAHScQCcVZrJkMqA==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.2.2.tgz", + "integrity": "sha512-K8SuNX45jEFlX3EBJpu9B+S2TISzMPGXZIuJ9ME924SqbdW6Pt6fIkKvXg7mOEOKJ4WxpQsxj0UTfcL/A434Ww==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.2", - "@inquirer/type": "^1.3.2", + "@inquirer/figures": "^1.0.3", + "@inquirer/type": "^1.3.3", "@types/mute-stream": "^0.0.4", - "@types/node": "^20.12.12", + "@types/node": "^20.12.13", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", @@ -2824,6 +2833,15 @@ "node": ">=18" } }, + "node_modules/@inquirer/core/node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@inquirer/core/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2927,18 +2945,18 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.2.tgz", - "integrity": "sha512-4F1MBwVr3c/m4bAUef6LgkvBfSjzwH+OfldgHqcuacWwSUetFebM2wi58WfG9uk1rR98U6GwLed4asLJbwdV5w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.3.tgz", + "integrity": "sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@inquirer/type": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.3.2.tgz", - "integrity": "sha512-5Frickan9c89QbPkSu6I6y8p+9eR6hZkdPahGmNDsTFX8FHLPAozyzCZMKUeW8FyYwnlCKUjqIEqxY+UctARiw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.3.3.tgz", + "integrity": "sha512-xTUt0NulylX27/zMx04ZYar/kr1raaiFTVvQ5feljQsiAgdm0WPj4S73/ye0fbslh+15QrIuDvfCXTek7pMY5A==", "dev": true, "engines": { "node": ">=18" @@ -3961,9 +3979,9 @@ } }, "node_modules/@mdn/browser-compat-data": { - "version": "5.5.29", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.29.tgz", - "integrity": "sha512-NHdG3QOiAsxh8ygBSKMa/WaNJwpNt87uVqW+S2RlnSqgeRdk+L3foNWTX6qd0I3NHSlCFb47rgopeNCJtRDY5A==", + "version": "5.5.31", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.31.tgz", + "integrity": "sha512-k2cK7WJKjWkcU3TY7yIc1dK6RZY8nqm+wNiR9uX9+Qcy5Gy9XzWoWNm+sQ/78OtBi6aTTXrK3HEopidhXasD+w==", "dev": true }, "node_modules/@mswjs/cookies": { @@ -6029,14 +6047,14 @@ } }, "node_modules/@swc/core": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", - "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.25.tgz", + "integrity": "sha512-qdGEIdLVoTjEQ7w72UyyQ0wLFY4XbHfZiidmPHKJQsvSXzdpHXxPdlTCea/mY4AhMqo/M+pvkJSXJAxZnFl7qw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@swc/counter": "^0.1.2", - "@swc/types": "0.1.7" + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.7" }, "engines": { "node": ">=10" @@ -6046,19 +6064,19 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.5.7", - "@swc/core-darwin-x64": "1.5.7", - "@swc/core-linux-arm-gnueabihf": "1.5.7", - "@swc/core-linux-arm64-gnu": "1.5.7", - "@swc/core-linux-arm64-musl": "1.5.7", - "@swc/core-linux-x64-gnu": "1.5.7", - "@swc/core-linux-x64-musl": "1.5.7", - "@swc/core-win32-arm64-msvc": "1.5.7", - "@swc/core-win32-ia32-msvc": "1.5.7", - "@swc/core-win32-x64-msvc": "1.5.7" + "@swc/core-darwin-arm64": "1.5.25", + "@swc/core-darwin-x64": "1.5.25", + "@swc/core-linux-arm-gnueabihf": "1.5.25", + "@swc/core-linux-arm64-gnu": "1.5.25", + "@swc/core-linux-arm64-musl": "1.5.25", + "@swc/core-linux-x64-gnu": "1.5.25", + "@swc/core-linux-x64-musl": "1.5.25", + "@swc/core-win32-arm64-msvc": "1.5.25", + "@swc/core-win32-ia32-msvc": "1.5.25", + "@swc/core-win32-x64-msvc": "1.5.25" }, "peerDependencies": { - "@swc/helpers": "^0.5.0" + "@swc/helpers": "*" }, "peerDependenciesMeta": { "@swc/helpers": { @@ -6067,9 +6085,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", - "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.25.tgz", + "integrity": "sha512-YbD0SBgVJS2DM0vwJTU5m7+wOyCjHPBDMf3nCBJQzFZzOLzK11eRW7SzU2jhJHr9HI9sKcNFfN4lIC2Sj+4inA==", "cpu": [ "arm64" ], @@ -6083,9 +6101,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", - "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.25.tgz", + "integrity": "sha512-OhP4TROT6gQuozn+ah0Y4UidSdgDmxwtQq3lgCUIAxJYErJAQ82/Y0kve2UaNmkSGjOHU+/b4siHPrYTkXOk0Q==", "cpu": [ "x64" ], @@ -6099,9 +6117,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", - "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.25.tgz", + "integrity": "sha512-tNmUfrAHxN2gvYPyYNnHx2CYlPO7DGAUuK/bZrqawu++djcg+atAV3eI3XYJgmHId7/sYAlDQ9wjkrOLofFjVg==", "cpu": [ "arm" ], @@ -6115,9 +6133,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", - "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.25.tgz", + "integrity": "sha512-stzpke+bRaNFM/HrZPRjX0aQZ86S/2DChVCwb8NAV1n5lu9mz1CS750y7WbbtX/KZjk92FsCeRy2qwkvjI0gWw==", "cpu": [ "arm64" ], @@ -6131,9 +6149,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", - "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.25.tgz", + "integrity": "sha512-UckUfDYedish/bj2V1jgQDGgouLhyRpG7jgF3mp8jHir11V2K6JiTyjFoz99eOiclS3+hNdr4QLJ+ifrQMJNZw==", "cpu": [ "arm64" ], @@ -6147,9 +6165,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", - "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.25.tgz", + "integrity": "sha512-LwbJEgNT3lXbvz4WFzVNXNvs8DvxpoXjMZk9K9Hig8tmZQJKHC2qZTGomcyK5EFzfj2HBuBXZnAEW8ZT9PcEaA==", "cpu": [ "x64" ], @@ -6163,9 +6181,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", - "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.25.tgz", + "integrity": "sha512-rsepMTgml0EkswWkBpg3Wrjj5eqjwTzZN5omAn1klzXSZnClTrfeHvBuoIJYVr1yx+jmBkqySgME2p7+magUAw==", "cpu": [ "x64" ], @@ -6179,9 +6197,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", - "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.25.tgz", + "integrity": "sha512-DJDsLBsRBV3uQBShRK2x6fqzABp9RLNVxDUpTTvUjc7qywJ8vS/yn+POK/zCyVEqLagf1z/8D5CEQ+RAIJq1NA==", "cpu": [ "arm64" ], @@ -6195,9 +6213,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", - "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.25.tgz", + "integrity": "sha512-BARL1ulHol53MEKC1ZVWM3A3FP757UUgG5Q8v97za+4a1SaIgbwvAQyHDxMYWi9+ij+OapK8YnWjJcFa17g8dw==", "cpu": [ "ia32" ], @@ -6211,9 +6229,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", - "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.25.tgz", + "integrity": "sha512-o+MHUWrQI9iR6EusEV8eNU2Ezi3KtlhUR4gfptQN5MbVzlgjTvQbhiKpE1GYOxp+0BLBbKRwITKOcdhxfEJ2Uw==", "cpu": [ "x64" ], @@ -6596,17 +6614,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", - "integrity": "sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", "dev": true, "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/type-utils": "7.10.0", - "@typescript-eslint/utils": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -6630,16 +6648,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.10.0.tgz", - "integrity": "sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", "dev": true, "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/typescript-estree": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4" }, "engines": { @@ -6659,13 +6677,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz", - "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0" + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6676,13 +6694,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz", - "integrity": "sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.10.0", - "@typescript-eslint/utils": "7.10.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6703,9 +6721,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz", - "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6716,13 +6734,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz", - "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6771,15 +6789,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz", - "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/typescript-estree": "7.10.0" + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6793,12 +6811,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz", - "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/types": "7.12.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -7164,9 +7182,9 @@ } }, "node_modules/ajv": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", - "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", @@ -7477,17 +7495,20 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, "peer": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/arraybuffer.prototype.slice": { @@ -8532,9 +8553,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001623", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001623.tgz", - "integrity": "sha512-X/XhAVKlpIxWPpgRTnlgZssJrF0m6YtRA0QDWgsBNT12uZM6LPRydR7ip405Y3t1LamD8cP2TZFEDZFBf5ApcA==", + "version": "1.0.30001629", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001629.tgz", + "integrity": "sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==", "dev": true, "funding": [ { @@ -8728,9 +8749,9 @@ } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "engines": { "node": ">=6.0" @@ -10614,9 +10635,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.783", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.783.tgz", - "integrity": "sha512-bT0jEz/Xz1fahQpbZ1D7LgmPYZ3iHVY39NcWWro1+hA2IvjiPeaXtfSqrQ+nXjApMvQRE2ASt1itSLRrebHMRQ==", + "version": "1.4.791", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.791.tgz", + "integrity": "sha512-6FlqP0NSWvxFf1v+gHu+LCn5wjr1pmkj5nPr7BsxPnj41EDR4EWhK/KmQN0ytHUqgTR1lkpHRYxvHBLZFQtkKw==", "dev": true }, "node_modules/emittery": { @@ -10670,9 +10691,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", - "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -11376,30 +11397,30 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "version": "7.34.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz", + "integrity": "sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==", "dev": true, "peer": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", + "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" + "string.prototype.matchall": "^4.0.11" }, "engines": { "node": ">=4" @@ -14677,9 +14698,9 @@ } }, "node_modules/jackspeak": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", - "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -16732,9 +16753,9 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.3.tgz", + "integrity": "sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==", "dev": true, "bin": { "jiti": "bin/jiti.js" @@ -18715,9 +18736,9 @@ } }, "node_modules/msw/node_modules/type-fest": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.3.tgz", - "integrity": "sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.19.0.tgz", + "integrity": "sha512-CN2l+hWACRiejlnr68vY0/7734Kzu+9+TOslUXbSCQ1ruY9XIHDBSceVXCcHm/oXrdzhtLMMdJEKfemf1yXiZQ==", "dev": true, "engines": { "node": ">=16" @@ -21121,9 +21142,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.3.tgz", - "integrity": "sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.19.0.tgz", + "integrity": "sha512-CN2l+hWACRiejlnr68vY0/7734Kzu+9+TOslUXbSCQ1ruY9XIHDBSceVXCcHm/oXrdzhtLMMdJEKfemf1yXiZQ==", "dev": true, "engines": { "node": ">=16" @@ -21185,9 +21206,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.3.tgz", - "integrity": "sha512-Q08/0IrpvM+NMY9PA2rti9Jb+JejTddwmwmVQGskAlhtcrw1wsRzoR6ode6mR+OAabNa75w/dxedSUY2mlphaQ==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.19.0.tgz", + "integrity": "sha512-CN2l+hWACRiejlnr68vY0/7734Kzu+9+TOslUXbSCQ1ruY9XIHDBSceVXCcHm/oXrdzhtLMMdJEKfemf1yXiZQ==", "dev": true, "engines": { "node": ">=16" @@ -24902,9 +24923,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", - "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.3.tgz", + "integrity": "sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -25006,12 +25027,6 @@ "crypto-js": "4.2.0", "get-value": "3.0.1", "is": "3.3.0", - "lodash.get": "4.4.2", - "lodash.isempty": "4.4.0", - "lodash.isequal": "4.5.0", - "lodash.isundefined": "3.0.1", - "lodash.pickby": "4.6.0", - "lodash.tostring": "4.1.4", "md5": "2.3.0", "obj-case": "0.2.1", "on-body": "0.0.1", diff --git a/packages/analytics-js-integrations/__tests__/integrations/AdobeAnalytics/util.test.js b/packages/analytics-js-integrations/__tests__/integrations/AdobeAnalytics/util.test.js new file mode 100644 index 000000000..aa3155d62 --- /dev/null +++ b/packages/analytics-js-integrations/__tests__/integrations/AdobeAnalytics/util.test.js @@ -0,0 +1,255 @@ +import { + getDataFromContext, + handleLists, + setConfig, + mapMerchProductEvents, + get, +} from '../../../src/integrations/AdobeAnalytics/util'; + +let windowSpy; +beforeEach(() => { + windowSpy = jest.spyOn(window, 'window', 'get'); +}); + +afterEach(() => { + windowSpy.mockRestore(); +}); +describe('AdobeAnalytics Utility functions tests', () => { + describe('getDataFromContext Tests', () => { + it('should return an empty object when contextMap is empty', () => { + const contextMap = {}; + const rudderElement = { message: {} }; + const result = getDataFromContext(contextMap, rudderElement); + expect(result).toEqual({}); + }); + it('should return an object with values mapped from context and properties of rudder message', () => { + const contextMap = { + 'page.name': 'pName', + 'page.url': 'pUrl', + 'page.arr.0.name': 'p0Name', + }; + const rudderElement = { + message: { + context: { + page: { + name: 'Home Page', + url: 'https://example.com', + arr: [{ name: 'arrName' }], + }, + path: '/page1', + }, + properties: { + property1: 'value1', + property2: 'value2', + }, + }, + }; + const result = getDataFromContext(contextMap, rudderElement); + expect(result).toEqual({ + pName: 'Home Page', + pUrl: 'https://example.com', + p0Name: 'arrName', + }); + }); + it('should map values from top level properties of rudder message to keys specified in contextMap', () => { + const contextMap = { anonymousId: 'aId', userId: 'uId' }; + const rudderElement = { + message: { + anonymousId: '12345', + userId: '67890', + properties: { + property1: 'value1', + property2: 'value2', + userId: '67890', + }, + }, + }; + const result = getDataFromContext(contextMap, rudderElement); + expect(result).toEqual({ + aId: '12345', + uId: '67890', + }); + }); + }); + describe('handleLists Tests', () => { + // Sets list variable of window.s with correct delimiter and list name + it('should set list variable of window.s with correct delimiter and list name when mapping and delimiter are present', () => { + const rudderElement = { + message: { + properties: { + key1: 'value1', + key2: 'value2', + }, + }, + }; + windowSpy.mockImplementation(() => ({ + s: { list1: 'value1', list2: 'value2' }, + })); + const config = { + listMapping: [ + { from: 'key1', to: 'list1', delimiter: ',' }, + { from: 'key2', to: 'list2', delimiter: ';' }, + ], + }; + setConfig(config); + handleLists(rudderElement); + + expect(window.s.list1).toBe('value1'); + expect(window.s.list2).toBe('value2'); + }); + // Skips list variable update if mapping or delimiter is missing + it('should skip list variable update if mapping or delimiter is missing', () => { + const rudderElement = { + message: { + properties: { + key1: 'value1', + key2: 'value2', + }, + }, + }; + windowSpy.mockImplementation(() => ({ + s: { list1: 'value1', list2: undefined }, + })); + const config = { + listMapping: [ + { from: 'key1', to: 'list1', delimiter: ',' }, + { from: 'key3', to: 'list3', delimiter: ';' }, + ], + }; + setConfig(config); + + handleLists(rudderElement); + + expect(window.s.list1).toBe('value1'); + expect(window.s.list2).toBeUndefined(); + }); + }); + describe('mapMerchProductEvents', () => { + // Should return an empty array when productMerchEventToAdobeEventHashmap does not contain the event + it('should return an empty array when productMerchEventToAdobeEventHashmap does not contain the event', () => { + const event = 'testEvent'; + const properties = { + currencyProdMerch: 'someRandomData', + prodLevelCurrency: 'some RandomCurrency', + }; + const adobeEvent = 'testAdobeEvent'; + const config = { + productMerchEventToAdobeEvent: [ + { from: 'key1', to: 'list1', delimiter: ',' }, + { from: 'testEvent', to: 'Test Adobe Event', delimiter: ';' }, + ], + productMerchProperties: [ + { + productMerchProperties: 'currencyProdMerch', + }, + { + productMerchProperties: 'addressProdMerch', + }, + { + productMerchProperties: 'products.prodLevelCurrency', + }, + ], + productIdentifier: 'id', + }; + setConfig(config); + const result = mapMerchProductEvents(event, properties, adobeEvent); + + expect(result).toEqual([ + 'testAdobeEvent=someRandomData', + 'testAdobeEvent=some RandomCurrency', + ]); + }); + // Should handle gracefully when productMerchProperties is undefined + it('should handle gracefully when productMerchProperties is undefined', () => { + const event = 'testEvent'; + const properties = {}; + const adobeEvent = 'testAdobeEvent'; + const config = { + productMerchEventToAdobeEvent: { + testevent: 'testadobeevent', + }, + productMerchProperties: undefined, + productIdentifier: 'id', + }; + setConfig(config); + const result = mapMerchProductEvents(event, properties, adobeEvent); + + expect(result).toEqual([]); + }); + }); + describe('get tests', () => { + it('should retrieve a value from a nested object using a dot-separated string', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + email: 'john.doe@example.com', + }, + }; + const value = 'user.name'; + const result = get(context, value); + expect(result).toBe('John Doe'); + }); + it('should return undefined when the path is an empty string', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + }, + }; + const value = ''; + const result = get(context, value); + expect(result).toBeUndefined(); + }); + it('should return undefined when the key contains dot', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + 'keyWith.dot': 'value', + }, + }; + const value = 'user.keyWith.dot'; + const result = get(context, value); + expect(result).toBeUndefined(); + }); + it('should return undefined when the key contains dot', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + 'keyWith-dash': 'value', + }, + }; + const value = 'user.keyWith-dash'; + const result = get(context, value); + expect(result).toEqual('value'); + }); + it('should return correct value when the value is an array and provided index', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + 'keyWith-dash': 'value', + keyWithArrayVal: ['value1', 'value2'], + }, + }; + const value = 'user.keyWithArrayVal.1'; + const result = get(context, value); + expect(result).toEqual('value2'); + }); + it('should return undefined if the path is undefined', () => { + const context = { + user: { + id: '123', + name: 'John Doe', + 'keyWith-dash': 'value', + keyWithArrayVal: ['value1', 'value2'], + }, + }; + const value = undefined; + const result = get(context, value); + expect(result).toEqual(undefined); + }); + }); +}); diff --git a/packages/analytics-js-integrations/__tests__/integrations/Braze/browser.test.js b/packages/analytics-js-integrations/__tests__/integrations/Braze/browser.test.js index f55e3ca3f..81f62cfbd 100644 --- a/packages/analytics-js-integrations/__tests__/integrations/Braze/browser.test.js +++ b/packages/analytics-js-integrations/__tests__/integrations/Braze/browser.test.js @@ -74,7 +74,9 @@ afterAll(() => { describe('constructor', () => { it('should set the log level if provided', () => { const config = { appKey: 'APP_KEY', logLevel: 'debug' }; - const analytics = {}; + const analytics = { + logLevel: '0', + }; const destinationInfo = {}; const braze = new Braze(config, analytics, destinationInfo); expect(braze.trackAnonymousUser).toEqual(undefined); @@ -82,7 +84,18 @@ describe('constructor', () => { expect(braze.allowUserSuppliedJavascript).toEqual(false); expect(braze.appKey).toEqual('APP_KEY'); }); - + it('should set the log level if provided', () => { + const config = { logLevel: 'debug', dataCenter: 'eu' }; + const analytics = { + logLevel: '0', + }; + const destinationInfo = {}; + const braze = new Braze(config, analytics, destinationInfo); + expect(braze.trackAnonymousUser).toEqual(undefined); + expect(braze.enableBrazeLogging).toEqual(false); + expect(braze.allowUserSuppliedJavascript).toEqual(false); + expect(braze.appKey).toEqual(''); + }); // Add more tests for the constructor if needed }); @@ -94,8 +107,11 @@ describe('init', () => { enableBrazeLogging: false, dataCenter: 'US-03', allowUserSuppliedJavascript: false, + enablePushNotification: true, + }; + const analytics = { + userId: '1234', }; - const analytics = {}; const destinationInfo = {}; const braze = new Braze(config, analytics, destinationInfo); @@ -113,6 +129,30 @@ describe('init', () => { // Add more tests for the init method if needed }); +describe('isLoaded', () => { + it('should get false value with isLoaded', () => { + const config = {}; + const analytics = {}; + const destinationInfo = {}; + + const braze = new Braze(config, analytics, destinationInfo); + const isLoaded = braze.isLoaded(); + expect(isLoaded).toBe(false); + }); +}); + +describe('isLoaded', () => { + it('should get false value with isReady', () => { + const config = {}; + const analytics = {}; + const destinationInfo = {}; + + const braze = new Braze(config, analytics, destinationInfo); + const isLoaded = braze.isReady(); + expect(isLoaded).toBe(false); + }); +}); + describe('identify', () => { it('should call the necessary Braze methods to set user attributes', () => { const config = { @@ -139,7 +179,7 @@ describe('identify', () => { email: 'test@example.com', firstName: 'John', lastName: 'Doe', - gender: 'male', + gender: 1, phone: '1234567890', address: { country: 'USA', @@ -169,7 +209,7 @@ describe('identify', () => { expect(window.braze.getUser().setEmail).toHaveBeenCalledWith('test@example.com'); expect(window.braze.getUser().setFirstName).toHaveBeenCalledWith('John'); expect(window.braze.getUser().setLastName).toHaveBeenCalledWith('Doe'); - expect(window.braze.getUser().setGender).toHaveBeenCalledWith('m'); + expect(window.braze.getUser().setGender).toHaveBeenCalledWith(undefined); expect(window.braze.getUser().setPhoneNumber).toHaveBeenCalledWith('1234567890'); expect(window.braze.getUser().setCountry).toHaveBeenCalledWith('USA'); expect(window.braze.getUser().setHomeCity).toHaveBeenCalledWith('New York'); @@ -201,6 +241,7 @@ describe('identify', () => { userId: 'user123', context: { traits: { + customTrait: 'random data', email: 'updated@example.com', firstName: 'David', lastName: 'Doe', @@ -244,6 +285,7 @@ describe('identify', () => { jest.spyOn(window.braze.getUser(), 'setCountry'); jest.spyOn(window.braze.getUser(), 'setHomeCity'); jest.spyOn(window.braze.getUser(), 'setDateOfBirth'); + jest.spyOn(window.braze.getUser(), 'setCustomUserAttribute'); // Call the identify method braze.identify(rudderElement); @@ -256,6 +298,10 @@ describe('identify', () => { expect(window.braze.getUser().setCountry).toHaveBeenCalledWith('USA'); expect(window.braze.getUser().setHomeCity).toHaveBeenCalledWith('Austin'); expect(window.braze.getUser().setDateOfBirth).not.toHaveBeenCalled(); + expect(window.braze.getUser().setCustomUserAttribute).toHaveBeenCalledWith( + 'customTrait', + 'random data', + ); // Expect any other necessary Braze methods to be called // Expect Storage.setItem to be called with the updated payload @@ -273,6 +319,7 @@ describe('identify', () => { city: 'Austin', }, birthday: '1990-01-01', + customTrait: 'random data', }, }, }); @@ -968,7 +1015,7 @@ describe('hybrid mode', () => { dataCenter: 'US-03', enableHtmlInAppMessages: false, allowUserSuppliedJavascript: false, - connectionMode: 'hybrid' + connectionMode: 'hybrid', }; const analytics = {}; const destinationInfo = {}; @@ -982,11 +1029,11 @@ describe('hybrid mode', () => { const rudderElement = { message: { userId: 'user123', - type: "page", - name: "Home", + type: 'page', + name: 'Home', properties: { - title: "Home | RudderStack", - url: "http://www.rudderstack.com" + title: 'Home | RudderStack', + url: 'http://www.rudderstack.com', }, }, }; @@ -1006,7 +1053,7 @@ describe('hybrid mode', () => { dataCenter: 'US-03', enableHtmlInAppMessages: false, allowUserSuppliedJavascript: false, - connectionMode: 'hybrid' + connectionMode: 'hybrid', }; const analytics = {}; const destinationInfo = {}; @@ -1020,11 +1067,11 @@ describe('hybrid mode', () => { const rudderElement = { message: { userId: 'user123', - type: "page", - name: "Home", + type: 'page', + name: 'Home', properties: { - title: "Home | RudderStack", - url: "http://www.rudderstack.com" + title: 'Home | RudderStack', + url: 'http://www.rudderstack.com', }, }, }; @@ -1044,7 +1091,7 @@ describe('hybrid mode', () => { dataCenter: 'US-03', enableHtmlInAppMessages: false, allowUserSuppliedJavascript: false, - connectionMode: 'hybrid' + connectionMode: 'hybrid', }; const analytics = {}; const destinationInfo = {}; @@ -1058,11 +1105,11 @@ describe('hybrid mode', () => { const rudderElement = { message: { userId: 'user123', - type: "page", - name: "Home", + type: 'page', + name: 'Home', properties: { - title: "Home | RudderStack", - url: "http://www.rudderstack.com" + title: 'Home | RudderStack', + url: 'http://www.rudderstack.com', }, }, }; @@ -1073,5 +1120,4 @@ describe('hybrid mode', () => { // Expect the necessary Braze methods to be called with the correct values expect(window.braze.changeUser).toBeCalledTimes(0); }); - }); diff --git a/packages/analytics-js-integrations/__tests__/utils/commonUtils.test.js b/packages/analytics-js-integrations/__tests__/utils/commonUtils.test.js index da91ed6c0..eacc3e788 100644 --- a/packages/analytics-js-integrations/__tests__/utils/commonUtils.test.js +++ b/packages/analytics-js-integrations/__tests__/utils/commonUtils.test.js @@ -345,3 +345,105 @@ describe('pick', () => { expect(result).toEqual({ a: 1, c: 3, A: 4, C: 6 }); }); }); + +describe('isBlank', () => { + it('should return true when input is an empty string', () => { + const result = utils.isBlank(''); + expect(result).toBe(true); + }); + it('should return false when input is null', () => { + const result = utils.isBlank(null); + expect(result).toBe(false); + }); + it('should return true when input is a string of whitespaces', () => { + const result = utils.isBlank(' '); + expect(result).toBe(true); + }); + it('should return false when input is a valid string', () => { + const result = utils.isBlank('validString'); + expect(result).toBe(false); + }); + it('should return false when input is a valid number', () => { + const result = utils.isBlank(123456); + expect(result).toBe(false); + }); + + it('should return false when input is a valid object', () => { + const result = utils.isBlank({ key1: 'value1', key2: 'value2' }); + expect(result).toBe(false); + }); + it('should return false when input is a valid boolean', () => { + const result = utils.isBlank(false); + expect(result).toBe(false); + }); +}); + +describe('isNotEmpty', () => { + // returns false for empty string + it('should return false when input is an empty string', () => { + expect(utils.isNotEmpty('')).toBe(false); + }); + // returns false for null + it('should return false when input is null', () => { + expect(utils.isNotEmpty(null)).toBe(true); + }); + // returns true for non-empty string + it('should return true when input is a non-empty string', () => { + expect(utils.isNotEmpty('hello')).toBe(true); + }); + // returns false for empty object + it('should return false when input is an empty object', () => { + expect(utils.isNotEmpty({})).toBe(false); + }); + // returns true for non-empty object + it('should return true when input is a non-empty object', () => { + const obj = { key: 'value' }; + expect(utils.isNotEmpty(obj)).toBe(true); + }); + // returns true for booleans + it('should return true when input is a boolean', () => { + expect(utils.isNotEmpty(true)).toBe(false); + expect(utils.isNotEmpty(false)).toBe(false); + }); + // returns true for numbers + it('should return true when input is a number', () => { + expect(utils.isNotEmpty(5)).toBe(false); + expect(utils.isNotEmpty(0)).toBe(false); + expect(utils.isNotEmpty(-10)).toBe(false); + expect(utils.isNotEmpty(0.444548)).toBe(false); + }); + // returns false for undefined + it('should return false when input is undefined', () => { + expect(utils.isNotEmpty(undefined)).toBe(false); + }); + // returns true for non-empty array + it('should return true when input is a non-empty array', () => { + const input = [1, 2, 3]; + expect(utils.isNotEmpty(input)).toBe(true); + }); + // handles strings with only whitespace correctly + it('should return false when input is a string with only whitespace', () => { + expect(utils.isNotEmpty(' ')).toBe(true); + }); + // returns false for empty array + it('should return false when input is an empty array', () => { + expect(utils.isNotEmpty([])).toBe(false); + }); + // handles mixed data types within arrays + it('should return true when input is an array with mixed data types', () => { + const input = [1, 'hello', { key: 'value' }, true]; + expect(utils.isNotEmpty(input)).toBe(true); + }); + // handles functions and symbols correctly + it('should return true for functions and symbols', () => { + const func = () => {}; + const sym = Symbol('test'); + expect(utils.isNotEmpty(func)).toBe(false); + expect(utils.isNotEmpty(sym)).toBe(false); + }); + // handles Date objects correctly + it('should return true when input is a Date object', () => { + const date = new Date(); + expect(utils.isNotEmpty(date)).toBe(true); + }); +}); diff --git a/packages/analytics-js-integrations/package.json b/packages/analytics-js-integrations/package.json index e3d072912..9f6be58d9 100644 --- a/packages/analytics-js-integrations/package.json +++ b/packages/analytics-js-integrations/package.json @@ -87,19 +87,13 @@ "dependencies": { "@rudderstack/analytics-js-common": "*", "@ndhoule/each": "2.0.1", - "lodash.get": "4.4.2", - "lodash.isequal": "4.5.0", - "obj-case": "0.2.1", - "on-body": "0.0.1", - "md5": "2.3.0", "crypto-js": "4.2.0", "is": "3.3.0", + "md5": "2.3.0", + "obj-case": "0.2.1", + "on-body": "0.0.1", "component-each": "0.2.6", "@ndhoule/extend": "2.0.0", - "lodash.isundefined": "3.0.1", - "lodash.isempty": "4.4.0", - "lodash.pickby": "4.6.0", - "lodash.tostring": "4.1.4", "@lukeed/uuid": "2.0.1", "get-value": "3.0.1", "ramda": "0.30.0" diff --git a/packages/analytics-js-integrations/src/integrations/AdobeAnalytics/util.js b/packages/analytics-js-integrations/src/integrations/AdobeAnalytics/util.js index eeed5a4cd..414d82b66 100644 --- a/packages/analytics-js-integrations/src/integrations/AdobeAnalytics/util.js +++ b/packages/analytics-js-integrations/src/integrations/AdobeAnalytics/util.js @@ -1,16 +1,13 @@ /* eslint-disable no-param-reassign */ /* eslint-disable no-undef */ -import get from 'lodash.get'; import each from '@ndhoule/each'; +import { isDefined } from '@rudderstack/analytics-js-common/utilities/checks'; import { DISPLAY_NAME } from '@rudderstack/analytics-js-common/constants/integrations/AdobeAnalytics/constants'; +import { path } from 'ramda'; import Logger from '../../utils/logger'; -import { - toIso, - getHashFromArray, - isDefinedAndNotNullAndNotEmpty, - isDefined, -} from '../../utils/commonUtils'; +import { toIso, getHashFromArray, isDefinedAndNotNullAndNotEmpty } from '../../utils/commonUtils'; +const get = (context, value) => (value ? path(value.split('.'), context) : undefined); const logger = new Logger(DISPLAY_NAME); let dynamicKeys = []; @@ -678,4 +675,5 @@ export { setConfig, getConfig, handleVideoContextData, + get, }; diff --git a/packages/analytics-js-integrations/src/integrations/Braze/browser.js b/packages/analytics-js-integrations/src/integrations/Braze/browser.js index 902e577e7..27f4632e0 100644 --- a/packages/analytics-js-integrations/src/integrations/Braze/browser.js +++ b/packages/analytics-js-integrations/src/integrations/Braze/browser.js @@ -1,6 +1,5 @@ /* eslint-disable class-methods-use-this */ -import isEqual from 'lodash.isequal'; -import { isEmpty } from 'ramda'; +import { equals } from 'ramda'; import { NAME, DISPLAY_NAME, @@ -9,6 +8,7 @@ import { Storage } from '@rudderstack/analytics-js-common/v1.1/utils/storage'; import { stringifyWithoutCircularV1 } from '@rudderstack/analytics-js-common/v1.1/utils/ObjectUtils'; import Logger from '../../utils/logger'; import { isObject } from '../../utils/utils'; +import { isNotEmpty } from '../../utils/commonUtils'; import { handlePurchase, formatGender, handleReservedProperties } from './utils'; import { loadNativeSdk } from './nativeSdkLoader'; @@ -187,7 +187,7 @@ class Braze { const traits = message?.context?.traits; const previousPayload = Storage.getItem('rs_braze_dedup_attributes') || {}; - if (this.supportDedup && !isEmpty(previousPayload) && userId === previousPayload?.userId) { + if (this.supportDedup && isNotEmpty(previousPayload) && userId === previousPayload?.userId) { const prevTraits = previousPayload?.context?.traits; const prevAddress = prevTraits?.address; const prevBirthday = prevTraits?.birthday || prevTraits?.dob; @@ -199,17 +199,17 @@ class Braze { if (email && email !== prevEmail) setEmail(); if (phone && phone !== prevPhone) setPhone(); - if (birthday && !isEqual(birthday, prevBirthday)) setBirthday(); + if (birthday && !equals(birthday, prevBirthday)) setBirthday(); if (firstName && firstName !== prevFirstname) setFirstName(); if (lastName && lastName !== prevLastname) setLastName(); if (gender && formatGender(gender) !== formatGender(prevGender)) setGender(formatGender(gender)); - if (address && !isEqual(address, prevAddress)) setAddress(); + if (address && !equals(address, prevAddress)) setAddress(); if (isObject(traits)) { Object.keys(traits) .filter(key => reserved.indexOf(key) === -1) .forEach(key => { - if (!prevTraits[key] || !isEqual(prevTraits[key], traits[key])) { + if (!prevTraits[key] || !equals(prevTraits[key], traits[key])) { window.braze.getUser().setCustomUserAttribute(key, traits[key]); } }); @@ -237,7 +237,7 @@ class Braze { if ( this.supportDedup && isObject(previousPayload) && - !isEmpty(previousPayload) && + isNotEmpty(previousPayload) && userId === previousPayload?.userId ) { Storage.setItem('rs_braze_dedup_attributes', { ...previousPayload, ...message }); diff --git a/packages/analytics-js-integrations/src/integrations/FacebookPixel/utils.js b/packages/analytics-js-integrations/src/integrations/FacebookPixel/utils.js index a1950a428..c06d8d773 100644 --- a/packages/analytics-js-integrations/src/integrations/FacebookPixel/utils.js +++ b/packages/analytics-js-integrations/src/integrations/FacebookPixel/utils.js @@ -5,8 +5,8 @@ import { NAME, DISPLAY_NAME, } from '@rudderstack/analytics-js-common/constants/integrations/FacebookPixel/constants'; +import { isDefined } from '@rudderstack/analytics-js-common/utilities/checks'; import Logger from '../../utils/logger'; -import { isDefined } from '../../utils/commonUtils'; const logger = new Logger(DISPLAY_NAME); diff --git a/packages/analytics-js-integrations/src/utils/commonUtils.js b/packages/analytics-js-integrations/src/utils/commonUtils.js index 8e51ebf16..09f64a20a 100644 --- a/packages/analytics-js-integrations/src/utils/commonUtils.js +++ b/packages/analytics-js-integrations/src/utils/commonUtils.js @@ -1,19 +1,26 @@ -import _isUndefined from 'lodash.isundefined'; -import _isEmpty from 'lodash.isempty'; -import _pickBy from 'lodash.pickby'; -import _toString from 'lodash.tostring'; -import { pick as ramdaPick } from 'ramda'; +import { isDefined, isString } from '@rudderstack/analytics-js-common/utilities/checks'; +import { pick as ramdaPick, pickBy, isEmpty } from 'ramda'; -const isDefined = x => !_isUndefined(x); -const isNotEmpty = x => !_isEmpty(x); +const isNotEmpty = x => { + if (typeof x === 'object' || typeof x === 'string') { + return !isEmpty(x); // Numbers and booleans are inherently "not empty" + } + return isEmpty(x); +}; const isNotNull = x => x != null; const isDefinedAndNotNull = x => isDefined(x) && isNotNull(x); const isDefinedAndNotNullAndNotEmpty = x => isDefined(x) && isNotNull(x) && isNotEmpty(x); -const removeUndefinedValues = obj => _pickBy(obj, isDefined); -const removeNullValues = obj => _pickBy(obj, isNotNull); -const removeUndefinedAndNullValues = obj => _pickBy(obj, isDefinedAndNotNull); -const removeUndefinedAndNullAndEmptyValues = obj => _pickBy(obj, isDefinedAndNotNullAndNotEmpty); -const isBlank = value => _isEmpty(_toString(value).trim()); +const removeUndefinedValues = obj => pickBy(isDefined, obj); +const removeNullValues = obj => pickBy(isNotNull, obj); +const removeUndefinedAndNullValues = obj => pickBy(isDefinedAndNotNull, obj); +const removeUndefinedAndNullAndEmptyValues = obj => pickBy(isDefinedAndNotNullAndNotEmpty, obj); +// with this function we are mostly checking if a string is empty or not +const isBlank = value => { + if (typeof value === 'string') { + return isEmpty(value.trim()); + } + return false; +}; const pick = (argObj, argArr) => ramdaPick(argArr, argObj); /** @@ -35,6 +42,7 @@ const getHashFromArrayWithDuplicate = ( if (Array.isArray(arrays)) { arrays.forEach(array => { if (!isNotEmpty(array[fromKey])) return; + if (!isString(array[fromKey])) return; const key = isLowerCase ? array[fromKey].toLowerCase().trim() : array[fromKey].trim(); if (hashMap[key]) { @@ -201,7 +209,6 @@ export { removeUndefinedAndNullValues, removeNullValues, removeUndefinedAndNullAndEmptyValues, - isDefined, isNotEmpty, isNotNull, isDefinedAndNotNull, diff --git a/packages/analytics-js-integrations/src/utils/utils.js b/packages/analytics-js-integrations/src/utils/utils.js index 3ed37f1b6..ce4e9910f 100644 --- a/packages/analytics-js-integrations/src/utils/utils.js +++ b/packages/analytics-js-integrations/src/utils/utils.js @@ -1,6 +1,7 @@ import get from 'get-value'; import { v4 as uuid } from '@lukeed/uuid'; import { v4 as uuidSecure } from '@lukeed/uuid/secure'; +import { isDefined } from '@rudderstack/analytics-js-common/utilities/checks'; import { logger } from '@rudderstack/analytics-js-common/v1.1/utils/logUtil'; /** @@ -301,7 +302,6 @@ const isEmptyObject = obj => { */ const isArray = obj => type(obj) === 'array'; -const isDefined = x => x !== undefined; const isNotNull = x => x !== null; const isDefinedAndNotNull = x => isDefined(x) && isNotNull(x); diff --git a/packages/analytics-js-service-worker/__tests__/Analytics.test.ts b/packages/analytics-js-service-worker/__tests__/Analytics.test.ts index f98d45c20..8b00a7631 100644 --- a/packages/analytics-js-service-worker/__tests__/Analytics.test.ts +++ b/packages/analytics-js-service-worker/__tests__/Analytics.test.ts @@ -135,4 +135,46 @@ describe('JS SDK Service Worker', () => { done(); }, 10); }); + + it('should add a message to the queue when all parameters are valid', () => { + const message = { + userId: 123, + anonymousId: 987, + event: 'Clicked Button', + properties: { + buttonName: 'Submit', + }, + }; + const analytics = new Analytics('writeKey', 'https://dataPlaneURL.com', { + flushAt: 10, + flushInterval: 5000, + enable: true, + maxInternalQueueSize: 100, + timeout: 5000, + logLevel: 'debug', + flushOverride: () => { + console.log('Custom flush override function'); + }, + }); + analytics.flushed = true; + analytics.enqueue('track', message, (err, data) => { + if (err) { + console.error('Error:', err); + } else { + console.log('Data:', data); + } + }); + + expect(analytics.queue.length).toBe(1); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + expect(analytics.queue?.[0].message).toMatchObject({ + userId: '123', + event: 'Clicked Button', + properties: { + buttonName: 'Submit', + }, + type: 'track', + }); + }); }); diff --git a/packages/analytics-js-service-worker/src/Analytics.ts b/packages/analytics-js-service-worker/src/Analytics.ts index c04246a2c..0a511a541 100644 --- a/packages/analytics-js-service-worker/src/Analytics.ts +++ b/packages/analytics-js-service-worker/src/Analytics.ts @@ -8,8 +8,7 @@ import axios, { import axiosRetry from 'axios-retry'; import ms from 'ms'; import { v4 as uuid } from '@lukeed/uuid'; -import isString from 'lodash.isstring'; -import cloneDeep from 'lodash.clonedeep'; +import { is, clone } from 'ramda'; import fetchAdapter from '@vespaiach/axios-fetch-adapter'; import { isValidURL } from '@rudderstack/analytics-js-common/utilities/url'; import type { IAnalytics } from './IAnalytics'; @@ -324,7 +323,7 @@ class Analytics implements IAnalytics { } // Clone the incoming message object // before altering the data - let lMessage = cloneDeep(message); + let lMessage = clone(message); callback = callback || noop; if (!this.enable) { @@ -367,10 +366,10 @@ class Analytics implements IAnalytics { // Historically this library has accepted strings and numbers as IDs. // However, our spec only allows strings. To avoid breaking compatibility, // we'll coerce these to strings if they aren't already. - if (lMessage.anonymousId && !isString(lMessage.anonymousId)) { + if (lMessage.anonymousId && !is(String, lMessage.anonymousId)) { lMessage.anonymousId = JSON.stringify(lMessage.anonymousId); } - if (lMessage.userId && !isString(lMessage.userId)) { + if (lMessage.userId && !is(String, lMessage.userId)) { lMessage.userId = JSON.stringify(lMessage.userId); } From 1be420fae16b68629789d2ba37e16e6a6e00017c Mon Sep 17 00:00:00 2001 From: Sai Kumar Battinoju <88789928+saikumarrs@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:17:00 +0530 Subject: [PATCH 05/17] fix: improve flushing events on page leave (#1754) * chore: upgrade all dependencies to latest * fix: improve flushing events on page leave * chore: paths in tsconfig.json file which was conflicting with linter * chore: fix linting issues by reverting to previous versions * chore: fix sample html page * chore: update snippet version, remove deprecated fieldsand add favicon * chore: update all readme files to latest * fix: export page utilities * chore: address ai bot review comments * chore: address more ai bot review comments * chore: address more ai bot review comments * feat: upgrade nx dependencies to latest * chore: fix linting issues * chore: address ai bot review comments --- .gitignore | 1 + .prettierignore | 3 +- README.md | 185 ++- examples/angular/sample-app/src/index.html | 2 +- examples/chrome-extension/USAGE.md | 2 +- .../app-using-v3-cdn/public/index.html | 2 +- .../hooks/sample-app/src/app/layout.tsx | 2 +- .../nextjs/js/sample-app/src/app/layout.js | 2 +- .../sample-app/src/pages/_document.tsx | 2 +- .../nextjs/ts/sample-app/src/app/layout.tsx | 2 +- .../hooks/sample-app/public/index.html | 2 +- .../reactjs/js/sample-app/public/index.html | 2 +- .../reactjs/ts/sample-app/public/index.html | 2 +- examples/reactjs/vite/sample-app/index.html | 2 +- examples/symfony/USAGE.md | 1 - examples/v3-beacon/index.html | 2 +- examples/v3-legacy-minimum-plugins/index.html | 2 +- examples/v3-legacy/index.html | 2 +- examples/v3-minimum-plugins/index.html | 2 +- examples/v3/index.html | 2 +- nx.json | 55 +- package-lock.json | 1265 ++++++++--------- package.json | 73 +- packages/analytics-js-common/README.md | 20 +- .../__tests__/utilities/page.test.ts | 128 ++ packages/analytics-js-common/package.json | 8 +- .../src/services/BufferQueue/BufferQueue.ts | 2 +- .../src/utilities/index.ts | 1 + .../analytics-js-common/src/utilities/page.ts | 36 + .../analytics-js-integrations/package.json | 2 +- .../public/list_integration_sdks.html | 1 + packages/analytics-js-plugins/README.md | 29 +- packages/analytics-js-plugins/package.json | 2 +- .../analytics-js-plugins/src/types/plugins.ts | 3 +- .../src/utilities/retryQueue/RetryQueue.ts | 19 +- .../analytics-js-service-worker/README.md | 18 +- .../analytics-js-service-worker/package.json | 12 +- packages/analytics-js/README.md | 24 +- .../analytics-js/__tests__/browser.test.ts | 2 + .../analytics-js/__tests__/nativeSdkLoader.js | 100 +- packages/analytics-js/package.json | 4 +- packages/analytics-js/public/index.html | 4 +- .../public/list_integration_sdks.html | 1 + .../configManager/util/commonUtil.ts | 4 +- .../pluginsManager/PluginsManager.ts | 2 +- .../src/components/utilities/consent.ts | 4 +- .../src/services/StoreManager/StoreManager.ts | 2 +- .../StoreManager/storages/storageEngine.ts | 4 +- packages/loading-scripts/public/index.html | 1 + packages/sanity-suite/README.md | 17 +- .../sanity-suite/__fixtures__/alias1.json | 5 +- .../sanity-suite/__fixtures__/alias2.json | 2 - .../sanity-suite/__fixtures__/alias3.json | 2 - .../sanity-suite/__fixtures__/alias4.json | 2 - .../sanity-suite/__fixtures__/alias5.json | 5 +- .../sanity-suite/__fixtures__/alias6.json | 5 +- .../sanity-suite/__fixtures__/group1.json | 5 +- .../sanity-suite/__fixtures__/group2.json | 5 +- .../sanity-suite/__fixtures__/group3.json | 5 +- .../sanity-suite/__fixtures__/group4.json | 5 +- .../sanity-suite/__fixtures__/group5.json | 5 +- .../sanity-suite/__fixtures__/group6.json | 5 +- .../sanity-suite/__fixtures__/identify1.json | 7 +- .../sanity-suite/__fixtures__/identify2.json | 5 +- .../sanity-suite/__fixtures__/identify3.json | 5 +- .../sanity-suite/__fixtures__/identify4.json | 5 +- .../sanity-suite/__fixtures__/identify5.json | 5 +- .../sanity-suite/__fixtures__/identify6.json | 5 +- .../sanity-suite/__fixtures__/identify7.json | 5 +- .../sanity-suite/__fixtures__/identify8.json | 5 +- packages/sanity-suite/__fixtures__/page1.json | 5 +- packages/sanity-suite/__fixtures__/page2.json | 5 +- packages/sanity-suite/__fixtures__/page3.json | 5 +- packages/sanity-suite/__fixtures__/page4.json | 5 +- packages/sanity-suite/__fixtures__/page5.json | 5 +- packages/sanity-suite/__fixtures__/page6.json | 5 +- packages/sanity-suite/__fixtures__/page7.json | 5 +- packages/sanity-suite/__fixtures__/page8.json | 5 +- .../sanity-suite/__fixtures__/track1.json | 5 +- .../sanity-suite/__fixtures__/track2.json | 5 +- .../sanity-suite/__fixtures__/track3.json | 5 +- .../sanity-suite/__fixtures__/track4.json | 5 +- .../sanity-suite/__fixtures__/track5.json | 5 +- .../sanity-suite/__fixtures__/track6.json | 5 +- .../sanity-suite/__fixtures__/track7.json | 5 +- .../sanity-suite/public/v3/index-cdn.html | 3 +- .../sanity-suite/public/v3/index-local.html | 3 +- .../sanity-suite/public/v3/index-npm.html | 3 +- .../public/v3/integrations/index-cdn.html | 3 +- .../public/v3/integrations/index-local.html | 3 +- .../public/v3/integrations/index-npm.html | 3 +- .../public/v3/manualLoadCall/index-cdn.html | 3 +- .../public/v3/manualLoadCall/index-local.html | 3 +- .../public/v3/manualLoadCall/index-npm.html | 3 +- .../ignoredProperties/ignoredProperties.js | 5 + ...onventional-changelog-for-jira+8.0.1.patch | 21 + patches/{nx+19.1.0.patch => nx+19.3.0.patch} | 2 +- tsconfig.json | 13 + tsconfig.paths.json | 17 +- 99 files changed, 1213 insertions(+), 1105 deletions(-) create mode 100644 packages/analytics-js-common/__tests__/utilities/page.test.ts create mode 100644 packages/analytics-js-common/src/utilities/page.ts create mode 100644 patches/@digitalroute+cz-conventional-changelog-for-jira+8.0.1.patch rename patches/{nx+19.1.0.patch => nx+19.3.0.patch} (99%) diff --git a/.gitignore b/.gitignore index 208b7ffa8..b58ba7f42 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ tsconfig.build.tsbuildinfo *.zip .nx/cache +.nx/workspace-data diff --git a/.prettierignore b/.prettierignore index 6c87b6039..2d30234d3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,4 +14,5 @@ examples/chrome-extension/**/foreground.js examples/**/index.html **/public/index.html -/.nx/cache \ No newline at end of file +/.nx/cache +/.nx/workspace-data \ No newline at end of file diff --git a/README.md b/README.md index 830b05cd9..8b18ad56f 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The JavaScript SDK lets you track customer event data from your website and send - [**Usage in Chrome Extensions**](#usage-in-chrome-extensions) - [**Usage in Serverless Runtimes**](#usage-in-serverless-runtimes) -| **IMPORTANT**: The service worker export has been deprecated from the RudderStack JavaScript SDK npm package and moved to a new package.
If you still wish to use it for your project, see [**@rudderstack/analytics-js-service-worker package**](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker). | +| **IMPORTANT**: The service worker export has been deprecated from the RudderStack JavaScript SDK NPM package and moved to a new package.
If you still wish to use it for your project, see [**@rudderstack/analytics-js-service-worker package**](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker). | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ## Installing the JavaScript SDK @@ -47,53 +47,59 @@ The JavaScript SDK lets you track customer event data from your website and send | For detailed installation steps, see the [JavaScript SDK documentation](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/installation/). | | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +### Using CDN + To integrate the JavaScript SDK with your website, place the following code snippet in the `` section of your website. ```javascript ```
-> The above snippet lets you integrate the SDK with your website and load it asynchronously to keep your page load time unaffected. +> The above snippet lets you integrate the SDK with your website and load it asynchronously to avoid impacting the performance of your webpages. To load SDK script on to your page synchronously, see the [**JavaScript SDK documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/installation/#synchronous-loading). -> **IMPORTANT**: The implicit `page` call at the end of the snippet (present in the previous JavaScript SDK versions) is removed in the latest SDK v3. You need to make a `page` call explicitly, if required, as shown below: +> **IMPORTANT**: The implicit `page` call at the end of the snippet (present in the previous JavaScript SDK versions) is removed in the latest SDK (v3). You need to make a `page` call explicitly, if required, as shown below: ```javascript rudderanalytics.page(); ``` -### NPM installation +### Using NPM Although we recommend using the CDN installation method to use the JavaScript SDK with your website, you can also use this [**NPM module**](https://www.npmjs.com/package/@rudderstack/analytics-js) to package RudderStack directly into your project. -To install the SDK via npm, run the following command: +To install the SDK via NPM, run the following command: ```bash npm install @rudderstack/analytics-js --save ``` **Note that this NPM module is only meant to be used for a browser installation**. If you want to integrate RudderStack with your Node.js application, see the [**RudderStack Node.js documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-node-sdk/). -

**IMPORTANT**: Since the module exports the [**related APIs**](#exported-apis) on an already-defined object combined with the Node.js module caching, you should run the following code snippet only once and use the exported object throughout your project: @@ -102,10 +108,10 @@ npm install @rudderstack/analytics-js --save ```javascript import { RudderAnalytics } from '@rudderstack/analytics-js'; -const rudderAnalytics = new RudderAnalytics(); -rudderAnalytics.load(WRITE_KEY, DATA_PLANE_URL, {}); +const rudderanalytics = new RudderAnalytics(); +rudderAnalytics.load(, , {}); -export { rudderAnalytics }; +export { rudderanalytics }; ``` - **For CJS using the `require` method**: @@ -114,85 +120,40 @@ export { rudderAnalytics }; var RudderAnalytics = require('@rudderstack/analytics-js'); const rudderAnalytics = new RudderAnalytics(); -rudderAnalytics.load(WRITE_KEY, DATA_PLANE_URL, {}); +rudderAnalytics.load(, , {}); exports.rudderanalytics = rudderAnalytics; ``` ### Sample implementations -See the following projects for a detailed walkthrough of the above steps: - -- [**Sample Angular project**](https://github.com/rudderlabs/rudder-analytics-angular) -- [**Sample React project**](https://github.com/rudderlabs/rudder-analytics-react) - -### Exported APIs - -The APIs exported by the module are: - -- `load` -- `ready` -- `identify` -- `page` -- `track` -- `group` -- `alias` -- `reset` -- `setAnonymousId` -- `startSession` -- `endSession` - -See [JavaScript SDK installation workflow](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/installation/#installation-workflow) for more information on these methods. +See the following applications for a detailed walkthrough of the above steps: -### Supported browser versions +- [**Sample Angular application**](https://github.com/rudderlabs/rudder-sdk-js/tree/main/examples/angular/) +- [**Sample React application**](https://github.com/rudderlabs/rudder-sdk-js/tree/main/examples/reactjs/) -| **Browser** | **Supported Versions** | -| :-------------- | :--------------------- | -| **Browser** | **Supported Versions** | -| :-------------- | :--------------------- | -| Safari | v7 and above | -| IE | v11 and above | -| Edge | v80 and above | -| Mozilla Firefox | v47 and above | -| Chrome | v54 and above | -| Opera | v43 and above | - -> You can try adding the browser [polyfills](https://developer.mozilla.org/en-US/docs/Glossary/Polyfill) to your application if the SDK does not work on your browser. +See the `examples` directory in this repository for more sample applications for different frameworks. ## Migrating SDK from an older version -If you are migrating the JavaScript SDK from an older version (<=v1.1), see the [Migration Guide](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/migration-guide/) for details. +If you are migrating the JavaScript SDK from an older version (<= v1.1), see the [Migration Guide](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/migration-guide/) for details. ## Loading the SDK -| For detailed information on the `load()` method, see the [**JavaScript SDK documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/). | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| For detailed information on the `load` API, see the [**JavaScript SDK documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/). | +| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -You can load the JavaScript SDK using the `load` API method to track and send events from your website to RudderStack. Make sure to replace the "write key" and data plane URL with their actual values. +You can load the JavaScript SDK using the `load` API to track and send events from your website to RudderStack. Make sure to replace the write key and data plane URL with their actual values. ```javascript rudderanalytics.load(, , [loadOptions]); ``` -You can use the [`loadOptions`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/#loading-options) object in the above `load` call to define various options while loading the SDK. - -For destinations where you don't want the SDK to load the third-party scripts separately, modify the `load` call as shown: - -```javascript -rudderanalytics.load( , , { - loadIntegration: false -}) -``` - -A few important things to note: - -- The SDK expects the destination global queue or function for pushing the events is already present for the particular destinations. -- Currently, `loadIntegration` is supported only for Amplitude and Google Analytics. -- The JavaScript SDK expects `window.amplitude` and `window.ga` to be already defined by the user separately for the sending the events to these destinations. +You can use the [`loadOptions`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/#loading-options) object in the above `load` call to define various [options](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/#loading-options) while loading the SDK. ## Identifying users -The [`identify`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#identify) call lets you identify a visiting user and associate them to their actions. It also lets you record the traits about them like their name, email address, etc. +The [`identify`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#identify) API lets you identify a visiting user and associate them to their actions. It also lets you record the traits about them like their name, email address, etc. A sample `identify` call is shown below: @@ -215,22 +176,22 @@ rudderanalytics.identify( }, }, () => { - console.log('identify call'); + console.log('Identify call is successful.'); }, ); ``` -In the above example, the JavaScript SDK captures the user information like `userId`, `firstName`, `lastName`, `email`, and `phone`, along with the [**contextual information**](https://www.rudderstack.com/docs/event-spec/standard-events/common-fields/#contextual-fields). +In the above example, the JavaScript SDK captures the user information like `userId`, `firstName`, `lastName`, `email`, and `phone`, along with the default [**contextual information**](https://www.rudderstack.com/docs/event-spec/standard-events/common-fields/#contextual-fields). -> There is no need to call `identify()` for anonymous visitors to your website. Such visitors are automatically assigned an `anonymousId`. +> There is no need to call `identify` API for anonymous visitors to your website. Such visitors are automatically assigned an `anonymousId`. -See the [**JavaScript SDK documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#identify) for more information on how to use the `identify` call. +See the [**JavaScript SDK documentation**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#identify) for more information on how to use the `identify` API. ## Tracking user actions -The [`track`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#track) call lets you capture the user events along with any associated properties. +The [`track`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#track) API lets you capture the user events along with any associated properties. -A sample `track` call is shown below: +A sample `track` API is shown below: ```javascript rudderanalytics.track( @@ -241,27 +202,47 @@ rudderanalytics.track( user_actual_id: 12345, }, () => { - console.log('track call'); + console.log('Track call is successful.'); }, ); ``` -In the above example, the `track` method tracks the user event ‘**Order Completed**’ and information like the `revenue`, `currency`, etc. +In the above example, the `track` API tracks the user event `Order Completed` and information like the `revenue`, `currency`, etc. -> You can use the `track` method to track various success metrics for your website like user signups, item purchases, article bookmarks, and more. +> You can use the `track` API to track various success metrics for your website like user signups, item purchases, article bookmarks, and more. -## The `ready` API +## Ready state -There are cases when you may want to tap into the features provided by the end-destination SDKs to enhance tracking and other functionalities. The JavaScript SDK exposes a `ready` API with a `callback` parameter that fires when the SDK is done initializing itself and the other third-party native SDK destinations. +There are cases when you may want to tap into the features provided by the end-destination SDKs to enhance tracking and other functionalities. The JavaScript SDK exposes a [`ready`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/#ready-api) API with a `callback` parameter that fires when the SDK is done initializing itself and the device-mode destinations. An example is shown in the following snippet: ```javascript rudderanalytics.ready(() => { - console.log('we are all set!!!'); + console.log('We are all set!!!'); }); ``` +### Loaded state + +Alternatively, if you just want to wait for the SDK to load, you can use the [`onLoaded`](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/load-js-sdk/#onloaded) load API option to configure a callback function. + +The configured callback function is executed when the SDK has loaded successfully but before all the device-mode destinations are initialized. + +This is especially helpful to query information from the SDK after it has loaded to use it elsewhere. For example, you can retrieve the anonymous ID generated by the SDK after it has loaded. + +An example is shown in the following snippet: + +```javascript +rudderanalytics.load(, , { + onLoaded: () => { + console.log('SDK has loaded.'); + console.log('Anonymous ID:', rudderanalytics.getAnonymousId()); + }, +}); + +``` + > For more information on the other supported methods, see the [**JavaScript SDK APIs**](https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/supported-api/). ## [](https://github.com/rudderlabs/rudder-sdk-js/blob/main/README.md#self-hosted-control-plane)Self-hosted control plane @@ -279,35 +260,29 @@ rudderanalytics.load(, , { More information on obtaining the `CONTROL_PLANE_URL` can be found [**here**](https://www.rudderstack.com/docs/get-started/rudderstack-open-source/control-plane-lite/#using-sdk-sources-set-up-in-self-hosted-control-plane). -## Adding your own integrations - -You can start adding integrations of your choice for sending the data through their respective web (JavaScript) SDKs. - ## How to build the SDK - Look for run scripts in the `package.json` file for getting the browser minified and non-minified builds. The builds are updated in the `dist` folder of the directory. Among the others, some of the important ones are: - - `npm run build:browser`: This outputs **dist/cdn/legacy/rudder-analytics.min.js**. - - `npm run build:npm`: This outputs **dist/npm** folder that contains the npm package contents. - - `npm run build:integration:all`: This outputs **dist/cdn/legacy** folder that contains the integrations. + - `npm run build:browser`: This outputs the **dist/cdn/legacy/rsa.min.js**. + - `npm run build:npm`: This outputs the **dist/npm** folder that contains the NPM package contents. + - `npm run build:integration:all`: This outputs the **dist/cdn/legacy** folder that contains the integrations. -> We use **rollup** to build our SDKs. The configuration for it is present in `rollup-configs` folder. +> We use **rollup** to build our SDKs. The configuration for it is present in the `rollup-configs` directory. - For adding or removing integrations, modify the imports in `index.js` under the `src/integrations` folder. ## Usage in Chrome extensions -You can use the JavaScript SDK in Chrome Extensions with manifest v3, both as a content script (via the JavaScript SDK package) -or as a background script service worker (via the [service worker package](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker)). +You can use the JavaScript SDK in Chrome Extensions with manifest v3, both as a content script (via the JavaScript SDK package) or as a background script service worker (via the [service worker package](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker)). -For examples and specific details, see [Chrome Extensions Usage](https://github.com/rudderlabs/rudder-sdk-js/blob/main/examples/chrome-extension/USAGE.md). +For more details, see [Chrome Extensions Usage](https://github.com/rudderlabs/rudder-sdk-js/blob/main/examples/chrome-extension/USAGE.md). ## Usage in Serverless runtimes -RudderStack JS SDK [service worker](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker) can be used -in serverless runtimes like Cloudflare Workers or Vercel Edge functions. +RudderStack JS SDK [service worker](https://www.npmjs.com/package/@rudderstack/analytics-js-service-worker) can be used in serverless runtimes like Cloudflare Workers or Vercel Edge functions. -For examples and specific details look into: +For more details, see: - [Vercel Edge Usage](https://github.com/rudderlabs/rudder-sdk-js/blob/main/examples/serverless/USAGE.md) - [Cloudflare Worker Usage](https://github.com/rudderlabs/rudder-sdk-js/blob/main/examples/serverless/USAGE.md) diff --git a/examples/angular/sample-app/src/index.html b/examples/angular/sample-app/src/index.html index a7f0a86d5..bf0494e29 100644 --- a/examples/angular/sample-app/src/index.html +++ b/examples/angular/sample-app/src/index.html @@ -9,7 +9,7 @@