diff --git a/packages/rum-react/.npmignore b/packages/rum-react/.npmignore index 4049b9b2d8..c239794535 100644 --- a/packages/rum-react/.npmignore +++ b/packages/rum-react/.npmignore @@ -5,3 +5,4 @@ /src/**/*.spec.ts /src/**/*.specHelper.ts !/react-router-v[6-7]/* +!/nextjs/* diff --git a/packages/rum-react/nextjs/package.json b/packages/rum-react/nextjs/package.json new file mode 100644 index 0000000000..38b6e4229f --- /dev/null +++ b/packages/rum-react/nextjs/package.json @@ -0,0 +1,7 @@ +{ + "name": "@datadog/browser-rum-react/nextjs", + "private": true, + "main": "../cjs/entries/nextjs.js", + "module": "../esm/entries/nextjs.js", + "types": "../cjs/entries/nextjs.d.ts" +} diff --git a/packages/rum-react/nextjs/typedoc.json b/packages/rum-react/nextjs/typedoc.json new file mode 100644 index 0000000000..194695bc63 --- /dev/null +++ b/packages/rum-react/nextjs/typedoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["../src/entries/nextjs.ts"] +} diff --git a/packages/rum-react/package.json b/packages/rum-react/package.json index 61ada61be4..166c02d8f4 100644 --- a/packages/rum-react/package.json +++ b/packages/rum-react/package.json @@ -14,6 +14,7 @@ "@datadog/browser-rum-core": "6.28.0" }, "peerDependencies": { + "next": ">=13", "react": "18 || 19", "react-router": "6 || 7", "react-router-dom": "6 || 7" @@ -25,6 +26,9 @@ "@datadog/browser-rum-slim": { "optional": true }, + "next": { + "optional": true + }, "react": { "optional": true }, @@ -38,6 +42,7 @@ "devDependencies": { "@types/react": "19.2.14", "@types/react-dom": "19.2.3", + "next": "15.2.2", "react": "19.2.4", "react-dom": "19.2.4", "react-router": "7.13.0", diff --git a/packages/rum-react/src/domain/nextjs/computeNextViewName.spec.ts b/packages/rum-react/src/domain/nextjs/computeNextViewName.spec.ts new file mode 100644 index 0000000000..941657b357 --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/computeNextViewName.spec.ts @@ -0,0 +1,49 @@ +import { computeNextViewName } from './computeNextViewName' + +describe('computeNextViewName', () => { + // prettier-ignore + const cases = [ + // [pathname, params, expectedViewName] + + // Static routes (no params) + ['/about', {}, '/about'], + ['/search', {}, '/search'], + ['/', {}, '/'], + + // Single dynamic segment + ['/users/123', { id: '123' }, '/users/:id'], + + // Multiple dynamic segments + ['/users/123/posts/456', { userId: '123', postId: '456' }, '/users/:userId/posts/:postId'], + + // Param value appears multiple times (FR-4) + ['/a/123/b/123', { id: '123' }, '/a/:id/b/:id'], + + // Catch-all segments (FR-3) — string array params + ['/docs/a/b/c', { slug: ['a', 'b', 'c'] }, '/docs/:slug'], + + // Catch-all from root + ['/docs/getting-started', { slug: ['docs', 'getting-started'] }, '/:slug'], + + // Segment-aware replacement (does NOT replace inside segment names) + ['/abc/a/def', { id: 'a' }, '/abc/:id/def'], + + // Undefined param value (optional catch-all with no match) — skipped + ['/foo', { opt: undefined }, '/foo'], + + // Empty string param value — skipped + ['/foo', { empty: '' }, '/foo'], + + // Catch-all with single segment + ['/blog/hello', { slug: ['hello'] }, '/blog/:slug'], + + // Mixed dynamic + catch-all + ['/users/42/files/a/b', { id: '42', path: ['a', 'b'] }, '/users/:id/files/:path'], + ] as const + + cases.forEach(([pathname, params, expectedViewName]) => { + it(`returns "${expectedViewName}" for pathname "${pathname}" and params ${JSON.stringify(params)}`, () => { + expect(computeNextViewName(pathname, params as any)).toBe(expectedViewName) + }) + }) +}) diff --git a/packages/rum-react/src/domain/nextjs/computeNextViewName.ts b/packages/rum-react/src/domain/nextjs/computeNextViewName.ts new file mode 100644 index 0000000000..049c5248b2 --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/computeNextViewName.ts @@ -0,0 +1,70 @@ +import type { NextParams } from './types' + +/** + * Reconstructs the parameterized route pattern from a Next.js pathname and params object. + * + * Uses segment-aware replacement to avoid matching param values as substrings of other + * path segments. For example, `{ id: 'a' }` with `/abc/a/def` correctly produces + * `/abc/:id/def` rather than `/:idbc/:id/def`. + * + * Processing order: + * 1. Array (catch-all) params are processed before string params, so the full contiguous + * segment sequence can be matched before individual segments are replaced. + * 2. String params are sorted by descending value length as a safety measure for edge cases + * where two params share values that are substrings of each other. + */ +export function computeNextViewName(pathname: string, params: NextParams): string { + const segments = pathname.split('/') + + // Sort entries: arrays first, then strings sorted by descending length. + // This ensures catch-all params are matched before individual segments, + // and longer values are matched before shorter ones to avoid partial replacements. + const entries = Object.entries(params).sort((a, b) => { + const aIsArray = Array.isArray(a[1]) + const bIsArray = Array.isArray(b[1]) + if (aIsArray !== bIsArray) { + return aIsArray ? -1 : 1 + } + // For strings, sort by descending value length + if (!aIsArray && !bIsArray) { + return String(b[1] ?? '').length - String(a[1] ?? '').length + } + return 0 + }) + + for (const [paramName, paramValue] of entries) { + if (paramValue === undefined || paramValue === '') { + continue + } + + if (Array.isArray(paramValue)) { + // Catch-all: find the first contiguous sequence of segments matching the array + if (paramValue.length === 0) { + continue + } + for (let i = 0; i <= segments.length - paramValue.length; i++) { + let matches = true + for (let j = 0; j < paramValue.length; j++) { + if (segments[i + j] !== paramValue[j]) { + matches = false + break + } + } + if (matches) { + // Replace the contiguous run with a single :paramName segment + segments.splice(i, paramValue.length, `:${paramName}`) + break // Only replace the first occurrence for catch-all + } + } + } else { + // String: replace all matching segments + for (let i = 0; i < segments.length; i++) { + if (segments[i] === paramValue) { + segments[i] = `:${paramName}` + } + } + } + } + + return segments.join('/') +} diff --git a/packages/rum-react/src/domain/nextjs/datadogRumProvider.spec.tsx b/packages/rum-react/src/domain/nextjs/datadogRumProvider.spec.tsx new file mode 100644 index 0000000000..4c63a81006 --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/datadogRumProvider.spec.tsx @@ -0,0 +1,144 @@ +import React, { act } from 'react' +import { display } from '@datadog/browser-core' +import { usePathname, useParams } from 'next/navigation' +import { replaceMockable } from '../../../../core/test' +import { appendComponent } from '../../../test/appendComponent' +import { initializeReactPlugin } from '../../../test/initializeReactPlugin' +import { DatadogRumProvider } from './datadogRumProvider' +import type { NextParams } from './types' + +describe('DatadogRumProvider', () => { + let mockPathname: string + let mockParams: NextParams + let startViewSpy: jasmine.Spy + + beforeEach(() => { + mockPathname = '/' + mockParams = {} + + replaceMockable(usePathname, (() => mockPathname) as typeof usePathname) + replaceMockable(useParams, (() => mockParams) as typeof useParams) + + startViewSpy = jasmine.createSpy() + initializeReactPlugin({ + configuration: { nextAppRouter: true }, + publicApi: { startView: startViewSpy }, + }) + }) + + it('starts a view on initial mount', () => { + mockPathname = '/users/123' + mockParams = { id: '123' } + + appendComponent(content) + + expect(startViewSpy).toHaveBeenCalledOnceWith('/users/:id') + }) + + it('renders children without wrapper DOM elements', () => { + const container = appendComponent( + + hello + + ) + + expect(container.innerHTML).toBe('hello') + }) + + it('does not start a new view on re-render with same pathname', () => { + mockPathname = '/about' + + let forceUpdate: () => void + + function App() { + const [, setState] = React.useState(0) + forceUpdate = () => setState((s) => s + 1) + return content + } + + appendComponent() + expect(startViewSpy).toHaveBeenCalledTimes(1) + + act(() => { + forceUpdate!() + }) + + expect(startViewSpy).toHaveBeenCalledTimes(1) + }) + + it('starts a new view when the view name changes', () => { + mockPathname = '/users/123' + mockParams = { id: '123' } + + let forceUpdate: () => void + + function App() { + const [, setState] = React.useState(0) + forceUpdate = () => setState((s) => s + 1) + return content + } + + appendComponent() + startViewSpy.calls.reset() + + // Navigate to a different route pattern + mockPathname = '/about' + mockParams = {} + + act(() => { + forceUpdate!() + }) + + expect(startViewSpy).toHaveBeenCalledOnceWith('/about') + }) + + it('does not start a new view when navigating to a different instance of the same route', () => { + mockPathname = '/users/123' + mockParams = { id: '123' } + + let forceUpdate: () => void + + function App() { + const [, setState] = React.useState(0) + forceUpdate = () => setState((s) => s + 1) + return content + } + + appendComponent() + expect(startViewSpy).toHaveBeenCalledOnceWith('/users/:id') + startViewSpy.calls.reset() + + // Navigate to a different user — same route pattern /users/:id + mockPathname = '/users/456' + mockParams = { id: '456' } + + act(() => { + forceUpdate!() + }) + + expect(startViewSpy).not.toHaveBeenCalled() + }) + + it('starts a view with raw pathname for static routes', () => { + mockPathname = '/about' + mockParams = {} + + appendComponent(content) + + expect(startViewSpy).toHaveBeenCalledOnceWith('/about') + }) + + it('warns when nextAppRouter config is missing', () => { + const displayWarnSpy = spyOn(display, 'warn') + initializeReactPlugin({ + configuration: {}, + publicApi: { startView: startViewSpy }, + }) + + mockPathname = '/about' + + appendComponent(content) + + expect(displayWarnSpy).toHaveBeenCalledOnceWith(jasmine.stringContaining('`nextAppRouter: true` is missing')) + }) +}) diff --git a/packages/rum-react/src/domain/nextjs/datadogRumProvider.tsx b/packages/rum-react/src/domain/nextjs/datadogRumProvider.tsx new file mode 100644 index 0000000000..7144577de9 --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/datadogRumProvider.tsx @@ -0,0 +1,22 @@ +import React, { useRef, type ReactNode } from 'react' +import { mockable } from '@datadog/browser-core' +import { usePathname, useParams } from 'next/navigation' +import { startNextjsView } from './startNextjsView' +import { computeNextViewName } from './computeNextViewName' + +export function DatadogRumProvider({ children }: { children: ReactNode }) { + const pathname = mockable(usePathname)() + const params = mockable(useParams)() + const viewNameRef = useRef(null) + + const viewName = computeNextViewName(pathname, params ?? {}) + + if (viewNameRef.current !== viewName) { + viewNameRef.current = viewName + startNextjsView(viewName) + } + + return <>{children} +} + +DatadogRumProvider.displayName = 'DatadogRumProvider' diff --git a/packages/rum-react/src/domain/nextjs/index.ts b/packages/rum-react/src/domain/nextjs/index.ts new file mode 100644 index 0000000000..862a8d8f2b --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/index.ts @@ -0,0 +1,4 @@ +export { computeNextViewName } from './computeNextViewName' +export { startNextjsView } from './startNextjsView' +export { DatadogRumProvider } from './datadogRumProvider' +export type { NextParams } from './types' diff --git a/packages/rum-react/src/domain/nextjs/startNextjsView.spec.ts b/packages/rum-react/src/domain/nextjs/startNextjsView.spec.ts new file mode 100644 index 0000000000..4a1b01d54f --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/startNextjsView.spec.ts @@ -0,0 +1,70 @@ +import { display } from '@datadog/browser-core' +import type { RumInitConfiguration, RumPublicApi } from '@datadog/browser-rum-core' +import { registerCleanupTask } from '../../../../core/test' +import { reactPlugin, resetReactPlugin } from '../reactPlugin' +import { initializeReactPlugin } from '../../../test/initializeReactPlugin' +import { startNextjsView } from './startNextjsView' + +describe('startNextjsView', () => { + it('starts a view with the given view name', () => { + const startViewSpy = jasmine.createSpy() + initializeReactPlugin({ + configuration: { + nextAppRouter: true, + }, + publicApi: { + startView: startViewSpy, + }, + }) + + startNextjsView('/users/:id') + + expect(startViewSpy).toHaveBeenCalledOnceWith('/users/:id') + }) + + it('displays a warning if nextAppRouter is not enabled', () => { + const displayWarnSpy = spyOn(display, 'warn') + initializeReactPlugin({ + configuration: {}, + }) + + startNextjsView('/users/:id') + + expect(displayWarnSpy).toHaveBeenCalledOnceWith( + '`nextAppRouter: true` is missing from the react plugin configuration, the view will not be tracked.' + ) + }) + + it('does not start a view when nextAppRouter is not enabled', () => { + const startViewSpy = jasmine.createSpy() + initializeReactPlugin({ + configuration: {}, + publicApi: { + startView: startViewSpy, + }, + }) + + startNextjsView('/users/:id') + + expect(startViewSpy).not.toHaveBeenCalled() + }) + + it('defers view start until RUM is initialized', () => { + const startViewSpy = jasmine.createSpy() + // Reset plugin state so no global init has happened yet + resetReactPlugin() + registerCleanupTask(() => resetReactPlugin()) + + // Call before init — callback is queued + startNextjsView('/users/:id') + expect(startViewSpy).not.toHaveBeenCalled() + + // Initialize the plugin — queued callbacks fire + reactPlugin({ nextAppRouter: true }).onInit({ + publicApi: { startView: startViewSpy } as unknown as RumPublicApi, + initConfiguration: {} as RumInitConfiguration, + }) + + expect(startViewSpy).toHaveBeenCalledOnceWith('/users/:id') + }) +}) diff --git a/packages/rum-react/src/domain/nextjs/startNextjsView.ts b/packages/rum-react/src/domain/nextjs/startNextjsView.ts new file mode 100644 index 0000000000..8364492a8d --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/startNextjsView.ts @@ -0,0 +1,14 @@ +import { display } from '@datadog/browser-core' +import { onRumInit } from '../reactPlugin' + +export function startNextjsView(viewName: string) { + onRumInit((configuration, rumPublicApi) => { + if (!configuration.nextAppRouter) { + display.warn( + '`nextAppRouter: true` is missing from the react plugin configuration, the view will not be tracked.' + ) + return + } + rumPublicApi.startView(viewName) + }) +} diff --git a/packages/rum-react/src/domain/nextjs/types.ts b/packages/rum-react/src/domain/nextjs/types.ts new file mode 100644 index 0000000000..85d07c525d --- /dev/null +++ b/packages/rum-react/src/domain/nextjs/types.ts @@ -0,0 +1,6 @@ +/** + * Type contract for Next.js `useParams()` return value. + * Each entry can be a single string (dynamic segment), a string array (catch-all segment), + * or undefined (optional catch-all with no match). + */ +export type NextParams = Record diff --git a/packages/rum-react/src/domain/reactPlugin.spec.ts b/packages/rum-react/src/domain/reactPlugin.spec.ts index 2540c79186..369e7a5e59 100644 --- a/packages/rum-react/src/domain/reactPlugin.spec.ts +++ b/packages/rum-react/src/domain/reactPlugin.spec.ts @@ -1,3 +1,4 @@ +import { display } from '@datadog/browser-core' import type { RumInitConfiguration, RumPublicApi } from '@datadog/browser-rum-core' import { onRumInit, reactPlugin, resetReactPlugin } from './reactPlugin' @@ -69,6 +70,44 @@ describe('reactPlugin', () => { const pluginConfiguration = { router: true } const plugin = reactPlugin(pluginConfiguration) - expect(plugin.getConfigurationTelemetry()).toEqual({ router: true }) + expect(plugin.getConfigurationTelemetry()).toEqual({ router: true, nextAppRouter: false }) + }) + + it('enforce manual view tracking when nextAppRouter is enabled', () => { + const initConfiguration = { ...INIT_CONFIGURATION } + reactPlugin({ nextAppRouter: true }).onInit({ publicApi: PUBLIC_API, initConfiguration }) + + expect(initConfiguration.trackViewsManually).toBe(true) + }) + + it('does not enforce manual view tracking when nextAppRouter is disabled', () => { + const initConfiguration = { ...INIT_CONFIGURATION } + reactPlugin({ nextAppRouter: false }).onInit({ publicApi: PUBLIC_API, initConfiguration }) + + expect(initConfiguration.trackViewsManually).toBeUndefined() + }) + + it('warns when both router and nextAppRouter are enabled', () => { + const displayWarnSpy = spyOn(display, 'warn') + const initConfiguration = { ...INIT_CONFIGURATION } + reactPlugin({ router: true, nextAppRouter: true }).onInit({ + publicApi: PUBLIC_API, + initConfiguration, + }) + + expect(displayWarnSpy).toHaveBeenCalledOnceWith(jasmine.stringContaining('Both `router` and `nextAppRouter`')) + expect(initConfiguration.trackViewsManually).toBe(true) + }) + + it('returns the configuration telemetry with nextAppRouter', () => { + const plugin = reactPlugin({ nextAppRouter: true }) + + expect(plugin.getConfigurationTelemetry()).toEqual({ router: false, nextAppRouter: true }) + }) + + it('returns the configuration telemetry with both router and nextAppRouter', () => { + const plugin = reactPlugin({ router: true, nextAppRouter: true }) + + expect(plugin.getConfigurationTelemetry()).toEqual({ router: true, nextAppRouter: true }) }) }) diff --git a/packages/rum-react/src/domain/reactPlugin.ts b/packages/rum-react/src/domain/reactPlugin.ts index 946e733ff7..53d4660646 100644 --- a/packages/rum-react/src/domain/reactPlugin.ts +++ b/packages/rum-react/src/domain/reactPlugin.ts @@ -1,3 +1,4 @@ +import { display } from '@datadog/browser-core' import type { RumPlugin, RumPublicApi, StartRumResult } from '@datadog/browser-rum-core' let globalPublicApi: RumPublicApi | undefined @@ -23,6 +24,11 @@ export interface ReactPluginConfiguration { * ``` */ router?: boolean + /** + * Enable Next.js App Router integration. Make sure to use `DatadogRumProvider` from + * {@link @datadog/browser-rum-react/nextjs! | @datadog/browser-rum-react/nextjs}. + */ + nextAppRouter?: boolean } /** @@ -61,9 +67,12 @@ export function reactPlugin(configuration: ReactPluginConfiguration = {}): React for (const subscriber of onRumInitSubscribers) { subscriber(globalConfiguration, globalPublicApi) } - if (configuration.router) { + if (configuration.router || configuration.nextAppRouter) { initConfiguration.trackViewsManually = true } + if (configuration.router && configuration.nextAppRouter) { + display.warn('Both `router` and `nextAppRouter` are enabled. Only `nextAppRouter` will be used.') + } }, onRumStart({ addEvent }) { globalAddEvent = addEvent @@ -74,7 +83,7 @@ export function reactPlugin(configuration: ReactPluginConfiguration = {}): React } }, getConfigurationTelemetry() { - return { router: !!configuration.router } + return { router: !!configuration.router, nextAppRouter: !!configuration.nextAppRouter } }, } satisfies RumPlugin } diff --git a/packages/rum-react/src/entries/nextjs.ts b/packages/rum-react/src/entries/nextjs.ts new file mode 100644 index 0000000000..a8da8ab5d6 --- /dev/null +++ b/packages/rum-react/src/entries/nextjs.ts @@ -0,0 +1,32 @@ +/** + * Next.js App Router integration. + * + * @packageDocumentation + * @example + * ```tsx + * // lib/datadog.ts + * 'use client' + * import { datadogRum } from '@datadog/browser-rum' + * import { reactPlugin } from '@datadog/browser-rum-react' + * + * datadogRum.init({ + * applicationId: '', + * clientToken: '', + * plugins: [reactPlugin({ nextAppRouter: true })], + * }) + * + * // app/layout.tsx + * import { DatadogRumProvider } from '@datadog/browser-rum-react/nextjs' + * + * export default function RootLayout({ children }: { children: React.ReactNode }) { + * return ( + * + * + * {children} + * + * + * ) + * } + * ``` + */ +export { DatadogRumProvider } from '../domain/nextjs' diff --git a/scripts/build/build-test-apps.ts b/scripts/build/build-test-apps.ts index 1af38f9102..a7fbed2870 100644 --- a/scripts/build/build-test-apps.ts +++ b/scripts/build/build-test-apps.ts @@ -16,6 +16,7 @@ runMain(async () => { buildApp('test/apps/vanilla') buildApp('test/apps/react-router-v6-app') + buildApp('test/apps/nextjs-app') buildApp('test/apps/react-heavy-spa') buildApp('test/apps/react-shopist-like') await buildReactRouterv7App() diff --git a/test/apps/nextjs-app/.gitignore b/test/apps/nextjs-app/.gitignore new file mode 100644 index 0000000000..e20e3cfac7 --- /dev/null +++ b/test/apps/nextjs-app/.gitignore @@ -0,0 +1,3 @@ +dist +node_modules +.yarn/* diff --git a/test/apps/nextjs-app/app.tsx b/test/apps/nextjs-app/app.tsx new file mode 100644 index 0000000000..9e5e4f500b --- /dev/null +++ b/test/apps/nextjs-app/app.tsx @@ -0,0 +1,142 @@ +import React, { useState } from 'react' +import ReactDOM from 'react-dom/client' +import { datadogRum } from '@datadog/browser-rum' +import { + reactPlugin, + UNSTABLE_ReactComponentTracker as ReactComponentTracker, + ErrorBoundary, +} from '@datadog/browser-rum-react' +import { DatadogRumProvider } from '@datadog/browser-rum-react/nextjs' +import { NavigationProvider, usePathname, useNavigate } from './mockNextNavigation' + +declare global { + interface Window { + RUM_CONFIGURATION?: any + RUM_CONTEXT?: any + } +} + +datadogRum.init({ ...window.RUM_CONFIGURATION, plugins: [reactPlugin({ nextAppRouter: true })] }) +if (window.RUM_CONTEXT) { + datadogRum.setGlobalContext(window.RUM_CONTEXT) +} + +function Link({ + to, + params, + children, +}: { + to: string + params?: Record + children: React.ReactNode +}) { + const navigate = useNavigate() + return ( + { + e.preventDefault() + navigate(to, params) + }} + > + {children} + + ) +} + +function HomePage() { + return ( +
+

Home

+ + Go to User + +
+ Go to Tracked +
+ Go to Error Component +
+ ) +} + +function UserPage() { + const pathname = usePathname() + const id = pathname.split('/').pop() + return ( +
+

User {id}

+
+ ) +} + +function TrackedPage() { + return ( + +

Component Tracker

+
+ ) +} + +function ComponentWithErrorButton() { + const [shouldError, setShouldError] = useState(false) + + if (shouldError) { + throw new Error('Error triggered by button click') + } + + return ( +
+

Component with Error Button

+ +
+ ) +} + +function ErrorPage() { + return ( +
+

Error Page

+ ( +
+

Something went wrong

+

{error.message}

+ +
+ )} + > + +
+
+ ) +} + +function App() { + const pathname = usePathname() + + if (pathname.startsWith('/user/')) { + return + } + if (pathname === '/tracked') { + return + } + if (pathname === '/error') { + return + } + return +} + +const rootElement = document.createElement('div') +document.body.appendChild(rootElement) +const root = ReactDOM.createRoot(rootElement) +root.render( + + + + + + + +) diff --git a/test/apps/nextjs-app/mockNextNavigation.tsx b/test/apps/nextjs-app/mockNextNavigation.tsx new file mode 100644 index 0000000000..b0a559472b --- /dev/null +++ b/test/apps/nextjs-app/mockNextNavigation.tsx @@ -0,0 +1,46 @@ +import React, { createContext, useContext, useState, useCallback, type ReactNode } from 'react' + +type Params = Record + +interface NavigationState { + pathname: string + params: Params +} + +interface NavigationContextType extends NavigationState { + navigate: (pathname: string, params?: Params) => void +} + +const NavigationContext = createContext({ + pathname: '/', + params: {}, + // eslint-disable-next-line @typescript-eslint/no-empty-function + navigate: (_pathname: string, _params?: Params) => {}, +}) + +export function usePathname(): string { + return useContext(NavigationContext).pathname +} + +export function useParams(): Params { + return useContext(NavigationContext).params +} + +export function useNavigate() { + return useContext(NavigationContext).navigate +} + +export function NavigationProvider({ + children, + initialPathname = '/', +}: { + children: ReactNode + initialPathname?: string +}) { + const [state, setState] = useState({ pathname: initialPathname, params: {} }) + const navigate = useCallback((pathname: string, params: Params = {}) => { + setState({ pathname, params }) + }, []) + + return {children} +} diff --git a/test/apps/nextjs-app/package.json b/test/apps/nextjs-app/package.json new file mode 100644 index 0000000000..59f2d45c66 --- /dev/null +++ b/test/apps/nextjs-app/package.json @@ -0,0 +1,41 @@ +{ + "name": "nextjs-app", + "private": true, + "scripts": { + "build": "webpack" + }, + "dependencies": { + "react": "19.2.4", + "react-dom": "19.2.4" + }, + "peerDependencies": { + "@datadog/browser-rum": "*", + "@datadog/browser-rum-react": "*" + }, + "peerDependenciesMeta": { + "@datadog/browser-rum": { + "optional": true + }, + "@datadog/browser-rum-react": { + "optional": true + } + }, + "resolutions": { + "@datadog/browser-rum-core": "file:../../../packages/rum-core/package.tgz", + "@datadog/browser-core": "file:../../../packages/core/package.tgz", + "@datadog/browser-rum": "file:../../../packages/rum/package.tgz", + "@datadog/browser-rum-react": "file:../../../packages/rum-react/package.tgz", + "@datadog/browser-rum-slim": "file:../../../packages/rum-slim/package.tgz", + "@datadog/browser-worker": "file:../../../packages/worker/package.tgz" + }, + "devDependencies": { + "@datadog/browser-rum": "6.28.0", + "@datadog/browser-rum-react": "6.28.0", + "ts-loader": "9.5.4", + "typescript": "5.9.3", + "webpack": "5.105.2" + }, + "volta": { + "extends": "../../../package.json" + } +} diff --git a/test/apps/nextjs-app/tsconfig.json b/test/apps/nextjs-app/tsconfig.json new file mode 100644 index 0000000000..5726320f91 --- /dev/null +++ b/test/apps/nextjs-app/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "strict": true, + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "jsx": "react", + "target": "es5", + "lib": ["ES2015", "DOM"], + "types": [] + } +} diff --git a/test/apps/nextjs-app/webpack.config.js b/test/apps/nextjs-app/webpack.config.js new file mode 100644 index 0000000000..a7e4a36db2 --- /dev/null +++ b/test/apps/nextjs-app/webpack.config.js @@ -0,0 +1,29 @@ +const path = require('node:path') + +module.exports = { + mode: 'production', + entry: './app.tsx', + target: ['web', 'es2018'], + module: { + rules: [ + { + test: /\.(ts|tsx)$/, + use: 'ts-loader', + }, + ], + }, + resolve: { + extensions: ['.ts', '.tsx', '.js', '.jsx'], + alias: { + 'next/navigation': path.resolve(__dirname, 'mockNextNavigation.tsx'), + }, + }, + optimization: { + chunkIds: 'named', + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'nextjs-app.js', + chunkFilename: 'chunks/[name]-[contenthash]-nextjs-app.js', + }, +} diff --git a/test/apps/nextjs-app/yarn.lock b/test/apps/nextjs-app/yarn.lock new file mode 100644 index 0000000000..521507828d --- /dev/null +++ b/test/apps/nextjs-app/yarn.lock @@ -0,0 +1,989 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@datadog/browser-core@file:../../../packages/core/package.tgz::locator=nextjs-app%40workspace%3A.": + version: 6.28.0 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=1921b8&locator=nextjs-app%40workspace%3A." + checksum: 10c0/890d4a6e9e5a5c1777387e5d899828c24fbfb884fd0cc65f383d315e863efcde10f5465734cbdc852f87eba78962a833007beb2b2fbee66d51988906c862c694 + languageName: node + linkType: hard + +"@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=nextjs-app%40workspace%3A.": + version: 6.28.0 + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=2af070&locator=nextjs-app%40workspace%3A." + dependencies: + "@datadog/browser-core": "npm:6.28.0" + checksum: 10c0/eca92247fbfd2ff3c4e9eed78cdab29a5c96a6fbfc20b0c3dd2d959417d0a574914302b41d952b54fed2429ce8ea6c4bbca39822df9648841e19f535d3383b26 + languageName: node + linkType: hard + +"@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz::locator=nextjs-app%40workspace%3A.": + version: 6.28.0 + resolution: "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz#../../../packages/rum-react/package.tgz::hash=04e94e&locator=nextjs-app%40workspace%3A." + dependencies: + "@datadog/browser-core": "npm:6.28.0" + "@datadog/browser-rum-core": "npm:6.28.0" + peerDependencies: + next: ">=13" + react: 18 || 19 + react-router: 6 || 7 + react-router-dom: 6 || 7 + peerDependenciesMeta: + "@datadog/browser-rum": + optional: true + "@datadog/browser-rum-slim": + optional: true + next: + optional: true + react: + optional: true + react-router: + optional: true + react-router-dom: + optional: true + checksum: 10c0/cafaf1121108394cb06087ec8ecd74ba636f61326e044ab382afafe93c3d014d0dae7064bea8293b2d0d89c5ac8c27888daf0ddff7451a8c39cde94206ea8b28 + languageName: node + linkType: hard + +"@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=nextjs-app%40workspace%3A.": + version: 6.28.0 + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=4c786a&locator=nextjs-app%40workspace%3A." + dependencies: + "@datadog/browser-core": "npm:6.28.0" + "@datadog/browser-rum-core": "npm:6.28.0" + peerDependencies: + "@datadog/browser-logs": 6.28.0 + peerDependenciesMeta: + "@datadog/browser-logs": + optional: true + checksum: 10c0/9c9435cbbb7a657b32c585fb086e66617824260e669cb9d37a56ab2965b1455cf4228f5ec249d962c0ec69c45f93cc710f054c6adf4ffc2a6bdcec81fc644671 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/source-map@npm:^0.3.3": + version: 0.3.11 + resolution: "@jridgewell/source-map@npm:0.3.11" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + checksum: 10c0/50a4fdafe0b8f655cb2877e59fe81320272eaa4ccdbe6b9b87f10614b2220399ae3e05c16137a59db1f189523b42c7f88bd097ee991dbd7bc0e01113c583e844 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.5 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" + checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + +"@types/eslint-scope@npm:^3.7.7": + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" + dependencies: + "@types/eslint": "npm:*" + "@types/estree": "npm:*" + checksum: 10c0/a0ecbdf2f03912679440550817ff77ef39a30fa8bfdacaf6372b88b1f931828aec392f52283240f0d648cf3055c5ddc564544a626bcf245f3d09fcb099ebe3cc + languageName: node + linkType: hard + +"@types/eslint@npm:*": + version: 9.6.1 + resolution: "@types/eslint@npm:9.6.1" + dependencies: + "@types/estree": "npm:*" + "@types/json-schema": "npm:*" + checksum: 10c0/69ba24fee600d1e4c5abe0df086c1a4d798abf13792d8cfab912d76817fe1a894359a1518557d21237fbaf6eda93c5ab9309143dee4c59ef54336d1b3570420e + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.8": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 25.3.0 + resolution: "@types/node@npm:25.3.0" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/7b2b18c9d68047157367fc2f786d4f166d22dc0ad9f82331ca02fb16f2f391854123dbe604dcb938cda119c87051e4bb71dcb9ece44a579f483a6f96d4bd41de + languageName: node + linkType: hard + +"@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/ast@npm:1.14.1" + dependencies: + "@webassemblyjs/helper-numbers": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + checksum: 10c0/67a59be8ed50ddd33fbb2e09daa5193ac215bf7f40a9371be9a0d9797a114d0d1196316d2f3943efdb923a3d809175e1563a3cb80c814fb8edccd1e77494972b + languageName: node + linkType: hard + +"@webassemblyjs/floating-point-hex-parser@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.13.2" + checksum: 10c0/0e88bdb8b50507d9938be64df0867f00396b55eba9df7d3546eb5dc0ca64d62e06f8d881ec4a6153f2127d0f4c11d102b6e7d17aec2f26bb5ff95a5e60652412 + languageName: node + linkType: hard + +"@webassemblyjs/helper-api-error@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-api-error@npm:1.13.2" + checksum: 10c0/31be497f996ed30aae4c08cac3cce50c8dcd5b29660383c0155fce1753804fc55d47fcba74e10141c7dd2899033164e117b3bcfcda23a6b043e4ded4f1003dfb + languageName: node + linkType: hard + +"@webassemblyjs/helper-buffer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-buffer@npm:1.14.1" + checksum: 10c0/0d54105dc373c0fe6287f1091e41e3a02e36cdc05e8cf8533cdc16c59ff05a646355415893449d3768cda588af451c274f13263300a251dc11a575bc4c9bd210 + languageName: node + linkType: hard + +"@webassemblyjs/helper-numbers@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-numbers@npm:1.13.2" + dependencies: + "@webassemblyjs/floating-point-hex-parser": "npm:1.13.2" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/9c46852f31b234a8fb5a5a9d3f027bc542392a0d4de32f1a9c0075d5e8684aa073cb5929b56df565500b3f9cc0a2ab983b650314295b9bf208d1a1651bfc825a + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-bytecode@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.13.2" + checksum: 10c0/c4355d14f369b30cf3cbdd3acfafc7d0488e086be6d578e3c9780bd1b512932352246be96e034e2a7fcfba4f540ec813352f312bfcbbfe5bcfbf694f82ccc682 + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-section@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-wasm-section@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + checksum: 10c0/1f9b33731c3c6dbac3a9c483269562fa00d1b6a4e7133217f40e83e975e636fd0f8736e53abd9a47b06b66082ecc976c7384391ab0a68e12d509ea4e4b948d64 + languageName: node + linkType: hard + +"@webassemblyjs/ieee754@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/ieee754@npm:1.13.2" + dependencies: + "@xtuc/ieee754": "npm:^1.2.0" + checksum: 10c0/2e732ca78c6fbae3c9b112f4915d85caecdab285c0b337954b180460290ccd0fb00d2b1dc4bb69df3504abead5191e0d28d0d17dfd6c9d2f30acac8c4961c8a7 + languageName: node + linkType: hard + +"@webassemblyjs/leb128@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/leb128@npm:1.13.2" + dependencies: + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/dad5ef9e383c8ab523ce432dfd80098384bf01c45f70eb179d594f85ce5db2f80fa8c9cba03adafd85684e6d6310f0d3969a882538975989919329ac4c984659 + languageName: node + linkType: hard + +"@webassemblyjs/utf8@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/utf8@npm:1.13.2" + checksum: 10c0/d3fac9130b0e3e5a1a7f2886124a278e9323827c87a2b971e6d0da22a2ba1278ac9f66a4f2e363ecd9fac8da42e6941b22df061a119e5c0335f81006de9ee799 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-edit@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-edit@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/helper-wasm-section": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-opt": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + "@webassemblyjs/wast-printer": "npm:1.14.1" + checksum: 10c0/5ac4781086a2ca4b320bdbfd965a209655fe8a208ca38d89197148f8597e587c9a2c94fb6bd6f1a7dbd4527c49c6844fcdc2af981f8d793a97bf63a016aa86d2 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-gen@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-gen@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/d678810d7f3f8fecb2e2bdadfb9afad2ec1d2bc79f59e4711ab49c81cec578371e22732d4966f59067abe5fba8e9c54923b57060a729d28d408e608beef67b10 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-opt@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-opt@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + checksum: 10c0/515bfb15277ee99ba6b11d2232ddbf22aed32aad6d0956fe8a0a0a004a1b5a3a277a71d9a3a38365d0538ac40d1b7b7243b1a244ad6cd6dece1c1bb2eb5de7ee + languageName: node + linkType: hard + +"@webassemblyjs/wasm-parser@npm:1.14.1, @webassemblyjs/wasm-parser@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-parser@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/95427b9e5addbd0f647939bd28e3e06b8deefdbdadcf892385b5edc70091bf9b92fa5faac3fce8333554437c5d85835afef8c8a7d9d27ab6ba01ffab954db8c6 + languageName: node + linkType: hard + +"@webassemblyjs/wast-printer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wast-printer@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/8d7768608996a052545251e896eac079c98e0401842af8dd4de78fba8d90bd505efb6c537e909cd6dae96e09db3fa2e765a6f26492553a675da56e2db51f9d24 + languageName: node + linkType: hard + +"@xtuc/ieee754@npm:^1.2.0": + version: 1.2.0 + resolution: "@xtuc/ieee754@npm:1.2.0" + checksum: 10c0/a8565d29d135039bd99ae4b2220d3e167d22cf53f867e491ed479b3f84f895742d0097f935b19aab90265a23d5d46711e4204f14c479ae3637fbf06c4666882f + languageName: node + linkType: hard + +"@xtuc/long@npm:4.2.2": + version: 4.2.2 + resolution: "@xtuc/long@npm:4.2.2" + checksum: 10c0/8582cbc69c79ad2d31568c412129bf23d2b1210a1dfb60c82d5a1df93334da4ee51f3057051658569e2c196d8dc33bc05ae6b974a711d0d16e801e1d0647ccd1 + languageName: node + linkType: hard + +"acorn-import-phases@npm:^1.0.3": + version: 1.0.4 + resolution: "acorn-import-phases@npm:1.0.4" + peerDependencies: + acorn: ^8.14.0 + checksum: 10c0/338eb46fc1aed5544f628344cb9af189450b401d152ceadbf1f5746901a5d923016cd0e7740d5606062d374fdf6941c29bb515d2bd133c4f4242d5d4cd73a3c7 + languageName: node + linkType: hard + +"acorn@npm:^8.15.0": + version: 8.16.0 + resolution: "acorn@npm:8.16.0" + bin: + acorn: bin/acorn + checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e + languageName: node + linkType: hard + +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/e43ba22e91b6a48d96224b83d260d3a3a561b42d391f8d3c6d2c1559f9aa5b253bfb306bc94bbeca1d967c014e15a6efe9a207309e95b3eaae07fcbcdc2af662 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.1.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + peerDependencies: + ajv: ^8.8.2 + checksum: 10c0/18bec51f0171b83123ba1d8883c126e60c6f420cef885250898bf77a8d3e65e3bfb9e8564f497e30bdbe762a83e0d144a36931328616a973ee669dc74d4a9590 + languageName: node + linkType: hard + +"ajv@npm:^8.0.0, ajv@npm:^8.9.0": + version: 8.18.0 + resolution: "ajv@npm:8.18.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/e7517c426173513a07391be951879932bdf3348feaebd2199f5b901c20f99d60db8cd1591502d4d551dc82f594e82a05c4fe1c70139b15b8937f7afeaed9532f + languageName: node + linkType: hard + +"ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + languageName: node + linkType: hard + +"baseline-browser-mapping@npm:^2.9.0": + version: 2.10.0 + resolution: "baseline-browser-mapping@npm:2.10.0" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/da9c3ec0fcd7f325226a47d2142794d41706b6e0a405718a2c15410bbdb72aacadd65738bedef558c6f1b106ed19458cb25b06f63b66df2c284799905dbbd003 + languageName: node + linkType: hard + +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 + languageName: node + linkType: hard + +"browserslist@npm:^4.28.1": + version: 4.28.1 + resolution: "browserslist@npm:4.28.1" + dependencies: + baseline-browser-mapping: "npm:^2.9.0" + caniuse-lite: "npm:^1.0.30001759" + electron-to-chromium: "npm:^1.5.263" + node-releases: "npm:^2.0.27" + update-browserslist-db: "npm:^1.2.0" + bin: + browserslist: cli.js + checksum: 10c0/545a5fa9d7234e3777a7177ec1e9134bb2ba60a69e6b95683f6982b1473aad347c77c1264ccf2ac5dea609a9731fbfbda6b85782bdca70f80f86e28a402504bd + languageName: node + linkType: hard + +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001759": + version: 1.0.30001774 + resolution: "caniuse-lite@npm:1.0.30001774" + checksum: 10c0/cc6a340a5421b9a67d8fa80889065ee27b2839ad62993571dded5296e18f02bbf685ce7094e93fe908cddc9fefdfad35d6c010b724cc3d22a6479b0d0b679f8c + languageName: node + linkType: hard + +"chalk@npm:^4.1.0": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + languageName: node + linkType: hard + +"chrome-trace-event@npm:^1.0.2": + version: 1.0.4 + resolution: "chrome-trace-event@npm:1.0.4" + checksum: 10c0/3058da7a5f4934b87cf6a90ef5fb68ebc5f7d06f143ed5a4650208e5d7acae47bc03ec844b29fbf5ba7e46e8daa6acecc878f7983a4f4bb7271593da91e61ff5 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"commander@npm:^2.20.0": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.263": + version: 1.5.302 + resolution: "electron-to-chromium@npm:1.5.302" + checksum: 10c0/014413f2b4ec3a0e043c68f6c07a760d230b14e36b8549c5b124f386a6318d9641e69be2aa0df1877395dd99922745c1722c8ecb3d72205f0f3b3b3dc44c8442 + languageName: node + linkType: hard + +"enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.19.0": + version: 5.19.0 + resolution: "enhanced-resolve@npm:5.19.0" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.3.0" + checksum: 10c0/966b1dffb82d5f6a4d6a86e904e812104a999066aa29f9223040aaa751e7c453b462a3f5ef91f8bd4408131ff6f7f90651dd1c804bdcb7944e2099a9c2e45ee2 + languageName: node + linkType: hard + +"es-module-lexer@npm:^2.0.0": + version: 2.0.0 + resolution: "es-module-lexer@npm:2.0.0" + checksum: 10c0/ae78dbbd43035a4b972c46cfb6877e374ea290adfc62bc2f5a083fea242c0b2baaab25c5886af86be55f092f4a326741cb94334cd3c478c383fdc8a9ec5ff817 + languageName: node + linkType: hard + +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d + languageName: node + linkType: hard + +"estraverse@npm:^5.2.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 + languageName: node + linkType: hard + +"events@npm:^3.2.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + languageName: node + linkType: hard + +"fast-uri@npm:^3.0.1": + version: 3.1.0 + resolution: "fast-uri@npm:3.1.0" + checksum: 10c0/44364adca566f70f40d1e9b772c923138d47efeac2ae9732a872baafd77061f26b097ba2f68f0892885ad177becd065520412b8ffeec34b16c99433c5b9e2de7 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 + languageName: node + linkType: hard + +"glob-to-regexp@npm:^0.4.1": + version: 0.4.1 + resolution: "glob-to-regexp@npm:0.4.1" + checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 + languageName: node + linkType: hard + +"jest-worker@npm:^27.4.5": + version: 27.5.1 + resolution: "jest-worker@npm:27.5.1" + dependencies: + "@types/node": "npm:*" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.0.0" + checksum: 10c0/8c4737ffd03887b3c6768e4cc3ca0269c0336c1e4b1b120943958ddb035ed2a0fc6acab6dc99631720a3720af4e708ff84fb45382ad1e83c27946adf3623969b + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.1": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 + languageName: node + linkType: hard + +"loader-runner@npm:^4.3.1": + version: 4.3.1 + resolution: "loader-runner@npm:4.3.1" + checksum: 10c0/a523b6329f114e0a98317158e30a7dfce044b731521be5399464010472a93a15ece44757d1eaed1d8845019869c5390218bc1c7c3110f4eeaef5157394486eac + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.0": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-types@npm:^2.1.27": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + +"neo-async@npm:^2.6.2": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d + languageName: node + linkType: hard + +"nextjs-app@workspace:.": + version: 0.0.0-use.local + resolution: "nextjs-app@workspace:." + dependencies: + "@datadog/browser-rum": "npm:6.28.0" + "@datadog/browser-rum-react": "npm:6.28.0" + react: "npm:19.2.4" + react-dom: "npm:19.2.4" + ts-loader: "npm:9.5.4" + typescript: "npm:5.9.3" + webpack: "npm:5.105.2" + peerDependencies: + "@datadog/browser-rum": "*" + "@datadog/browser-rum-react": "*" + peerDependenciesMeta: + "@datadog/browser-rum": + optional: true + "@datadog/browser-rum-react": + optional: true + languageName: unknown + linkType: soft + +"node-releases@npm:^2.0.27": + version: 2.0.27 + resolution: "node-releases@npm:2.0.27" + checksum: 10c0/f1e6583b7833ea81880627748d28a3a7ff5703d5409328c216ae57befbced10ce2c991bea86434e8ec39003bd017f70481e2e5f8c1f7e0a7663241f81d6e00e2 + languageName: node + linkType: hard + +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + languageName: node + linkType: hard + +"randombytes@npm:^2.1.0": + version: 2.1.0 + resolution: "randombytes@npm:2.1.0" + dependencies: + safe-buffer: "npm:^5.1.0" + checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 + languageName: node + linkType: hard + +"react-dom@npm:19.2.4": + version: 19.2.4 + resolution: "react-dom@npm:19.2.4" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.4 + checksum: 10c0/f0c63f1794dedb154136d4d0f59af00b41907f4859571c155940296808f4b94bf9c0c20633db75b5b2112ec13d8d7dd4f9bf57362ed48782f317b11d05a44f35 + languageName: node + linkType: hard + +"react@npm:19.2.4": + version: 19.2.4 + resolution: "react@npm:19.2.4" + checksum: 10c0/cd2c9ff67a720799cc3b38a516009986f7fc4cb8d3e15716c6211cf098d1357ee3e348ab05ad0600042bbb0fd888530ba92e329198c92eafa0994f5213396596 + languageName: node + linkType: hard + +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 + languageName: node + linkType: hard + +"safe-buffer@npm:^5.1.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 + languageName: node + linkType: hard + +"schema-utils@npm:^4.3.0, schema-utils@npm:^4.3.3": + version: 4.3.3 + resolution: "schema-utils@npm:4.3.3" + dependencies: + "@types/json-schema": "npm:^7.0.9" + ajv: "npm:^8.9.0" + ajv-formats: "npm:^2.1.1" + ajv-keywords: "npm:^5.1.0" + checksum: 10c0/1c8d2c480a026d7c02ab2ecbe5919133a096d6a721a3f201fa50663e4f30f6d6ba020dfddd93cb828b66b922e76b342e103edd19a62c95c8f60e9079cc403202 + languageName: node + linkType: hard + +"semver@npm:^7.3.4": + version: 7.7.4 + resolution: "semver@npm:7.7.4" + bin: + semver: bin/semver.js + checksum: 10c0/5215ad0234e2845d4ea5bb9d836d42b03499546ddafb12075566899fc617f68794bb6f146076b6881d755de17d6c6cc73372555879ec7dce2c2feee947866ad2 + languageName: node + linkType: hard + +"serialize-javascript@npm:^6.0.2": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" + dependencies: + randombytes: "npm:^2.1.0" + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 + languageName: node + linkType: hard + +"source-map-support@npm:~0.5.20": + version: 0.5.21 + resolution: "source-map-support@npm:0.5.21" + dependencies: + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d + languageName: node + linkType: hard + +"source-map@npm:^0.6.0": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 + languageName: node + linkType: hard + +"source-map@npm:^0.7.4": + version: 0.7.6 + resolution: "source-map@npm:0.7.6" + checksum: 10c0/59f6f05538539b274ba771d2e9e32f6c65451982510564438e048bc1352f019c6efcdc6dd07909b1968144941c14015c2c7d4369fb7c4d7d53ae769716dcc16c + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + languageName: node + linkType: hard + +"supports-color@npm:^8.0.0": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 + languageName: node + linkType: hard + +"tapable@npm:^2.3.0": + version: 2.3.0 + resolution: "tapable@npm:2.3.0" + checksum: 10c0/cb9d67cc2c6a74dedc812ef3085d9d681edd2c1fa18e4aef57a3c0605fdbe44e6b8ea00bd9ef21bc74dd45314e39d31227aa031ebf2f5e38164df514136f2681 + languageName: node + linkType: hard + +"terser-webpack-plugin@npm:^5.3.16": + version: 5.3.16 + resolution: "terser-webpack-plugin@npm:5.3.16" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.25" + jest-worker: "npm:^27.4.5" + schema-utils: "npm:^4.3.0" + serialize-javascript: "npm:^6.0.2" + terser: "npm:^5.31.1" + peerDependencies: + webpack: ^5.1.0 + peerDependenciesMeta: + "@swc/core": + optional: true + esbuild: + optional: true + uglify-js: + optional: true + checksum: 10c0/39e37c5b3015c1a5354a3633f77235677bfa06eac2608ce26d258b1d1a74070a99910319a6f2f2c437eb61dc321f66434febe01d78e73fa96b4d4393b813f4cf + languageName: node + linkType: hard + +"terser@npm:^5.31.1": + version: 5.46.0 + resolution: "terser@npm:5.46.0" + dependencies: + "@jridgewell/source-map": "npm:^0.3.3" + acorn: "npm:^8.15.0" + commander: "npm:^2.20.0" + source-map-support: "npm:~0.5.20" + bin: + terser: bin/terser + checksum: 10c0/93ad468f13187c4f66b609bbfc00a6aee752007779ca3157f2c1ee063697815748d6010fd449a16c30be33213748431d5f54cc0224ba6a3fbbf5acd3582a4356 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + languageName: node + linkType: hard + +"ts-loader@npm:9.5.4": + version: 9.5.4 + resolution: "ts-loader@npm:9.5.4" + dependencies: + chalk: "npm:^4.1.0" + enhanced-resolve: "npm:^5.0.0" + micromatch: "npm:^4.0.0" + semver: "npm:^7.3.4" + source-map: "npm:^0.7.4" + peerDependencies: + typescript: "*" + webpack: ^5.0.0 + checksum: 10c0/f0982404b43628c335d3b3a60ac3f1738385da7b97c3f04cb5ad2ebad791597be39b25c8a4e158a66173f9bd9f5aa72e285b046b0573e4beed8ecd032d418e4d + languageName: node + linkType: hard + +"typescript@npm:5.9.3": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A5.9.3#optional!builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 + languageName: node + linkType: hard + +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.2.0": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec + languageName: node + linkType: hard + +"watchpack@npm:^2.5.1": + version: 2.5.1 + resolution: "watchpack@npm:2.5.1" + dependencies: + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.1.2" + checksum: 10c0/dffbb483d1f61be90dc570630a1eb308581e2227d507d783b1d94a57ac7b705ecd9a1a4b73d73c15eab596d39874e5276a3d9cb88bbb698bafc3f8d08c34cf17 + languageName: node + linkType: hard + +"webpack-sources@npm:^3.3.3": + version: 3.3.4 + resolution: "webpack-sources@npm:3.3.4" + checksum: 10c0/94a42508531338eb41939cf1d48a4a8a6db97f3a47e5453cff2133a68d3169ca779d4bcbe9dfed072ce16611959eba1e16f085bc2dc56714e1a1c1783fd661a3 + languageName: node + linkType: hard + +"webpack@npm:5.105.2": + version: 5.105.2 + resolution: "webpack@npm:5.105.2" + dependencies: + "@types/eslint-scope": "npm:^3.7.7" + "@types/estree": "npm:^1.0.8" + "@types/json-schema": "npm:^7.0.15" + "@webassemblyjs/ast": "npm:^1.14.1" + "@webassemblyjs/wasm-edit": "npm:^1.14.1" + "@webassemblyjs/wasm-parser": "npm:^1.14.1" + acorn: "npm:^8.15.0" + acorn-import-phases: "npm:^1.0.3" + browserslist: "npm:^4.28.1" + chrome-trace-event: "npm:^1.0.2" + enhanced-resolve: "npm:^5.19.0" + es-module-lexer: "npm:^2.0.0" + eslint-scope: "npm:5.1.1" + events: "npm:^3.2.0" + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.2.11" + json-parse-even-better-errors: "npm:^2.3.1" + loader-runner: "npm:^4.3.1" + mime-types: "npm:^2.1.27" + neo-async: "npm:^2.6.2" + schema-utils: "npm:^4.3.3" + tapable: "npm:^2.3.0" + terser-webpack-plugin: "npm:^5.3.16" + watchpack: "npm:^2.5.1" + webpack-sources: "npm:^3.3.3" + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: 10c0/565df8072c00d72e0a22e136971862b7eac7beb8b8d39a2ae4ab00838941ea58acc5b49dd7ea268e3d839810756cb86ba5c272b3a25904f6db7807cfa8ed0b29 + languageName: node + linkType: hard diff --git a/test/e2e/lib/framework/sdkBuilds.ts b/test/e2e/lib/framework/sdkBuilds.ts index 98358ad7c0..dd191c5585 100644 --- a/test/e2e/lib/framework/sdkBuilds.ts +++ b/test/e2e/lib/framework/sdkBuilds.ts @@ -11,6 +11,7 @@ export function getTestAppBundlePath(appName: string, originalUrl: string) { app: 'apps/vanilla', 'react-router-v6-app': 'apps/react-router-v6-app', 'react-router-v7-app': 'apps/react-router-v7-app', + 'nextjs-app': 'apps/nextjs-app', } const targetAppPath = appNameMapping[appName] || appName diff --git a/test/e2e/lib/framework/serverApps/mock.ts b/test/e2e/lib/framework/serverApps/mock.ts index 4a41f71deb..60bff9b2d4 100644 --- a/test/e2e/lib/framework/serverApps/mock.ts +++ b/test/e2e/lib/framework/serverApps/mock.ts @@ -196,7 +196,7 @@ export function createMockServerApp( } }) - app.get(/(?app|react-[\w-]+).js$/, (req, res) => { + app.get(/(?app|react-[\w-]+|nextjs-[\w-]+).js$/, (req, res) => { const { originalUrl, params } = req res.sendFile(getTestAppBundlePath(params.appName, originalUrl)) }) diff --git a/test/e2e/scenario/reactPlugin.scenario.ts b/test/e2e/scenario/reactPlugin.scenario.ts index ef72129ff2..5afd5383a8 100644 --- a/test/e2e/scenario/reactPlugin.scenario.ts +++ b/test/e2e/scenario/reactPlugin.scenario.ts @@ -6,6 +6,8 @@ const reactApps = [ { appName: 'react-router-v7-app', description: 'React Router v7' }, ] +const nextApps = [{ appName: 'nextjs-app', description: 'Next.js App Router' }] + test.describe('react plugin', () => { for (const { appName, description } of reactApps) { test.describe(`with ${description}`, () => { @@ -61,4 +63,59 @@ test.describe('react plugin', () => { }) }) } + + for (const { appName, description } of nextApps) { + test.describe(`with ${description}`, () => { + createTest('should define a view name with DatadogRumProvider') + .withRum() + .withReactApp(appName) + .run(async ({ page, flushEvents, intakeRegistry }) => { + await page.click('text=Go to User') + await flushEvents() + const viewEvents = intakeRegistry.rumViewEvents + expect(viewEvents.length).toBeGreaterThan(0) + const lastView = viewEvents[viewEvents.length - 1] + expect(lastView.view.name).toBe('/user/:id') + }) + + createTest('should send a react component render vital event') + .withRum() + .withReactApp(appName) + .run(async ({ flushEvents, intakeRegistry, page }) => { + await page.click('text=Go to Tracked') + + await flushEvents() + const vitalEvents = intakeRegistry.rumVitalEvents[0] + expect(vitalEvents.vital.description).toBe('TrackedPage') + expect(vitalEvents.vital.duration).toEqual(expect.any(Number)) + }) + + createTest('should capture react error from error boundary') + .withRum() + .withReactApp(appName) + .run(async ({ page, flushEvents, intakeRegistry, browserName, withBrowserLogs }) => { + await page.click('text=Go to Error') + await page.click('#error-button') + + // Firefox may delay dispatching error events from React error boundaries, + // causing flushEvents() to miss them, this timeout ensures the RUM event is captured. + if (browserName === 'firefox') { + await page.waitForTimeout(1000) + } + + await flushEvents() + expect(intakeRegistry.rumErrorEvents.length).toBeGreaterThan(0) + const errorEvent = intakeRegistry.rumErrorEvents[1] + + expect(errorEvent.error.message).toBe('Error triggered by button click') + expect(errorEvent.error.source).toBe('custom') + expect(errorEvent.error.stack).toBeDefined() + expect(errorEvent.context?.framework).toBe('react') + expect(errorEvent.error.component_stack).toBeDefined() + withBrowserLogs((browserLogs) => { + expect(browserLogs.length).toBeGreaterThan(0) + }) + }) + }) + } }) diff --git a/tsconfig.base.json b/tsconfig.base.json index c40d33dd99..41fcd3c508 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -34,6 +34,7 @@ "@datadog/browser-rum-react": ["./packages/rum-react/src/entries/main"], "@datadog/browser-rum-react/react-router-v6": ["./packages/rum-react/src/entries/reactRouterV6"], "@datadog/browser-rum-react/react-router-v7": ["./packages/rum-react/src/entries/reactRouterV7"], + "@datadog/browser-rum-react/nextjs": ["./packages/rum-react/src/entries/nextjs"], "@datadog/browser-worker": ["./packages/worker/src/entries/main"] } diff --git a/yarn.lock b/yarn.lock index a37dc34e26..413dc0a9b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -330,12 +330,14 @@ __metadata: "@datadog/browser-rum-core": "npm:6.28.0" "@types/react": "npm:19.2.14" "@types/react-dom": "npm:19.2.3" + next: "npm:15.2.2" react: "npm:19.2.4" react-dom: "npm:19.2.4" react-router: "npm:7.13.0" react-router-dom: "npm:7.13.0" react-router-dom-6: "npm:react-router-dom@6.30.3" peerDependencies: + next: ">=13" react: 18 || 19 react-router: 6 || 7 react-router-dom: 6 || 7 @@ -344,6 +346,8 @@ __metadata: optional: true "@datadog/browser-rum-slim": optional: true + next: + optional: true react: optional: true react-router: @@ -462,7 +466,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.1.0, @emnapi/runtime@npm:^1.4.3": +"@emnapi/runtime@npm:^1.1.0, @emnapi/runtime@npm:^1.2.0, @emnapi/runtime@npm:^1.4.3": version: 1.8.1 resolution: "@emnapi/runtime@npm:1.8.1" dependencies: @@ -873,6 +877,181 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": "npm:^1.2.0" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@inquirer/ansi@npm:^1.0.0, @inquirer/ansi@npm:^1.0.2": version: 1.0.2 resolution: "@inquirer/ansi@npm:1.0.2" @@ -1634,6 +1813,69 @@ __metadata: languageName: node linkType: hard +"@next/env@npm:15.2.2": + version: 15.2.2 + resolution: "@next/env@npm:15.2.2" + checksum: 10c0/a5188353cbbb955f4c87b1d04f8d9419af3f05086b5bf640f456d3e0cd810f17811ca0a29a0b5e492d96ce636eeedc6e306f7dd191c82ff8076c00123481709c + languageName: node + linkType: hard + +"@next/swc-darwin-arm64@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-darwin-arm64@npm:15.2.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@next/swc-darwin-x64@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-darwin-x64@npm:15.2.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@next/swc-linux-arm64-gnu@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-linux-arm64-gnu@npm:15.2.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@next/swc-linux-arm64-musl@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-linux-arm64-musl@npm:15.2.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@next/swc-linux-x64-gnu@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-linux-x64-gnu@npm:15.2.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@next/swc-linux-x64-musl@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-linux-x64-musl@npm:15.2.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@next/swc-win32-arm64-msvc@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-win32-arm64-msvc@npm:15.2.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@next/swc-win32-x64-msvc@npm:15.2.2": + version: 15.2.2 + resolution: "@next/swc-win32-x64-msvc@npm:15.2.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -2639,13 +2881,22 @@ __metadata: languageName: node linkType: hard -"@swc/counter@npm:^0.1.3": +"@swc/counter@npm:0.1.3, @swc/counter@npm:^0.1.3": version: 0.1.3 resolution: "@swc/counter@npm:0.1.3" checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 languageName: node linkType: hard +"@swc/helpers@npm:0.5.15": + version: 0.5.15 + resolution: "@swc/helpers@npm:0.5.15" + dependencies: + tslib: "npm:^2.8.0" + checksum: 10c0/33002f74f6f885f04c132960835fdfc474186983ea567606db62e86acd0680ca82f34647e8e610f4e1e422d1c16fce729dde22cd3b797ab1fd9061a825dabca4 + languageName: node + linkType: hard + "@swc/types@npm:^0.1.25": version: 0.1.25 resolution: "@swc/types@npm:0.1.25" @@ -4568,7 +4819,7 @@ __metadata: languageName: node linkType: hard -"busboy@npm:^1.0.0": +"busboy@npm:1.6.0, busboy@npm:^1.0.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" dependencies: @@ -4716,6 +4967,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001774 + resolution: "caniuse-lite@npm:1.0.30001774" + checksum: 10c0/cc6a340a5421b9a67d8fa80889065ee27b2839ad62993571dded5296e18f02bbf685ce7094e93fe908cddc9fefdfad35d6c010b724cc3d22a6479b0d0b679f8c + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001759": version: 1.0.30001768 resolution: "caniuse-lite@npm:1.0.30001768" @@ -4960,6 +5218,13 @@ __metadata: languageName: node linkType: hard +"client-only@npm:0.0.1": + version: 0.0.1 + resolution: "client-only@npm:0.0.1" + checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 + languageName: node + linkType: hard + "cliui@npm:^7.0.2": version: 7.0.4 resolution: "cliui@npm:7.0.4" @@ -5030,13 +5295,23 @@ __metadata: languageName: node linkType: hard -"color-name@npm:~1.1.4": +"color-name@npm:^1.0.0, color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: "npm:^1.0.0" + simple-swizzle: "npm:^0.2.2" + checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404 + languageName: node + linkType: hard + "color-support@npm:1.1.3": version: 1.1.3 resolution: "color-support@npm:1.1.3" @@ -5046,6 +5321,16 @@ __metadata: languageName: node linkType: hard +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: "npm:^2.0.1" + color-string: "npm:^1.9.0" + checksum: 10c0/7fbe7cfb811054c808349de19fb380252e5e34e61d7d168ec3353e9e9aacb1802674bddc657682e4e9730c2786592a4de6f8283e7e0d3870b829bb0b7b2f6118 + languageName: node + linkType: hard + "colorette@npm:^2.0.10, colorette@npm:^2.0.14, colorette@npm:^2.0.20": version: 2.0.20 resolution: "colorette@npm:2.0.20" @@ -5790,6 +6075,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.3": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 + languageName: node + linkType: hard + "detect-node-es@npm:^1.1.0": version: 1.1.0 resolution: "detect-node-es@npm:1.1.0" @@ -8435,6 +8727,13 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.3.1": + version: 0.3.4 + resolution: "is-arrayish@npm:0.3.4" + checksum: 10c0/1fa672a2f0bedb74154440310f616c0b6e53a95cf0625522ae050f06626d1cabd1a3d8085c882dc45c61ad0e7df2529aff122810b3b4a552880bf170d6df94e0 + languageName: node + linkType: hard + "is-async-function@npm:^2.0.0": version: 2.1.1 resolution: "is-async-function@npm:2.1.1" @@ -10573,7 +10872,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11": +"nanoid@npm:^3.3.11, nanoid@npm:^3.3.6": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -10626,6 +10925,67 @@ __metadata: languageName: node linkType: hard +"next@npm:15.2.2": + version: 15.2.2 + resolution: "next@npm:15.2.2" + dependencies: + "@next/env": "npm:15.2.2" + "@next/swc-darwin-arm64": "npm:15.2.2" + "@next/swc-darwin-x64": "npm:15.2.2" + "@next/swc-linux-arm64-gnu": "npm:15.2.2" + "@next/swc-linux-arm64-musl": "npm:15.2.2" + "@next/swc-linux-x64-gnu": "npm:15.2.2" + "@next/swc-linux-x64-musl": "npm:15.2.2" + "@next/swc-win32-arm64-msvc": "npm:15.2.2" + "@next/swc-win32-x64-msvc": "npm:15.2.2" + "@swc/counter": "npm:0.1.3" + "@swc/helpers": "npm:0.5.15" + busboy: "npm:1.6.0" + caniuse-lite: "npm:^1.0.30001579" + postcss: "npm:8.4.31" + sharp: "npm:^0.33.5" + styled-jsx: "npm:5.1.6" + peerDependencies: + "@opentelemetry/api": ^1.1.0 + "@playwright/test": ^1.41.2 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + dependenciesMeta: + "@next/swc-darwin-arm64": + optional: true + "@next/swc-darwin-x64": + optional: true + "@next/swc-linux-arm64-gnu": + optional: true + "@next/swc-linux-arm64-musl": + optional: true + "@next/swc-linux-x64-gnu": + optional: true + "@next/swc-linux-x64-musl": + optional: true + "@next/swc-win32-arm64-msvc": + optional: true + "@next/swc-win32-x64-msvc": + optional: true + sharp: + optional: true + peerDependenciesMeta: + "@opentelemetry/api": + optional: true + "@playwright/test": + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + bin: + next: dist/bin/next + checksum: 10c0/ed303ae014fa8236afa556d178fe426a81aa2baebff912dfbfbb9178a955cbc7d528d27608b66d6d9fb5b33a415ad550cdd984d9b6dbc2a6ff7f2d991b760029 + languageName: node + linkType: hard + "no-case@npm:^3.0.4": version: 3.0.4 resolution: "no-case@npm:3.0.4" @@ -11731,7 +12091,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 @@ -11906,6 +12266,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:8.4.31": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" + dependencies: + nanoid: "npm:^3.3.6" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.0.2" + checksum: 10c0/748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf + languageName: node + linkType: hard + "postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -13273,6 +13644,75 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.33.5": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.33.5" + "@img/sharp-darwin-x64": "npm:0.33.5" + "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" + "@img/sharp-libvips-darwin-x64": "npm:1.0.4" + "@img/sharp-libvips-linux-arm": "npm:1.0.5" + "@img/sharp-libvips-linux-arm64": "npm:1.0.4" + "@img/sharp-libvips-linux-s390x": "npm:1.0.4" + "@img/sharp-libvips-linux-x64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" + "@img/sharp-linux-arm": "npm:0.33.5" + "@img/sharp-linux-arm64": "npm:0.33.5" + "@img/sharp-linux-s390x": "npm:0.33.5" + "@img/sharp-linux-x64": "npm:0.33.5" + "@img/sharp-linuxmusl-arm64": "npm:0.33.5" + "@img/sharp-linuxmusl-x64": "npm:0.33.5" + "@img/sharp-wasm32": "npm:0.33.5" + "@img/sharp-win32-ia32": "npm:0.33.5" + "@img/sharp-win32-x64": "npm:0.33.5" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.3" + semver: "npm:^7.6.3" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -13379,6 +13819,15 @@ __metadata: languageName: node linkType: hard +"simple-swizzle@npm:^0.2.2": + version: 0.2.4 + resolution: "simple-swizzle@npm:0.2.4" + dependencies: + is-arrayish: "npm:^0.3.1" + checksum: 10c0/846c3fdd1325318d5c71295cfbb99bfc9edc4c8dffdda5e6e9efe30482bbcd32cf360fc2806f46ac43ff7d09bcfaff20337bb79f826f0e6a8e366efd3cdd7868 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -13484,7 +13933,7 @@ __metadata: languageName: node linkType: hard -"source-map-js@npm:^1.2.1": +"source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf @@ -13911,6 +14360,22 @@ __metadata: languageName: node linkType: hard +"styled-jsx@npm:5.1.6": + version: 5.1.6 + resolution: "styled-jsx@npm:5.1.6" + dependencies: + client-only: "npm:0.0.1" + peerDependencies: + react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + peerDependenciesMeta: + "@babel/core": + optional: true + babel-plugin-macros: + optional: true + checksum: 10c0/ace50e7ea5ae5ae6a3b65a50994c51fca6ae7df9c7ecfd0104c36be0b4b3a9c5c1a2374d16e2a11e256d0b20be6d47256d768ecb4f91ab390f60752a075780f5 + languageName: node + linkType: hard + "supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -14268,7 +14733,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0": +"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62