diff --git a/eslint-local-rules/disallowSideEffects.js b/eslint-local-rules/disallowSideEffects.js index 8bd1a9d8d4..890c5852df 100644 --- a/eslint-local-rules/disallowSideEffects.js +++ b/eslint-local-rules/disallowSideEffects.js @@ -35,6 +35,7 @@ const pathsWithSideEffect = new Set([ const packagesWithoutSideEffect = new Set([ '@datadog/browser-core', '@datadog/browser-rum-core', + '@datadog/browser-rum-react/internal', 'react', 'react-router-dom', 'vue', diff --git a/package.json b/package.json index 82da504c7d..64e413b88d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "build:apps": "node scripts/build/build-test-apps.ts", "build:docs:json": "typedoc --logLevel Verbose --json ./generated-docs.json", "build:docs:html": "typedoc --out ./generated-docs", - "pack": "yarn workspaces foreach --all --parallel --include '@datadog/*' exec yarn pack", + "pack": "yarn workspaces foreach --all --parallel --topological --include '@datadog/*' exec yarn pack", "format": "prettier --check .", "lint": "NODE_OPTIONS='--max-old-space-size=4096' eslint .", "typecheck": "tsc -b --noEmit true", diff --git a/packages/rum-nextjs/package.json b/packages/rum-nextjs/package.json index af0a91c39f..defb831a66 100644 --- a/packages/rum-nextjs/package.json +++ b/packages/rum-nextjs/package.json @@ -11,7 +11,8 @@ }, "dependencies": { "@datadog/browser-core": "6.31.0", - "@datadog/browser-rum-core": "6.31.0" + "@datadog/browser-rum-core": "6.31.0", + "@datadog/browser-rum-react": "6.31.0" }, "peerDependencies": { "next": ">=13.0.0", @@ -36,6 +37,7 @@ "devDependencies": { "@types/react": "19.2.11", "next": "15.5.10", - "react": "19.2.4" + "react": "19.2.4", + "react-dom": "19.2.4" } } diff --git a/packages/rum-nextjs/src/domain/error/errorBoundary.spec.tsx b/packages/rum-nextjs/src/domain/error/errorBoundary.spec.tsx new file mode 100644 index 0000000000..123aede1a5 --- /dev/null +++ b/packages/rum-nextjs/src/domain/error/errorBoundary.spec.tsx @@ -0,0 +1,42 @@ +import React from 'react' + +import { disableJasmineUncaughtExceptionTracking, ignoreConsoleLogs } from '@datadog/browser-core/test' +import { appendComponent } from '../../../../rum-react/test/appendComponent' +import { initReactOldBrowsersSupport } from '../../../../rum-react/test/reactOldBrowsersSupport' +import { initializeNextjsPlugin } from '../../../test/initializeNextjsPlugin' +import { ErrorBoundary } from './errorBoundary' + +// Component behavior (renders children, fallback, resetError) is tested via createErrorBoundary +// in packages/rum-react/src/domain/error/errorBoundary.spec.tsx + +describe('NextjsErrorBoundary', () => { + it('reports the error through addNextjsError', () => { + ignoreConsoleLogs('error', 'Error: error') + disableJasmineUncaughtExceptionTracking() + initReactOldBrowsersSupport() + + const addErrorSpy = jasmine.createSpy() + initializeNextjsPlugin({ addError: addErrorSpy }) + const originalError = new Error('error') + const ComponentSpy = jasmine.createSpy().and.throwError(originalError) + ;(ComponentSpy as any).displayName = 'ComponentSpy' + + appendComponent( + null}> + + + ) + + expect(addErrorSpy).toHaveBeenCalledOnceWith( + jasmine.objectContaining({ + error: originalError, + handlingStack: jasmine.any(String), + startClocks: jasmine.any(Object), + context: jasmine.objectContaining({ + framework: 'nextjs', + }), + componentStack: jasmine.stringContaining('ComponentSpy'), + }) + ) + }) +}) diff --git a/packages/rum-nextjs/src/domain/error/errorBoundary.ts b/packages/rum-nextjs/src/domain/error/errorBoundary.ts new file mode 100644 index 0000000000..67ad094d54 --- /dev/null +++ b/packages/rum-nextjs/src/domain/error/errorBoundary.ts @@ -0,0 +1,22 @@ +'use client' +import { createErrorBoundary } from '@datadog/browser-rum-react/internal' +export type { ErrorBoundaryFallback, ErrorBoundaryProps } from '@datadog/browser-rum-react/internal' +import { addNextjsError } from './addNextjsError' + +/** + * ErrorBoundary component to report React errors to Datadog using the Next.js error context. + * + * For more advanced error handling, you can use the {@link addNextjsError} function. + * + * @category Error + * @example + * ```ts + * import { ErrorBoundary } from '@datadog/browser-rum-nextjs' + * + * null}> + * + * + * ``` + */ +// eslint-disable-next-line local-rules/disallow-side-effects +export const ErrorBoundary = createErrorBoundary(addNextjsError) diff --git a/packages/rum-nextjs/src/entries/main.ts b/packages/rum-nextjs/src/entries/main.ts index d6bdb2237f..70f1d03311 100644 --- a/packages/rum-nextjs/src/entries/main.ts +++ b/packages/rum-nextjs/src/entries/main.ts @@ -3,3 +3,5 @@ export type { NextjsPlugin } from '../domain/nextjsPlugin' export { DatadogAppRouter } from '../domain/nextJSRouter/datadogAppRouter' export { DatadogPagesRouter } from '../domain/nextJSRouter/datadogPagesRouter' export { addNextjsError } from '../domain/error/addNextjsError' +export { ErrorBoundary } from '../domain/error/errorBoundary' +export type { ErrorBoundaryFallback, ErrorBoundaryProps } from '../domain/error/errorBoundary' diff --git a/test/apps/angular-app/yarn.lock b/test/apps/angular-app/yarn.lock index 5c3c417df6..7070b9c168 100644 --- a/test/apps/angular-app/yarn.lock +++ b/test/apps/angular-app/yarn.lock @@ -296,14 +296,14 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=angular-app%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=d110af&locator=angular-app%40workspace%3A." - checksum: 10c0/1e3797a56310fde499578396bd2594c4e0ac891610e7d57ddac2164a8c29a97177b3eac938f6a8480192bb31b5d798acaf2ea26de1778047d43c010ff0124dc0 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=6201e3&locator=angular-app%40workspace%3A." + checksum: 10c0/a019713374971a2dd35c63318cecd76e38d08348a24ca5b88abb8fca8501d17589e187bd4e68c7358f3523dd3fd08d110b307647854a620b0f3371f2c7db14ca languageName: node linkType: hard "@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz::locator=angular-app%40workspace%3A.": version: 0.0.0 - resolution: "@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz#../../../packages/rum-angular/package.tgz::hash=1db391&locator=angular-app%40workspace%3A." + resolution: "@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz#../../../packages/rum-angular/package.tgz::hash=004229&locator=angular-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" @@ -311,27 +311,22 @@ __metadata: "@angular/core": ">=15 <=21" "@angular/router": ">=15 <=21" rxjs: ">=7" - peerDependenciesMeta: - "@angular/core": - optional: true - "@angular/router": - optional: true - checksum: 10c0/837488f8f27aee3c58e0be4f91039b2de9c3bc00e655f6f65bd5992c1101443ae48fbeedc68c95ef4281535c3a4de8c3e3073974b2938ebb493cf23e3a91f5a6 + checksum: 10c0/ec9054d51805f45cb4618bcbc6fa00049ba5d1597048aa3c354aea14a15a06275ee0ba06b3de7d77fbd0d2f009f74159a88e10f2f6b9e629eeed0a5ca30a27ae languageName: node linkType: hard "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=angular-app%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=638808&locator=angular-app%40workspace%3A." + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=0334b6&locator=angular-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" - checksum: 10c0/f57c5d9fdbc7243f373afba6912bb75a90f3b65ab036750a858aa7776ed30b8921e456eff32a02e7dc021c192cd7bc220ea7b124459eacb7685c5c5ba0cca1c5 + checksum: 10c0/3ece55e0ca0bc0691fd91c557433c806e2871b56e3a0008c01b6e369809c9130fa384952b22ee6464d49d182d3e4e5bd66f51b6b629d4024d6e482f7e64d13c8 languageName: node linkType: hard "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=angular-app%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=920d70&locator=angular-app%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=033900&locator=angular-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" @@ -340,7 +335,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/135a2cdf999ea9505e08031ae7069f4d6a236a88e6203ef7105c784a77ae23a23fbabc648d793305dcb4b960cbe4a535fab2d688748efb5824137597f4de84b5 + checksum: 10c0/ac0080efb7f664a5664162a64e618b885d2c4d2d06426db0ad076c855dd02cbc84f1ba6fc30913db8db74d50a511d0a0a62ba1ad7bb9e8de5c3ef0c03e3f9c56 languageName: node linkType: hard diff --git a/test/apps/nextjs/pages/pages-router/error-test.tsx b/test/apps/nextjs/pages/pages-router/error-test.tsx new file mode 100644 index 0000000000..9ec73b34d1 --- /dev/null +++ b/test/apps/nextjs/pages/pages-router/error-test.tsx @@ -0,0 +1,35 @@ +import { ErrorBoundary } from '@datadog/browser-rum-nextjs' +import type { ErrorBoundaryFallback } from '@datadog/browser-rum-nextjs' +import { useState } from 'react' +import Link from 'next/link' + +function ErrorThrower() { + const [shouldThrow, setShouldThrow] = useState(false) + if (shouldThrow) throw new Error('Pages Router error from NextjsErrorBoundary') + return ( + + ) +} + +const ErrorFallback: ErrorBoundaryFallback = ({ error, resetError }) => ( +
+

{error.message}

+ +
+) + +export default function ErrorTestPage() { + return ( +
+ ← Back to Home +

Error Test

+ + + +
+ ) +} diff --git a/test/apps/nextjs/pages/pages-router/index.tsx b/test/apps/nextjs/pages/pages-router/index.tsx index cc03d59a47..2d31b81838 100644 --- a/test/apps/nextjs/pages/pages-router/index.tsx +++ b/test/apps/nextjs/pages/pages-router/index.tsx @@ -11,6 +11,9 @@ export default function HomePage() {
  • Go to Guides 123
  • +
  • + Go to Error Test +
  • ) diff --git a/test/apps/nextjs/pages/pages-router/user/[id].tsx b/test/apps/nextjs/pages/pages-router/user/[id].tsx index 54efa0f286..ef36c9180e 100644 --- a/test/apps/nextjs/pages/pages-router/user/[id].tsx +++ b/test/apps/nextjs/pages/pages-router/user/[id].tsx @@ -10,9 +10,15 @@ export default function UserPage() { ← Back to Home

    User {id}

    This is a dynamic route testing view name normalization.

    - Go to User 999 - Change query params - Go to Section +
    + Go to User 999 +
    +
    + Change query params +
    +
    + Go to Section +
    ) } diff --git a/test/apps/nextjs/yarn.lock b/test/apps/nextjs/yarn.lock index 350c54ea6d..2b2d9e7166 100644 --- a/test/apps/nextjs/yarn.lock +++ b/test/apps/nextjs/yarn.lock @@ -7,8 +7,8 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=nextjs%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=d35e3a&locator=nextjs%40workspace%3A." - checksum: 10c0/e35c0d98c72fa3ed46dcbd42615c156fcb13f4622681906145aac91630c291adc7a166861568e61a09f6301baed1adaf5c95b675b9407c72fbe936129f305253 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=6201e3&locator=nextjs%40workspace%3A." + checksum: 10c0/a019713374971a2dd35c63318cecd76e38d08348a24ca5b88abb8fca8501d17589e187bd4e68c7358f3523dd3fd08d110b307647854a620b0f3371f2c7db14ca languageName: node linkType: hard @@ -23,10 +23,11 @@ __metadata: "@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz::locator=nextjs%40workspace%3A.": version: 0.0.0 - resolution: "@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz#../../../packages/rum-nextjs/package.tgz::hash=0643d8&locator=nextjs%40workspace%3A." + resolution: "@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz#../../../packages/rum-nextjs/package.tgz::hash=33a720&locator=nextjs%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" + "@datadog/browser-rum-react": "npm:6.31.0" peerDependencies: next: ">=13.0.0" react: ">=18.0.0" @@ -35,13 +36,13 @@ __metadata: optional: true react: optional: true - checksum: 10c0/8f1ae5ce76730608a77b924f6c25cc9b325f314621fa1d03ed29a9a6d6a084dcfa61e9a36bb1f2005ff5939b5137dbe11ff5b27af09d41b3a5dcdbc0e0ef4ace + checksum: 10c0/5bd3c94fa2fa71d0c19626b8a8cdfa933da6bd0626a99abbd5d0bb07374c9bca9554eba05c427baf35fe0e0fbf4f891dd741822908a4cebe30ca4ea502ae9355 languageName: node linkType: hard "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz::locator=nextjs%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz#../../../packages/rum-react/package.tgz::hash=2dd471&locator=nextjs%40workspace%3A." + resolution: "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz#../../../packages/rum-react/package.tgz::hash=ff7bfc&locator=nextjs%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" @@ -66,7 +67,7 @@ __metadata: "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=nextjs%40workspace%3A.": version: 6.31.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=439f60&locator=nextjs%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=033900&locator=nextjs%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" @@ -75,7 +76,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/be73607a3c5602407ad824b7e149c633c9bfebf3e6fd543b56598a4067afcbbf28e6324be430b6e846aef8bee0c588e4bd258ae3671a1419a3fdaa31efa5e3f1 + checksum: 10c0/ac0080efb7f664a5664162a64e618b885d2c4d2d06426db0ad076c855dd02cbc84f1ba6fc30913db8db74d50a511d0a0a62ba1ad7bb9e8de5c3ef0c03e3f9c56 languageName: node linkType: hard @@ -415,18 +416,18 @@ __metadata: linkType: hard "baseline-browser-mapping@npm:^2.8.3": - version: 2.10.7 - resolution: "baseline-browser-mapping@npm:2.10.7" + version: 2.10.8 + resolution: "baseline-browser-mapping@npm:2.10.8" bin: baseline-browser-mapping: dist/cli.cjs - checksum: 10c0/fe2988088ede5a2dc7936f0a718d4b500b2a28a7ee3e11e2a3844a9444dd217a95a070c00508d8130da73c4fe576d677b21844bc078f6cd7867fb0e1be60caf0 + checksum: 10c0/a77882e8ac37a900a9a0757b9bf4e50f407829ed17ee7630273ab5da0ae10d9c64ed4c5a1e03afb3490e39713440092417ded4bb856eeb9bd44856eacbd97497 languageName: node linkType: hard "caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001778 - resolution: "caniuse-lite@npm:1.0.30001778" - checksum: 10c0/830042e0a6af0796d3da4d9575f60966b92308c5504577993b618dd196c835d023dbd725fa8b47c33b74c487d75ce01ee3ebd6e7a078714989513110e8ff80e5 + version: 1.0.30001780 + resolution: "caniuse-lite@npm:1.0.30001780" + checksum: 10c0/8a88f39758a228852d6f3ac92362ecb7694b1b2b022f194d8dfe59123ad40a5de6202bf2dff0fe316bb3d5ca9caf316c22056e0da693459c3be2771cde4f4bf9 languageName: node linkType: hard diff --git a/test/e2e/scenario/nextjsPlugin.scenario.ts b/test/e2e/scenario/nextjsPlugin.scenario.ts index ac4795f49b..395e695c71 100644 --- a/test/e2e/scenario/nextjsPlugin.scenario.ts +++ b/test/e2e/scenario/nextjsPlugin.scenario.ts @@ -14,6 +14,7 @@ const routerConfigs = [ router: 'pages' as const, viewPrefix: '/pages-router', homeUrlPattern: /\/pages-router(\?|$)/, + clientErrorMessage: 'Pages Router error from NextjsErrorBoundary', }, ] @@ -200,71 +201,77 @@ test.describe('nextjs - router', () => { }) test.describe('nextjs - errors', () => { - const { name, viewPrefix, clientErrorMessage, router } = routerConfigs[0] - - test.describe(name, () => { - createTest('should report client-side error') - .withRum() - .withNextjsApp(router) - .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Error Test') - await page.waitForURL(`**${viewPrefix}/error-test`) + routerConfigs.forEach(({ name, router, viewPrefix, clientErrorMessage }) => { + test.describe(name, () => { + createTest('should report client-side error') + .withRum() + .withNextjsApp(router) + .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs, browserName }) => { + test.skip( + browserName === 'firefox', + 'firefox is sending the errors in two separate batches, however the last batch is delayed making the test setup to miss it' + ) + await page.click('text=Go to Error Test') + await page.waitForURL(`**${viewPrefix}/error-test`) - await page.click('[data-testid="trigger-error"]') - await page.waitForSelector('[data-testid="error-boundary"]') + await page.click('[data-testid="trigger-error"]') + await page.waitForSelector('[data-testid="error-boundary"]') - await flushEvents() + await flushEvents() - const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') - expect(customErrors).toHaveLength(1) - expect(customErrors[0].error.message).toBe(clientErrorMessage) - expect(customErrors[0].error.handling_stack).toBeDefined() - expect(customErrors[0].context).toMatchObject({ framework: 'nextjs' }) + const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') + expect(customErrors).toHaveLength(1) + expect(customErrors[0].error.message).toBe(clientErrorMessage) + expect(customErrors[0].error.handling_stack).toBeDefined() + expect(customErrors[0].context).toMatchObject({ framework: 'nextjs' }) - withBrowserLogs((browserLogs) => { - expect(browserLogs.length).toBeGreaterThan(0) - }) - }) - - createTest('should report a server error with digest via addNextjsError') - .withRum() - .withNextjsApp(router) - .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Server Error') - await page.waitForSelector('[data-testid="error-boundary"]') - - await flushEvents() - - const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') - expect(customErrors).toHaveLength(1) - expect(customErrors[0].error.handling_stack).toBeDefined() - expect(customErrors[0].context).toMatchObject({ - framework: 'nextjs', - nextjs: { digest: expect.any(String) }, + withBrowserLogs((browserLogs) => { + expect(browserLogs.length).toBeGreaterThan(0) + }) }) - withBrowserLogs((browserLogs) => { - expect(browserLogs.length).toBeGreaterThan(0) - }) - }) + if (router === 'app') { + createTest('should report a server error with digest via addNextjsError') + .withRum() + .withNextjsApp(router) + .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { + await page.click('text=Go to Server Error') + await page.waitForSelector('[data-testid="error-boundary"]') - createTest('should report global error via global-error.tsx') - .withRum() - .withNextjsApp(router) - .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { - await page.click('text=Go to Global Error') - await page.waitForSelector('[data-testid="global-error-boundary"]') + await flushEvents() - await flushEvents() + const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') + expect(customErrors).toHaveLength(1) + expect(customErrors[0].error.handling_stack).toBeDefined() + expect(customErrors[0].context).toMatchObject({ + framework: 'nextjs', + nextjs: { digest: expect.any(String) }, + }) + + withBrowserLogs((browserLogs) => { + expect(browserLogs.length).toBeGreaterThan(0) + }) + }) - const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') - expect(customErrors).toHaveLength(1) - expect(customErrors[0].error.handling_stack).toBeDefined() - expect(customErrors[0].context).toMatchObject({ framework: 'nextjs' }) + createTest('should report global error via global-error.tsx') + .withRum() + .withNextjsApp(router) + .run(async ({ page, flushEvents, intakeRegistry, withBrowserLogs }) => { + await page.click('text=Go to Global Error') + await page.waitForSelector('[data-testid="global-error-boundary"]') - withBrowserLogs((browserLogs) => { - expect(browserLogs.length).toBeGreaterThan(0) - }) - }) + await flushEvents() + + const customErrors = intakeRegistry.rumErrorEvents.filter((e) => e.error.source === 'custom') + expect(customErrors).toHaveLength(1) + expect(customErrors[0].error.handling_stack).toBeDefined() + expect(customErrors[0].context).toMatchObject({ framework: 'nextjs' }) + + withBrowserLogs((browserLogs) => { + expect(browserLogs.length).toBeGreaterThan(0) + }) + }) + } + }) }) }) diff --git a/yarn.lock b/yarn.lock index 23f62ff94e..47fe7cada0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -372,9 +372,11 @@ __metadata: dependencies: "@datadog/browser-core": "npm:6.31.0" "@datadog/browser-rum-core": "npm:6.31.0" + "@datadog/browser-rum-react": "npm:6.31.0" "@types/react": "npm:19.2.11" next: "npm:15.5.10" react: "npm:19.2.4" + react-dom: "npm:19.2.4" peerDependencies: next: ">=13.0.0" react: ">=18.0.0" @@ -386,7 +388,7 @@ __metadata: languageName: unknown linkType: soft -"@datadog/browser-rum-react@workspace:packages/rum-react": +"@datadog/browser-rum-react@npm:6.31.0, @datadog/browser-rum-react@workspace:packages/rum-react": version: 0.0.0-use.local resolution: "@datadog/browser-rum-react@workspace:packages/rum-react" dependencies: