diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 59779568a..619440258 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,8 +23,7 @@ packages/plugins/metrics @DataDog/f packages/plugins/error-tracking @yoannmoinet # Rum -packages/plugins/rum @yoannmoinet -packages/plugins/rum/src/privacy @DataDog/rum-browser +packages/plugins/rum @DataDog/rum-browser @yoannmoinet # Analytics packages/plugins/analytics @yoannmoinet diff --git a/.yarn/cache/@datadog-browser-core-npm-6.24.0-e883c4fc19-601add9977.zip b/.yarn/cache/@datadog-browser-core-npm-6.26.0-00db60a2f7-c5a84b637d.zip similarity index 58% rename from .yarn/cache/@datadog-browser-core-npm-6.24.0-e883c4fc19-601add9977.zip rename to .yarn/cache/@datadog-browser-core-npm-6.26.0-00db60a2f7-c5a84b637d.zip index fca277014..c681177ef 100644 Binary files a/.yarn/cache/@datadog-browser-core-npm-6.24.0-e883c4fc19-601add9977.zip and b/.yarn/cache/@datadog-browser-core-npm-6.26.0-00db60a2f7-c5a84b637d.zip differ diff --git a/.yarn/cache/@datadog-browser-rum-core-npm-6.24.0-1e2bc22c73-eea74ab7e6.zip b/.yarn/cache/@datadog-browser-rum-core-npm-6.26.0-5d3f0e2bd2-2d3423c324.zip similarity index 55% rename from .yarn/cache/@datadog-browser-rum-core-npm-6.24.0-1e2bc22c73-eea74ab7e6.zip rename to .yarn/cache/@datadog-browser-rum-core-npm-6.26.0-5d3f0e2bd2-2d3423c324.zip index 2ad8b2760..c8314b406 100644 Binary files a/.yarn/cache/@datadog-browser-rum-core-npm-6.24.0-1e2bc22c73-eea74ab7e6.zip and b/.yarn/cache/@datadog-browser-rum-core-npm-6.26.0-5d3f0e2bd2-2d3423c324.zip differ diff --git a/.yarn/cache/@datadog-browser-rum-npm-6.24.0-1963fb8d4d-c1b7fc0687.zip b/.yarn/cache/@datadog-browser-rum-npm-6.24.0-1963fb8d4d-c1b7fc0687.zip deleted file mode 100644 index 877517bdd..000000000 Binary files a/.yarn/cache/@datadog-browser-rum-npm-6.24.0-1963fb8d4d-c1b7fc0687.zip and /dev/null differ diff --git a/.yarn/cache/@datadog-browser-rum-npm-6.26.0-d266ecc471-53b9309ea5.zip b/.yarn/cache/@datadog-browser-rum-npm-6.26.0-d266ecc471-53b9309ea5.zip new file mode 100644 index 000000000..3a2ba3b1b Binary files /dev/null and b/.yarn/cache/@datadog-browser-rum-npm-6.26.0-d266ecc471-53b9309ea5.zip differ diff --git a/packages/plugins/rum/package.json b/packages/plugins/rum/package.json index 770cf3493..c4954f139 100644 --- a/packages/plugins/rum/package.json +++ b/packages/plugins/rum/package.json @@ -36,7 +36,7 @@ "chalk": "2.3.1" }, "devDependencies": { - "@datadog/browser-rum": "6.24.0", + "@datadog/browser-rum": "6.26.0", "typescript": "5.4.3" } } diff --git a/packages/plugins/rum/src/getSourceCodeContextSnippet.ts b/packages/plugins/rum/src/getSourceCodeContextSnippet.ts new file mode 100644 index 000000000..036b02fe1 --- /dev/null +++ b/packages/plugins/rum/src/getSourceCodeContextSnippet.ts @@ -0,0 +1,24 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +import type { SourceCodeContextOptions } from './types'; + +export const DEFAULT_SOURCE_CODE_CONTEXT_VARIABLE = 'DD_SOURCE_CODE_CONTEXT' as const; + +// The source code context snippet - single injection with function definition and call +// SSR-safe: checks window before accessing, never throws +// +// Unminified version: +// (function(c, n) { +// try { +// if (typeof window === 'undefined') return; +// var w = window, +// m = w[n] = w[n] || {}, +// s = new Error().stack; +// s && (m[s] = c) +// } catch (e) {} +// })(context, variableName); +export const getSourceCodeContextSnippet = (context: SourceCodeContextOptions): string => { + return `(function(c,n){try{if(typeof window==='undefined')return;var w=window,m=w[n]=w[n]||{},s=new Error().stack;s&&(m[s]=c)}catch(e){}})(${JSON.stringify(context)},${JSON.stringify(DEFAULT_SOURCE_CODE_CONTEXT_VARIABLE)});`; +}; diff --git a/packages/plugins/rum/src/index.test.ts b/packages/plugins/rum/src/index.test.ts index fb9992717..8fe18ad6d 100644 --- a/packages/plugins/rum/src/index.test.ts +++ b/packages/plugins/rum/src/index.test.ts @@ -21,12 +21,14 @@ describe('RUM Plugin', () => { const injections = { 'browser-sdk': path.resolve('../plugins/rum/src/rum-browser-sdk.js'), 'sdk-init': injectionValue, + 'source-code-context': + /(?=.*DD_SOURCE_CODE_CONTEXT)(?=.*"service":"checkout")(?=.*"version":"1\.2\.3")/, }; const expectations: { type: string; config: RumOptions; - should: { inject: (keyof typeof injections)[]; throw?: boolean }; + should: { inject: (keyof typeof injections)[] }; }[] = [ { type: 'no sdk', @@ -38,6 +40,16 @@ describe('RUM Plugin', () => { config: { sdk: { applicationId: 'app-id' } }, should: { inject: ['browser-sdk', 'sdk-init'] }, }, + { + type: 'source code context', + config: { + sourceCodeContext: { + service: 'checkout', + version: '1.2.3', + }, + }, + should: { inject: ['source-code-context'] }, + }, ]; describe('getPlugins', () => { const injectMock = jest.fn(); @@ -79,21 +91,13 @@ describe('RUM Plugin', () => { const mockContext = getContextMock(); const pluginConfig = { ...defaultPluginOptions, rum: config }; - const expectResult = expect(() => { - getPlugins(getGetPluginsArg(pluginConfig, mockContext)); - }); - - if (should.throw) { - expectResult.toThrow(); - } else { - expectResult.not.toThrow(); - } + getPlugins(getGetPluginsArg(pluginConfig, mockContext)); expect(mockContext.inject).toHaveBeenCalledTimes(should.inject.length); for (const inject of should.inject) { expect(mockContext.inject).toHaveBeenCalledWith( expect.objectContaining({ - value: injections[inject], + value: expect.stringMatching(injections[inject]), }), ); } diff --git a/packages/plugins/rum/src/index.ts b/packages/plugins/rum/src/index.ts index e15aaa630..0bf029795 100644 --- a/packages/plugins/rum/src/index.ts +++ b/packages/plugins/rum/src/index.ts @@ -7,6 +7,7 @@ import { InjectPosition } from '@dd/core/types'; import path from 'path'; import { CONFIG_KEY, PLUGIN_NAME } from './constants'; +import { getSourceCodeContextSnippet } from './getSourceCodeContextSnippet'; import { getPrivacyPlugin } from './privacy'; import { getInjectionValue } from './sdk'; import type { RumOptions, RumOptionsWithSdk, RumPublicApi, RumInitConfiguration } from './types'; @@ -36,6 +37,15 @@ export const getPlugins: GetPlugins = ({ options, context }) => { return plugins; } + if (validatedOptions.sourceCodeContext) { + context.inject({ + type: 'code', + position: InjectPosition.BEFORE, + injectIntoAllChunks: true, + value: getSourceCodeContextSnippet(validatedOptions.sourceCodeContext), + }); + } + // NOTE: These files are built from "@dd/tools/rollupConfig.mjs" and available in the distributed package. if (validatedOptions.sdk) { // Inject the SDK from the CDN. diff --git a/packages/plugins/rum/src/types.ts b/packages/plugins/rum/src/types.ts index e331648db..1a8e6bfd6 100644 --- a/packages/plugins/rum/src/types.ts +++ b/packages/plugins/rum/src/types.ts @@ -10,10 +10,16 @@ import type { Assign } from '@dd/core/types'; import type { PrivacyOptions, PrivacyOptionsWithDefaults } from './privacy/types'; +export type SourceCodeContextOptions = { + service: string; + version?: string; +}; + export type RumOptions = { enable?: boolean; sdk?: SDKOptions; privacy?: PrivacyOptions; + sourceCodeContext?: SourceCodeContextOptions; }; export type RumPublicApi = typeof datadogRum; @@ -57,6 +63,7 @@ export type RumOptionsWithDefaults = { enable?: boolean; sdk?: SDKOptionsWithDefaults; privacy?: PrivacyOptionsWithDefaults; + sourceCodeContext?: SourceCodeContextOptions; }; export type RumOptionsWithSdk = Assign; diff --git a/packages/plugins/rum/src/validate.test.ts b/packages/plugins/rum/src/validate.test.ts index 8cd123c0e..6d0a6fa7a 100644 --- a/packages/plugins/rum/src/validate.test.ts +++ b/packages/plugins/rum/src/validate.test.ts @@ -5,7 +5,7 @@ import { defaultPluginOptions } from '@dd/tests/_jest/helpers/mocks'; import { createFilter } from '@rollup/pluginutils'; -import { validatePrivacyOptions } from './validate'; +import { validatePrivacyOptions, validateSourceCodeContextOptions } from './validate'; describe('Test privacy plugin option exclude regex', () => { let filter: (path: string) => boolean; @@ -34,3 +34,34 @@ describe('Test privacy plugin option exclude regex', () => { expect(filter(path)).toBe(expected); }); }); + +describe('sourceCodeContext validation', () => { + test('should return empty result when not configured', () => { + const pluginOptions = { ...defaultPluginOptions, rum: {} }; + const result = validateSourceCodeContextOptions(pluginOptions); + expect(result.errors).toHaveLength(0); + expect(result.config).toBeUndefined(); + }); + + test('should accept when only service is provided (version optional)', () => { + const pluginOptions = { + ...defaultPluginOptions, + rum: { sourceCodeContext: { service: 'checkout' } }, + }; + const result = validateSourceCodeContextOptions(pluginOptions); + expect(result.errors).toHaveLength(0); + expect(result.config).toEqual(expect.objectContaining({ service: 'checkout' })); + }); + + test('should error when service is missing', () => { + const pluginOptions = { + ...defaultPluginOptions, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + rum: { sourceCodeContext: { version: '1.2.3' } as any }, + }; + const result = validateSourceCodeContextOptions(pluginOptions); + expect(result.errors).toEqual( + expect.arrayContaining([expect.stringContaining('"rum.sourceCodeContext.service"')]), + ); + }); +}); diff --git a/packages/plugins/rum/src/validate.ts b/packages/plugins/rum/src/validate.ts index 013280e09..120b9d9ee 100644 --- a/packages/plugins/rum/src/validate.ts +++ b/packages/plugins/rum/src/validate.ts @@ -7,7 +7,12 @@ import chalk from 'chalk'; import { CONFIG_KEY, PLUGIN_NAME } from './constants'; import type { PrivacyOptionsWithDefaults } from './privacy/types'; -import type { RumOptions, RumOptionsWithDefaults, SDKOptionsWithDefaults } from './types'; +import type { + RumOptions, + RumOptionsWithDefaults, + SDKOptionsWithDefaults, + SourceCodeContextOptions, +} from './types'; export const validateOptions = ( options: OptionsWithDefaults, @@ -18,9 +23,11 @@ export const validateOptions = ( // Validate and add defaults sub-options. const sdkResults = validateSDKOptions(options); const privacyResults = validatePrivacyOptions(options); + const sourceCodeContextResults = validateSourceCodeContextOptions(options); errors.push(...sdkResults.errors); errors.push(...privacyResults.errors); + errors.push(...sourceCodeContextResults.errors); // Throw if there are any errors. if (errors.length) { @@ -34,6 +41,7 @@ export const validateOptions = ( ...options[CONFIG_KEY], sdk: undefined, privacy: undefined, + sourceCodeContext: undefined, }; // Fill in the defaults. @@ -55,6 +63,10 @@ export const validateOptions = ( ); } + if (sourceCodeContextResults.config) { + toReturn.sourceCodeContext = sourceCodeContextResults.config; + } + return toReturn; }; @@ -141,3 +153,26 @@ export const validatePrivacyOptions = (options: Options): ToReturn => { + const red = chalk.bold.red; + const validatedOptions: RumOptions = options[CONFIG_KEY] || {}; + const toReturn: ToReturn = { + errors: [], + }; + + if (!validatedOptions.sourceCodeContext) { + return toReturn; + } + + const cfg: SourceCodeContextOptions = validatedOptions.sourceCodeContext; + + if (!cfg?.service || typeof cfg.service !== 'string') { + toReturn.errors.push(`Missing ${red('"rum.sourceCodeContext.service"')}.`); + } + + toReturn.config = cfg; + return toReturn; +}; diff --git a/packages/tests/package.json b/packages/tests/package.json index 3d8584c51..e4c6ec842 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -24,6 +24,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@datadog/browser-rum": "6.26.0", "@datadog/esbuild-plugin": "workspace:*", "@datadog/rollup-plugin": "workspace:*", "@datadog/rspack-plugin": "workspace:*", diff --git a/packages/tests/src/_playwright/helpers/buildProject.ts b/packages/tests/src/_playwright/helpers/buildProject.ts index a42ed030d..252b4dbb9 100644 --- a/packages/tests/src/_playwright/helpers/buildProject.ts +++ b/packages/tests/src/_playwright/helpers/buildProject.ts @@ -12,7 +12,7 @@ import typescript from '@rollup/plugin-typescript'; import fs from 'fs'; import path from 'path'; -type BuildConfigOverride = Partial>; +type BuildConfigOverride = Partial>; // Build a given project with a given bundler. const buildProject = async ( @@ -60,6 +60,7 @@ const buildProject = async ( outDir: path.resolve(cwd, './dist'), // Use a consistent entry name to avoid injection conflicts entry: { [bundler]: bundlerEntry }, + splitting: buildConfigOverride?.splitting, plugins: [plugin, ...additionalPlugins], }); diff --git a/packages/tests/src/e2e/sourceCodeContext/project/chunk.js b/packages/tests/src/e2e/sourceCodeContext/project/chunk.js new file mode 100644 index 000000000..a874d492c --- /dev/null +++ b/packages/tests/src/e2e/sourceCodeContext/project/chunk.js @@ -0,0 +1,15 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +/* eslint-env browser */ +import { datadogRum } from '@datadog/browser-rum'; + +// Used by Playwright tests to ensure the chunk module has been evaluated. +window.chunkLoaded = true; + +const $ = document.querySelector.bind(document); + +$('#trigger_chunk_error').addEventListener('click', () => { + datadogRum.addError(new Error('chunk_error')); +}); diff --git a/packages/tests/src/e2e/sourceCodeContext/project/index.html b/packages/tests/src/e2e/sourceCodeContext/project/index.html new file mode 100644 index 000000000..b12c918d9 --- /dev/null +++ b/packages/tests/src/e2e/sourceCodeContext/project/index.html @@ -0,0 +1,21 @@ + + + + + + + Source Code Context Test + + + +

Source Code Context Test - {{bundler}}

+

Testing source code context injection.

+ + + + + + + + + diff --git a/packages/tests/src/e2e/sourceCodeContext/project/index.js b/packages/tests/src/e2e/sourceCodeContext/project/index.js new file mode 100644 index 000000000..0a5b5aa77 --- /dev/null +++ b/packages/tests/src/e2e/sourceCodeContext/project/index.js @@ -0,0 +1,17 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +/* eslint-env browser */ + +import { datadogRum } from '@datadog/browser-rum'; + +const $ = document.querySelector.bind(document); + +$('#trigger_entry_error').addEventListener('click', () => { + datadogRum.addError(new Error('entry_error')); +}); + +$('#load_chunk').addEventListener('click', async () => { + await import('./chunk.js'); +}); diff --git a/packages/tests/src/e2e/sourceCodeContext/sourceCodeContext.spec.ts b/packages/tests/src/e2e/sourceCodeContext/sourceCodeContext.spec.ts new file mode 100644 index 000000000..4381e979f --- /dev/null +++ b/packages/tests/src/e2e/sourceCodeContext/sourceCodeContext.spec.ts @@ -0,0 +1,151 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +/* eslint-env browser */ +/* global globalThis */ +import { verifyProjectBuild } from '@dd/tests/_playwright/helpers/buildProject'; +import type { TestOptions } from '@dd/tests/_playwright/testParams'; +import { test } from '@dd/tests/_playwright/testParams'; +import { defaultConfig } from '@dd/tools/plugins'; +import type { Page } from '@playwright/test'; +import path from 'path'; + +// Have a similar experience to Jest. +const { expect, beforeAll, describe } = test; + +const SERVICE_NAME = 'test-micro-frontend'; +const SERVICE_VERSION = '1.2.3'; + +const userFlow = async (url: string, page: Page, bundler: TestOptions['bundler']) => { + // Navigate to our page. + await page.goto(`${url}/index.html?context_bundler=${bundler}`); + await page.waitForSelector('body'); +}; + +const getRUMEvents = async (page: Page) => { + await page.evaluate(() => { + (globalThis as any).DD_RUM.stopSession(); + }); + return page.evaluate(() => (globalThis as any).rum_events); +}; + +describe('Source Code Context', () => { + // Build our fixture project. + beforeAll(async ({ publicDir, bundlers, suiteName }) => { + const source = path.resolve(__dirname, 'project'); + const destination = path.resolve(publicDir, suiteName); + await verifyProjectBuild( + source, + destination, + bundlers, + { + ...defaultConfig, + rum: { + enable: true, + sourceCodeContext: { + service: SERVICE_NAME, + version: SERVICE_VERSION, + }, + }, + }, + { splitting: true }, + ); + }); + + test('Should inject DD_SOURCE_CODE_CONTEXT global variable', async ({ + page, + bundler, + browserName, + suiteName, + devServerUrl, + }) => { + const errors: string[] = []; + const testBaseUrl = `${devServerUrl}/${suiteName}`; + + // Listen for errors on the page. + page.on('pageerror', (error) => errors.push(error.message)); + page.on('response', async (response) => { + if (!response.ok()) { + const url = response.request().url(); + const prefix = `[${bundler} ${browserName} ${response.status()}]`; + errors.push(`${prefix} ${url}`); + } + }); + + await userFlow(testBaseUrl, page, bundler); + + // Check that DD_SOURCE_CODE_CONTEXT is defined + const hasContext = await page.evaluate(() => { + return typeof (globalThis as any).DD_SOURCE_CODE_CONTEXT !== 'undefined'; + }); + + expect(hasContext).toBe(true); + expect(errors).toEqual([]); + }); + + test('Should not throw errors', async ({ + page, + bundler, + browserName, + suiteName, + devServerUrl, + }) => { + const errors: string[] = []; + const testBaseUrl = `${devServerUrl}/${suiteName}`; + + // Listen for errors on the page. + page.on('pageerror', (error) => errors.push(error.message)); + + // Mock error to confirm the snippet’s try/catch blocks failures + await page.addInitScript(() => { + (globalThis as any).Error = function () { + // eslint-disable-next-line no-throw-literal + throw 'Test error from source code context'; + }; + }); + + await userFlow(testBaseUrl, page, bundler); + expect(errors).toEqual([]); + }); + + test('Should enrich RUM events with source code context (service/version)', async ({ + page, + bundler, + suiteName, + devServerUrl, + }) => { + await userFlow(`${devServerUrl}/${suiteName}`, page, bundler); + + // Initialize RUM with beforeSend. + await page.evaluate(() => { + (globalThis as any).rum_events = []; + (globalThis as any).DD_RUM.init({ + clientToken: '', + applicationId: '', + enableExperimentalFeatures: ['source_code_context'], + beforeSend: (event: any) => { + (globalThis as any).rum_events.push(event); + return true; + }, + }); + }); + + await page.click('#load_chunk'); + await page.waitForFunction(() => window.chunkLoaded === true); + // Only testing error events here. Integration tests covering all RUM event types + // with source code context are maintained in the Browser SDK repository to avoid duplication. + await page.click('#trigger_entry_error'); + await page.click('#trigger_chunk_error'); + + const events = await getRUMEvents(page); + + const predicate = (message: string) => (event: any) => + event.type === 'error' && event.error.message === message; + const entryError = events.find(predicate('entry_error')); + const chunkError = events.find(predicate('chunk_error')); + + expect(entryError).toMatchObject({ version: SERVICE_VERSION, service: SERVICE_NAME }); + expect(chunkError).toMatchObject({ version: SERVICE_VERSION, service: SERVICE_NAME }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 2d2b14bec..b8c213fe3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1625,34 +1625,34 @@ __metadata: languageName: node linkType: hard -"@datadog/browser-core@npm:6.24.0": - version: 6.24.0 - resolution: "@datadog/browser-core@npm:6.24.0" - checksum: 10/601add9977a9b761c1a2e86c37249a8593b5494509a75bc7582d93f7596185510a8ad7ed96d206824a9141850bc4120e9424cf8b630fa82606ea32ed2f246718 +"@datadog/browser-core@npm:6.26.0": + version: 6.26.0 + resolution: "@datadog/browser-core@npm:6.26.0" + checksum: 10/c5a84b637d40d2d0a50c63871d49f2cbdb328f932f123e6936c5e5cb2c07b0fdf739f80c2762366dd22364d1eb9356c5c39f80831b36fa5f8ae8d0fcc75eafcd languageName: node linkType: hard -"@datadog/browser-rum-core@npm:6.24.0": - version: 6.24.0 - resolution: "@datadog/browser-rum-core@npm:6.24.0" +"@datadog/browser-rum-core@npm:6.26.0": + version: 6.26.0 + resolution: "@datadog/browser-rum-core@npm:6.26.0" dependencies: - "@datadog/browser-core": "npm:6.24.0" - checksum: 10/eea74ab7e6f83fefa8733ab76425cd5b125828edfba7805db226f1f214a3800b455a9745ddae6e64672324e701a3f143341b8fe0eb9c233351a17a9843e3411b + "@datadog/browser-core": "npm:6.26.0" + checksum: 10/2d3423c324f7e0e462b3a2ba6af1a88829f763bc9c6d4d721334a1c97f4e6999556369a4ab9b7cdabedba2466fa7ec0204ad185b77e01400d443ef7a85c52728 languageName: node linkType: hard -"@datadog/browser-rum@npm:6.24.0": - version: 6.24.0 - resolution: "@datadog/browser-rum@npm:6.24.0" +"@datadog/browser-rum@npm:6.26.0": + version: 6.26.0 + resolution: "@datadog/browser-rum@npm:6.26.0" dependencies: - "@datadog/browser-core": "npm:6.24.0" - "@datadog/browser-rum-core": "npm:6.24.0" + "@datadog/browser-core": "npm:6.26.0" + "@datadog/browser-rum-core": "npm:6.26.0" peerDependencies: - "@datadog/browser-logs": 6.24.0 + "@datadog/browser-logs": 6.26.0 peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10/c1b7fc06871b0bc0b725f7dfbc05808a7d06f9d8ef0232157f0b8c90f20a8fc6399177e750f0f993e24930af910cd6aab5005a5bb4df86145333f6024286d944 + checksum: 10/53b9309ea5e5d825cdee06933beca87a6b631f63ecdd8a0cd68c43c3e23f4891be3dcf394e8ae658c558fc185f022b5d678a984ba5011c8f17d94cf4f9701b06 languageName: node linkType: hard @@ -2039,7 +2039,7 @@ __metadata: version: 0.0.0-use.local resolution: "@dd/rum-plugin@workspace:packages/plugins/rum" dependencies: - "@datadog/browser-rum": "npm:6.24.0" + "@datadog/browser-rum": "npm:6.26.0" "@datadog/js-instrumentation-wasm": "npm:1.0.8" "@dd/core": "workspace:*" chalk: "npm:2.3.1" @@ -2051,6 +2051,7 @@ __metadata: version: 0.0.0-use.local resolution: "@dd/tests@workspace:packages/tests" dependencies: + "@datadog/browser-rum": "npm:6.26.0" "@datadog/esbuild-plugin": "workspace:*" "@datadog/rollup-plugin": "workspace:*" "@datadog/rspack-plugin": "workspace:*"