diff --git a/errors/next-prerender-crypto.mdx b/errors/next-prerender-crypto.mdx index 30ed3bcd43801..cf697f4272690 100644 --- a/errors/next-prerender-crypto.mdx +++ b/errors/next-prerender-crypto.mdx @@ -1,15 +1,17 @@ --- -title: Cannot access `crypto.getRandomValue()`, `crypto.randomUUID()`, or another web or node crypto API that generates random values synchronously in a Server Component +title: Cannot access `crypto.getRandomValue()`, `crypto.randomUUID()`, or another web or node crypto API that generates random values synchronously before other uncached data or Request data in a Server Component --- ## Why This Error Occurred -An API that produces a random value synchronously from the Web Crypto API or from Node's `crypto` API was called outside of a `"use cache"` scope and without first calling `await connection()`. Random values that are produced synchronously must either be inside a `"use cache"` scope or be preceded with `await connection()` to explicitly communicate to Next.js whether the random values produced can be reused across many requests (cached) or if they must be unique per Request (`await connection()`). - -If the API used has an async version you can also switch to that instead of using `await connection()`. +An API that produces a random value synchronously from the Web Crypto API or from Node's `crypto` package was used in a Server Component before accessing other uncached data through APIs like `fetch()` and native database drivers, or Request data through Next.js APIs like `cookies()`, `headers()`, `connection()` and `searchParams`. Accessing random values synchronously in this way interferes with the prerendering and prefetching capabilities of Next.js. ## Possible Ways to Fix It +If the random crypto value is appropriate to be prerendered and prefetched consider moving it into a Cache Component or Cache Function with the `"use cache"` directive. + +If the random crypto value is intended to be generated on every user request consider whether an async API exists that achieves the same result. If not consider whether you can move the random crypto value generation later, behind other existing uncached data or Request data access. If there is no way to do this you can always precede the random crypto value generation with Request data access by using `await connection()`. + ### Cache the token value If you are generating a token to talk to a database that itself should be cached move the token generation inside the `"use cache"`. diff --git a/errors/next-prerender-current-time.mdx b/errors/next-prerender-current-time.mdx index 23ab9314a9df3..def797693cae7 100644 --- a/errors/next-prerender-current-time.mdx +++ b/errors/next-prerender-current-time.mdx @@ -1,15 +1,21 @@ --- -title: Cannot infer intended usage of current time with `Date.now()`, `Date()`, or `new Date()` in a Server Component +title: Cannot access `Date.now()`, `Date()`, or `new Date()` before other uncached data or Request data in a Server Component --- ## Why This Error Occurred -Reading the current time in a Server Component can be ambiguous. Sometimes you intend to capture the time when something was cached, other times you intend to capture the time of a user Request. You might also be trying to measure runtime performance to track elapsed time. - -Depending on your use case you might use alternative time APIs like `performance.now()`, you might cache the time read with `"use cache"`, or you might communicate that the time must be evaluated on each request by guarding it with `await connection()` or moving it into a Client Component. +`Date.now()`, `Date()`, or `new Date()` was used in a Server Component before accessing other uncached data through APIs like `fetch()` and native database drivers, or Request data through built-in APIs like `cookies()`, `headers()`, `connection()` and `searchParams`. Accessing the current time in this way interferes with the prerendering and prefetching capabilities of Next.js. ## Possible Ways to Fix It +If the current time is being used for diagnostic purposes such as logging or performance tracking consider using `performance.now()` instead. + +If the current time is appropriate to be prerendered and prefetched consider moving it into a Cache Component or Cache Function with the `"use cache"` directive. + +If the current time is intended to be accessed dynamically on every user request first consider whether it is more appropriate to access it in a Client Component, which can often be the case when reading the time for display purposes. If a Client Component isn't the right choice then consider whether you can move the current time access later, behind other existing uncached data or Request data access. If there is no way to do this you can always precede the current time access with Request data access by using `await connection()`. + +> **Note**: Sometimes the place that accesses the current time is inside 3rd party code. While you can't easily convert the time access to `performance.now()` the other strategies can be applied in your own project code regardless of how deeply the time is read. + ### Performance use case If you are using the current time for performance tracking with elapsed time use `performance.now()`. @@ -40,6 +46,7 @@ export default async function Page() { ``` > **Note**: If you need report an absolute time to an observability tool you can also use `performance.timeOrigin + performance.now()`. +> **Note**: It is essential that the values provided by `performance.now()` do not influence the rendered output of your Component and should never be passed into Cache Functions as arguments or props. ### Cacheable use cases @@ -214,6 +221,8 @@ async function DynamicBanner() { } ``` +> **Note**: This example illustrates using `await connection()`, but you could alternatively move where a uncached fetch happens or read cookies before as well. + ## Useful Links - [`Date.now` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) diff --git a/errors/next-prerender-random.mdx b/errors/next-prerender-random.mdx index bfdf5f23212a0..2b158cffc97f6 100644 --- a/errors/next-prerender-random.mdx +++ b/errors/next-prerender-random.mdx @@ -1,13 +1,21 @@ --- -title: Cannot infer intended usage of `Math.random()` in a Server Component +title: Cannot access `Math.random()` before other uncached data or Request data in a Server Component --- ## Why This Error Occurred -A Server Component is calling `Math.random()` without specifying whether it should be cached or whether it should be evaluated on each user Request. If you want this random value to be included in the prerendered HTML for this page you must cache it using `"use cache"`. If you want this random value to be unique per Request you must precede it with `await connection()` so Next.js knows to exclude it from the prerendered HTML. +`Math.random()` was called in a Server Component before accessing other uncached data through APIs like `fetch()` and native database drivers, or Request data through built-in APIs like `cookies()`, `headers()`, `connection()` and `searchParams`. Accessing random values in this way interferes with the prerendering and prefetching capabilities of Next.js. ## Possible Ways to Fix It +If the random value is appropriate to be prerendered and prefetched consider moving it into a Cache Component or Cache Function with the `"use cache"` directive. + +If the random value is intended to be generated on every user request consider whether you can move the random value generation later, behind other existing uncached data or Request data access. If there is no way to do this you can always precede the random value generation with Request data access by using `await connection()`. + +If the random value is being used as a unique identifier for diagnostic purposes such as logging or tracking consider using an alternate method of id generation that does not rely on random number generation such as incrementing an integer. + +> **Note**: Sometimes the place that generates a random value synchronously is inside 3rd party code. While you can't easily replace the `Math.random()` call directly, the other strategies can be applied in your own project code regardless of how deep random generation is. + ### Cache the random value If your random value is cacheable, move the `Math.random()` call to a `"use cache"` function. For instance, imagine you have a product page and you want to randomize the product order periodically but you are fine with the random order being re-used for different users. diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 9cc0312427bcc..9885b95632cf5 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -138,7 +138,6 @@ import { consumeDynamicAccess, type DynamicAccess, logDisallowedDynamicError, - warnOnSyncDynamicError, } from './dynamic-rendering' import { getClientComponentLoaderMetrics, @@ -909,8 +908,6 @@ async function finalRuntimeServerPrerender( } ) - warnOnSyncDynamicError(serverDynamicTracking) - return { result, // TODO(runtime-ppr): do we need to produce a digest map here? diff --git a/packages/next/src/server/app-render/dynamic-rendering.ts b/packages/next/src/server/app-render/dynamic-rendering.ts index 54ab827733705..2c88cd8e0bfc1 100644 --- a/packages/next/src/server/app-render/dynamic-rendering.ts +++ b/packages/next/src/server/app-render/dynamic-rendering.ts @@ -341,21 +341,6 @@ export function abortAndThrowOnSynchronousRequestDataAccess( ) } -/** - * Use this function when dynamically prerendering with dynamicIO. - * We don't want to error, because it's better to return something - * (and we've already aborted the render at the point where the sync dynamic error occured), - * but we should log an error server-side. - * @internal - */ -export function warnOnSyncDynamicError(dynamicTracking: DynamicTrackingState) { - if (dynamicTracking.syncDynamicErrorWithStack) { - // the server did something sync dynamic, likely - // leading to an early termination of the prerender. - console.error(dynamicTracking.syncDynamicErrorWithStack) - } -} - // For now these implementations are the same so we just reexport export const trackSynchronousRequestDataAccessInDev = trackSynchronousPlatformIOAccessInDev @@ -778,6 +763,14 @@ export function throwIfDisallowedDynamic( dynamicValidation: DynamicValidationState, serverDynamic: DynamicTrackingState ): void { + if (serverDynamic.syncDynamicErrorWithStack) { + logDisallowedDynamicError( + workStore, + serverDynamic.syncDynamicErrorWithStack + ) + throw new StaticGenBailoutError() + } + if (prelude !== PreludeState.Full) { if (dynamicValidation.hasSuspenseAboveBody) { // This route has opted into allowing fully dynamic rendering @@ -786,17 +779,6 @@ export function throwIfDisallowedDynamic( return } - if (serverDynamic.syncDynamicErrorWithStack) { - // There is no shell and the server did something sync dynamic likely - // leading to an early termination of the prerender before the shell - // could be completed. We terminate the build/validating render. - logDisallowedDynamicError( - workStore, - serverDynamic.syncDynamicErrorWithStack - ) - throw new StaticGenBailoutError() - } - // We didn't have any sync bailouts but there may be user code which // blocked the root. We would have captured these during the prerender // and can log them here and then terminate the build/validating render diff --git a/packages/next/src/server/node-environment-extensions/utils.tsx b/packages/next/src/server/node-environment-extensions/utils.tsx index 9e147e1a344e3..f630ad1cc9866 100644 --- a/packages/next/src/server/node-environment-extensions/utils.tsx +++ b/packages/next/src/server/node-environment-extensions/utils.tsx @@ -30,13 +30,13 @@ export function io(expression: string, type: ApiType) { let message: string switch (type) { case 'time': - message = `Route "${workStore.route}" used ${expression} instead of using \`performance\` or without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time` + message = `Route "${workStore.route}" used ${expression} before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time` break case 'random': - message = `Route "${workStore.route}" used ${expression} outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random` + message = `Route "${workStore.route}" used ${expression} before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random` break case 'crypto': - message = `Route "${workStore.route}" used ${expression} outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto` + message = `Route "${workStore.route}" used ${expression} before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto` break default: throw new InvariantError( diff --git a/test/development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts b/test/development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts index a03c25d217c8b..cd5c5726f096d 100644 --- a/test/development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts +++ b/test/development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts @@ -22,7 +22,7 @@ describe('Cache Components Dev Errors', () => { // soft-navigating to the page (see test below). await expect(browser).toDisplayCollapsedRedbox(` { - "description": "Route "/error" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "description": "Route "/error" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", "environmentLabel": "Server", "label": "Console Error", "source": "app/error/page.tsx (2:23) @ Page @@ -52,7 +52,7 @@ describe('Cache Components Dev Errors', () => { // TODO: React should not include the anon stack in the Owner Stack. await expect(browser).toDisplayCollapsedRedbox(` { - "description": "Route "/error" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "description": "Route "/error" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", "environmentLabel": "Server", "label": "Console Error", "source": "app/error/page.tsx (2:23) @ Page diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts index c6dd7bd13a233..065869c96f9d5 100644 --- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts +++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts @@ -863,25 +863,104 @@ describe('Cache Components Errors', () => { } if (isNextDev) { - it('should not show a collapsed redbox error', async () => { + it('should show a collapsed redbox error', async () => { const browser = await next.browser(pathname) - await assertNoErrorToast(browser) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-random-with-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-random-with-fallback/page.tsx (37:23) @ RandomReadingComponent + > 37 | const random = Math.random() + | ^", + "stack": [ + "RandomReadingComponent app/sync-random-with-fallback/page.tsx (37:23)", + "Page app/sync-random-with-fallback/page.tsx (18:11)", + "LogSafely ", + ], + } + `) }) } else { - it('should not error the build when calling Math.random() if all dynamic access is inside a Suspense boundary', async () => { + it('should error the build if Math.random() happens before some component outside a Suspense boundary is complete', async () => { try { await prerender(pathname) - } catch (error) { - throw new Error('expected build not to fail', { cause: error }) + } catch { + // we expect the build to fail } - expect(next.cliOutput.slice(cliOutputLength)).toContain( - `◐ ${pathname}` + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } ) - await next.start({ skipBuild: true }) - const $ = await next.render$(pathname) - expect($('[data-fallback]').length).toBe(2) + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-random-with-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at RandomReadingComponent (bundler:///app/sync-random-with-fallback/page.tsx:37:23) + 35 | use(new Promise((r) => process.nextTick(r))) + 36 | } + > 37 | const random = Math.random() + | ^ + 38 | return ( + 39 |
+ 40 | {random} + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-random-with-fallback" in your browser to investigate the error. + Error occurred prerendering page "/sync-random-with-fallback". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-random-with-fallback/page: /sync-random-with-fallback" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-random-with-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-random-with-fallback/page.tsx:37:23) + 35 | use(new Promise((r) => process.nextTick(r))) + 36 | } + > 37 | const random = Math.random() + | ^ + 38 | return ( + 39 |
+ 40 | {random} + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-random-with-fallback" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-random-with-fallback". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-random-with-fallback/page: /sync-random-with-fallback, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-random-with-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at RandomReadingComponent (bundler:///app/sync-random-with-fallback/page.tsx:37:23) + 35 | use(new Promise((r) => process.nextTick(r))) + 36 | } + > 37 | const random = Math.random() + | ^ + 38 | return ( + 39 |
+ 40 | {random} + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-random-with-fallback" in your browser to investigate the error. + Error occurred prerendering page "/sync-random-with-fallback". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-random-with-fallback/page: /sync-random-with-fallback" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-random-with-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-random-with-fallback" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-random-with-fallback". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-random-with-fallback/page: /sync-random-with-fallback, exiting the build." + `) + } + } }) } }) @@ -898,21 +977,21 @@ describe('Cache Components Errors', () => { const browser = await next.browser(pathname) await expect(browser).toDisplayCollapsedRedbox(` - { - "description": "Route "/sync-random-without-fallback" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random", - "environmentLabel": "Server", - "label": "Console Error", - "source": "app/sync-random-without-fallback/page.tsx (32:15) @ getRandomNumber - > 32 | return Math.random() - | ^", - "stack": [ - "getRandomNumber app/sync-random-without-fallback/page.tsx (32:15)", - "RandomReadingComponent app/sync-random-without-fallback/page.tsx (40:18)", - "Page app/sync-random-without-fallback/page.tsx (18:11)", - "LogSafely ", - ], - } - `) + { + "description": "Route "/sync-random-without-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-random-without-fallback/page.tsx (32:15) @ getRandomNumber + > 32 | return Math.random() + | ^", + "stack": [ + "getRandomNumber app/sync-random-without-fallback/page.tsx (32:15)", + "RandomReadingComponent app/sync-random-without-fallback/page.tsx (40:18)", + "Page app/sync-random-without-fallback/page.tsx (18:11)", + "LogSafely ", + ], + } + `) }) } else { it('should error the build if Math.random() happens before some component outside a Suspense boundary is complete', async () => { @@ -930,7 +1009,7 @@ describe('Cache Components Errors', () => { if (isTurbopack) { if (isDebugPrerender) { expect(output).toMatchInlineSnapshot(` - "Error: Route "/sync-random-without-fallback" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random + "Error: Route "/sync-random-without-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random at getRandomNumber (bundler:///app/sync-random-without-fallback/page.tsx:32:15) at RandomReadingComponent (bundler:///app/sync-random-without-fallback/page.tsx:40:18) 30 | @@ -948,7 +1027,7 @@ describe('Cache Components Errors', () => { `) } else { expect(output).toMatchInlineSnapshot(` - "Error: Route "/sync-random-without-fallback" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random + "Error: Route "/sync-random-without-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random at a (bundler:///app/sync-random-without-fallback/page.tsx:32:15) 30 | 31 | function getRandomNumber() { @@ -967,7 +1046,7 @@ describe('Cache Components Errors', () => { } else { if (isDebugPrerender) { expect(output).toMatchInlineSnapshot(` - "Error: Route "/sync-random-without-fallback" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random + "Error: Route "/sync-random-without-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random at getRandomNumber (bundler:///app/sync-random-without-fallback/page.tsx:32:15) at RandomReadingComponent (bundler:///app/sync-random-without-fallback/page.tsx:40:18) 30 | @@ -985,7 +1064,7 @@ describe('Cache Components Errors', () => { `) } else { expect(output).toMatchInlineSnapshot(` - "Error: Route "/sync-random-without-fallback" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random + "Error: Route "/sync-random-without-fallback" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random at a () To get a more detailed stack trace and pinpoint the issue, try one of the following: - Start the app in development mode by running \`next dev\`, then open "/sync-random-without-fallback" in your browser to investigate the error. @@ -3197,5 +3276,1742 @@ describe('Cache Components Errors', () => { } }) }) + + describe('Sync IO - Current Time - Date()', () => { + const pathname = '/sync-io-current-time/date' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-current-time/date" used \`Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-current-time/date/page.tsx (19:16) @ DateReadingComponent + > 19 | return
{Date()}
+ | ^", + "stack": [ + "DateReadingComponent app/sync-io-current-time/date/page.tsx (19:16)", + "Page app/sync-io-current-time/date/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date" used \`Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/date". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/date/page: /sync-io-current-time/date" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date" used \`Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a (bundler:///app/sync-io-current-time/date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/date". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/date/page: /sync-io-current-time/date, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date" used \`Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/date". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/date/page: /sync-io-current-time/date" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date" used \`Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/date". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/date/page: /sync-io-current-time/date, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Current Time - Date.now()', () => { + const pathname = '/sync-io-current-time/date-now' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-current-time/date-now" used \`Date.now()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-current-time/date-now/page.tsx (19:21) @ DateReadingComponent + > 19 | return
{Date.now()}
+ | ^", + "stack": [ + "DateReadingComponent app/sync-io-current-time/date-now/page.tsx (19:21)", + "Page app/sync-io-current-time/date-now/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date-now" used \`Date.now()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/date-now/page.tsx:19:21) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date.now()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date-now" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/date-now". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/date-now/page: /sync-io-current-time/date-now" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date-now" used \`Date.now()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a (bundler:///app/sync-io-current-time/date-now/page.tsx:19:21) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date.now()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date-now" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/date-now". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/date-now/page: /sync-io-current-time/date-now, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date-now" used \`Date.now()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/date-now/page.tsx:19:21) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Date.now()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date-now" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/date-now". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/date-now/page: /sync-io-current-time/date-now" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/date-now" used \`Date.now()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/date-now" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/date-now". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/date-now/page: /sync-io-current-time/date-now, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Current Time - new Date()', () => { + const pathname = '/sync-io-current-time/new-date' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-current-time/new-date" used \`new Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-current-time/new-date/page.tsx (19:16) @ DateReadingComponent + > 19 | return
{new Date().toString()}
+ | ^", + "stack": [ + "DateReadingComponent app/sync-io-current-time/new-date/page.tsx (19:16)", + "Page app/sync-io-current-time/new-date/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/new-date" used \`new Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/new-date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{new Date().toString()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/new-date" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/new-date". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/new-date/page: /sync-io-current-time/new-date" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/new-date" used \`new Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a (bundler:///app/sync-io-current-time/new-date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{new Date().toString()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/new-date" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/new-date". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/new-date/page: /sync-io-current-time/new-date, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/new-date" used \`new Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at DateReadingComponent (bundler:///app/sync-io-current-time/new-date/page.tsx:19:16) + 17 | async function DateReadingComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{new Date().toString()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/new-date" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-current-time/new-date". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-current-time/new-date/page: /sync-io-current-time/new-date" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-current-time/new-date" used \`new Date()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing the current time in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-current-time + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-current-time/new-date" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-current-time/new-date". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-current-time/new-date/page: /sync-io-current-time/new-date, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Random - Math.random()', () => { + const pathname = '/sync-io-random/math-random' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-random/math-random" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-random/math-random/page.tsx (19:21) @ SyncIOComponent + > 19 | return
{Math.random()}
+ | ^", + "stack": [ + "SyncIOComponent app/sync-io-random/math-random/page.tsx (19:21)", + "Page app/sync-io-random/math-random/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-random/math-random" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-random/math-random/page.tsx:19:21) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Math.random()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-random/math-random" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-random/math-random". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-random/math-random/page: /sync-io-random/math-random" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-random/math-random" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-random/math-random/page.tsx:19:21) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Math.random()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-random/math-random" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-random/math-random". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-random/math-random/page: /sync-io-random/math-random, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-random/math-random" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-random/math-random/page.tsx:19:21) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{Math.random()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-random/math-random" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-random/math-random". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-random/math-random/page: /sync-io-random/math-random" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-random/math-random" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-random/math-random" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-random/math-random". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-random/math-random/page: /sync-io-random/math-random, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Web Crypto - getRandomValue()', () => { + const pathname = '/sync-io-web-crypto/get-random-value' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-web-crypto/get-random-value" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-web-crypto/get-random-value/page.tsx (20:10) @ SyncIOComponent + > 20 | crypto.getRandomValues(buffer) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-web-crypto/get-random-value/page.tsx (20:10)", + "Page app/sync-io-web-crypto/get-random-value/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/get-random-value" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-web-crypto/get-random-value/page.tsx:20:10) + 18 | await new Promise((r) => process.nextTick(r)) + 19 | const buffer = new Uint8Array(8) + > 20 | crypto.getRandomValues(buffer) + | ^ + 21 | return
{buffer.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/get-random-value" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-web-crypto/get-random-value". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-web-crypto/get-random-value/page: /sync-io-web-crypto/get-random-value" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/get-random-value" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a (bundler:///app/sync-io-web-crypto/get-random-value/page.tsx:20:10) + 18 | await new Promise((r) => process.nextTick(r)) + 19 | const buffer = new Uint8Array(8) + > 20 | crypto.getRandomValues(buffer) + | ^ + 21 | return
{buffer.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/get-random-value" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-web-crypto/get-random-value". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-web-crypto/get-random-value/page: /sync-io-web-crypto/get-random-value, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/get-random-value" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-web-crypto/get-random-value/page.tsx:20:10) + 18 | await new Promise((r) => process.nextTick(r)) + 19 | const buffer = new Uint8Array(8) + > 20 | crypto.getRandomValues(buffer) + | ^ + 21 | return
{buffer.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/get-random-value" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-web-crypto/get-random-value". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-web-crypto/get-random-value/page: /sync-io-web-crypto/get-random-value" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/get-random-value" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/get-random-value" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-web-crypto/get-random-value". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-web-crypto/get-random-value/page: /sync-io-web-crypto/get-random-value, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Web Crypto - randomUUID()', () => { + const pathname = '/sync-io-web-crypto/random-uuid' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-web-crypto/random-uuid" used \`crypto.randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-web-crypto/random-uuid/page.tsx (19:23) @ SyncIOComponent + > 19 | return
{crypto.randomUUID()}
+ | ^", + "stack": [ + "SyncIOComponent app/sync-io-web-crypto/random-uuid/page.tsx (19:23)", + "Page app/sync-io-web-crypto/random-uuid/page.tsx (11:9)", + "LogSafely ", + ], + } + `) + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/random-uuid" used \`crypto.randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-web-crypto/random-uuid/page.tsx:19:23) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{crypto.randomUUID()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/random-uuid" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-web-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-web-crypto/random-uuid/page: /sync-io-web-crypto/random-uuid" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/random-uuid" used \`crypto.randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a (bundler:///app/sync-io-web-crypto/random-uuid/page.tsx:19:23) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{crypto.randomUUID()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/random-uuid" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-web-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-web-crypto/random-uuid/page: /sync-io-web-crypto/random-uuid, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/random-uuid" used \`crypto.randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-web-crypto/random-uuid/page.tsx:19:23) + 17 | async function SyncIOComponent() { + 18 | await new Promise((r) => process.nextTick(r)) + > 19 | return
{crypto.randomUUID()}
+ | ^ + 20 | } + 21 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/random-uuid" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-web-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-web-crypto/random-uuid/page: /sync-io-web-crypto/random-uuid" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-web-crypto/random-uuid" used \`crypto.randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-web-crypto/random-uuid" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-web-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-web-crypto/random-uuid/page: /sync-io-web-crypto/random-uuid, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - generateKeyPairSync()', () => { + const pathname = '/sync-io-node-crypto/generate-key-pair-sync' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (20:24) @ SyncIOComponent + > 20 | const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (20:24)", + "Page app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (20:17)", + "Page app/sync-io-node-crypto/generate-key-pair-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-key-pair-sync/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + | ^ + 21 | return
{first.publicKey}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-pair-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-pair-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-key-pair-sync/page: /sync-io-node-crypto/generate-key-pair-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/generate-key-pair-sync/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + | ^ + 21 | return
{first.publicKey}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-pair-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-pair-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-key-pair-sync/page: /sync-io-node-crypto/generate-key-pair-sync, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-key-pair-sync/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + | ^ + 21 | return
{first.publicKey}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-pair-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-pair-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-key-pair-sync/page: /sync-io-node-crypto/generate-key-pair-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-pair-sync" used \`require('node:crypto').generateKeyPairSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-pair-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-pair-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-key-pair-sync/page: /sync-io-node-crypto/generate-key-pair-sync, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - generateKeySync()', () => { + const pathname = '/sync-io-node-crypto/generate-key-sync' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-key-sync/page.tsx (21:6) @ SyncIOComponent + > 21 | .generateKeySync('hmac', { + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-key-sync/page.tsx (21:6)", + "Page app/sync-io-node-crypto/generate-key-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-key-sync/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-key-sync/page.tsx (20:17)", + "Page app/sync-io-node-crypto/generate-key-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-key-sync/page.tsx:21:6) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = crypto + > 21 | .generateKeySync('hmac', { + | ^ + 22 | length: 512, + 23 | }) + 24 | .export() + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-key-sync/page: /sync-io-node-crypto/generate-key-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/generate-key-sync/page.tsx:21:6) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = crypto + > 21 | .generateKeySync('hmac', { + | ^ + 22 | length: 512, + 23 | }) + 24 | .export() + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-key-sync/page: /sync-io-node-crypto/generate-key-sync, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-key-sync/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto + | ^ + 21 | .generateKeySync('hmac', { + 22 | length: 512, + 23 | }) + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-key-sync/page: /sync-io-node-crypto/generate-key-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-key-sync" used \`require('node:crypto').generateKeySync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-key-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-key-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-key-sync/page: /sync-io-node-crypto/generate-key-sync, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - generatePrimeSync()', () => { + const pathname = '/sync-io-node-crypto/generate-prime-sync' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-prime-sync/page.tsx (20:39) @ SyncIOComponent + > 20 | const first = new Uint8Array(crypto.generatePrimeSync(128)) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-prime-sync/page.tsx (20:39)", + "Page app/sync-io-node-crypto/generate-prime-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/generate-prime-sync/page.tsx (20:32) @ SyncIOComponent + > 20 | const first = new Uint8Array(crypto.generatePrimeSync(128)) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/generate-prime-sync/page.tsx (20:32)", + "Page app/sync-io-node-crypto/generate-prime-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-prime-sync/page.tsx:20:39) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = new Uint8Array(crypto.generatePrimeSync(128)) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-prime-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-prime-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-prime-sync/page: /sync-io-node-crypto/generate-prime-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/generate-prime-sync/page.tsx:20:39) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = new Uint8Array(crypto.generatePrimeSync(128)) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-prime-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-prime-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-prime-sync/page: /sync-io-node-crypto/generate-prime-sync, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/generate-prime-sync/page.tsx:20:32) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = new Uint8Array(crypto.generatePrimeSync(128)) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-prime-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/generate-prime-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/generate-prime-sync/page: /sync-io-node-crypto/generate-prime-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/generate-prime-sync" used \`require('node:crypto').generatePrimeSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/generate-prime-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/generate-prime-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/generate-prime-sync/page: /sync-io-node-crypto/generate-prime-sync, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - getRandomValues()', () => { + const pathname = '/sync-io-node-crypto/get-random-values' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/get-random-values/page.tsx (21:10) @ SyncIOComponent + > 21 | crypto.getRandomValues(first) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/get-random-values/page.tsx (21:10)", + "Page app/sync-io-node-crypto/get-random-values/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/get-random-values/page.tsx (21:3) @ SyncIOComponent + > 21 | crypto.getRandomValues(first) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/get-random-values/page.tsx (21:3)", + "Page app/sync-io-node-crypto/get-random-values/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-node-crypto/get-random-values/page.tsx:21:10) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(8) + > 21 | crypto.getRandomValues(first) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/get-random-values" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/get-random-values". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/get-random-values/page: /sync-io-node-crypto/get-random-values" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a (bundler:///app/sync-io-node-crypto/get-random-values/page.tsx:21:10) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(8) + > 21 | crypto.getRandomValues(first) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/get-random-values" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/get-random-values". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/get-random-values/page: /sync-io-node-crypto/get-random-values, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at SyncIOComponent (bundler:///app/sync-io-node-crypto/get-random-values/page.tsx:21:3) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(8) + > 21 | crypto.getRandomValues(first) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/get-random-values" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/get-random-values". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/get-random-values/page: /sync-io-node-crypto/get-random-values" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/get-random-values" used \`crypto.getRandomValues()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random cryptographic values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-crypto + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/get-random-values" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/get-random-values". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/get-random-values/page: /sync-io-node-crypto/get-random-values, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - random-bytes()', () => { + const pathname = '/sync-io-node-crypto/random-bytes' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-bytes/page.tsx (20:24) @ SyncIOComponent + > 20 | const first = crypto.randomBytes(8) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-bytes/page.tsx (20:24)", + "Page app/sync-io-node-crypto/random-bytes/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-bytes/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto.randomBytes(8) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-bytes/page.tsx (20:17)", + "Page app/sync-io-node-crypto/random-bytes/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-bytes/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomBytes(8) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-bytes" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-bytes". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-bytes/page: /sync-io-node-crypto/random-bytes" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/random-bytes/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomBytes(8) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-bytes" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-bytes". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-bytes/page: /sync-io-node-crypto/random-bytes, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-bytes/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomBytes(8) + | ^ + 21 | return
{first.toString()}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-bytes" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-bytes". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-bytes/page: /sync-io-node-crypto/random-bytes" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-bytes" used \`require('node:crypto').randomBytes(size)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-bytes" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-bytes". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-bytes/page: /sync-io-node-crypto/random-bytes, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - random-fill-sync()', () => { + const pathname = '/sync-io-node-crypto/random-fill-sync' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-fill-sync/page.tsx (21:10) @ SyncIOComponent + > 21 | crypto.randomFillSync(first, 4, 8) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-fill-sync/page.tsx (21:10)", + "Page app/sync-io-node-crypto/random-fill-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-fill-sync/page.tsx (21:3) @ SyncIOComponent + > 21 | crypto.randomFillSync(first, 4, 8) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-fill-sync/page.tsx (21:3)", + "Page app/sync-io-node-crypto/random-fill-sync/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-fill-sync/page.tsx:21:10) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(16) + > 21 | crypto.randomFillSync(first, 4, 8) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-fill-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-fill-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-fill-sync/page: /sync-io-node-crypto/random-fill-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/random-fill-sync/page.tsx:21:10) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(16) + > 21 | crypto.randomFillSync(first, 4, 8) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-fill-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-fill-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-fill-sync/page: /sync-io-node-crypto/random-fill-sync, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-fill-sync/page.tsx:21:3) + 19 | await new Promise((r) => process.nextTick(r)) + 20 | const first = new Uint8Array(16) + > 21 | crypto.randomFillSync(first, 4, 8) + | ^ + 22 | return
{first.toString()}
+ 23 | } + 24 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-fill-sync" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-fill-sync". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-fill-sync/page: /sync-io-node-crypto/random-fill-sync" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-fill-sync" used \`require('node:crypto').randomFillSync(...)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-fill-sync" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-fill-sync". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-fill-sync/page: /sync-io-node-crypto/random-fill-sync, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - random-int-between()', () => { + const pathname = '/sync-io-node-crypto/random-int-between' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-int-between/page.tsx (20:24) @ SyncIOComponent + > 20 | const first = crypto.randomInt(128, 256) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-int-between/page.tsx (20:24)", + "Page app/sync-io-node-crypto/random-int-between/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-int-between/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto.randomInt(128, 256) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-int-between/page.tsx (20:17)", + "Page app/sync-io-node-crypto/random-int-between/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-int-between/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128, 256) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-between" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-int-between". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-int-between/page: /sync-io-node-crypto/random-int-between" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/random-int-between/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128, 256) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-between" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-int-between". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-int-between/page: /sync-io-node-crypto/random-int-between, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-int-between/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128, 256) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-between" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-int-between". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-int-between/page: /sync-io-node-crypto/random-int-between" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-between" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-between" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-int-between". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-int-between/page: /sync-io-node-crypto/random-int-between, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - random-int-up-to()', () => { + const pathname = '/sync-io-node-crypto/random-int-up-to' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-int-up-to/page.tsx (20:24) @ SyncIOComponent + > 20 | const first = crypto.randomInt(128) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-int-up-to/page.tsx (20:24)", + "Page app/sync-io-node-crypto/random-int-up-to/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-int-up-to/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto.randomInt(128) + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-int-up-to/page.tsx (20:17)", + "Page app/sync-io-node-crypto/random-int-up-to/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-int-up-to/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-up-to" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-int-up-to". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-int-up-to/page: /sync-io-node-crypto/random-int-up-to" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/random-int-up-to/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-up-to" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-int-up-to". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-int-up-to/page: /sync-io-node-crypto/random-int-up-to, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-int-up-to/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomInt(128) + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-up-to" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-int-up-to". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-int-up-to/page: /sync-io-node-crypto/random-int-up-to" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-int-up-to" used \`require('node:crypto').randomInt(min, max)\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-int-up-to" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-int-up-to". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-int-up-to/page: /sync-io-node-crypto/random-int-up-to, exiting the build." + `) + } + } + }) + } + }) + + describe('Sync IO - Node Crypto - random-uuid', () => { + const pathname = '/sync-io-node-crypto/random-uuid' + + if (isNextDev) { + it('should show a collapsed redbox error', async () => { + const browser = await next.browser(pathname) + + if (isTurbopack) { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-uuid/page.tsx (20:24) @ SyncIOComponent + > 20 | const first = crypto.randomUUID() + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-uuid/page.tsx (20:24)", + "Page app/sync-io-node-crypto/random-uuid/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } else { + await expect(browser).toDisplayCollapsedRedbox(` + { + "description": "Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random", + "environmentLabel": "Server", + "label": "Console Error", + "source": "app/sync-io-node-crypto/random-uuid/page.tsx (20:17) @ SyncIOComponent + > 20 | const first = crypto.randomUUID() + | ^", + "stack": [ + "SyncIOComponent app/sync-io-node-crypto/random-uuid/page.tsx (20:17)", + "Page app/sync-io-node-crypto/random-uuid/page.tsx (12:9)", + "LogSafely ", + ], + } + `) + } + }) + } else { + it('should error the build if sync IO is used in a Server Component while prerendering', async () => { + try { + await prerender(pathname) + } catch { + // we expect the build to fail + } + + const output = getPrerenderOutput( + next.cliOutput.slice(cliOutputLength), + { isMinified: !isDebugPrerender } + ) + + if (isTurbopack) { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-uuid/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomUUID() + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-uuid" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-uuid/page: /sync-io-node-crypto/random-uuid" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a (bundler:///app/sync-io-node-crypto/random-uuid/page.tsx:20:24) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomUUID() + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-uuid" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-uuid/page: /sync-io-node-crypto/random-uuid, exiting the build." + `) + } + } else { + if (isDebugPrerender) { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at SyncIOComponent (bundler:///app/sync-io-node-crypto/random-uuid/page.tsx:20:17) + 18 | async function SyncIOComponent() { + 19 | await new Promise((r) => process.nextTick(r)) + > 20 | const first = crypto.randomUUID() + | ^ + 21 | return
{first}
+ 22 | } + 23 | + To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-uuid" in your browser to investigate the error. + Error occurred prerendering page "/sync-io-node-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + + > Export encountered errors on following paths: + /sync-io-node-crypto/random-uuid/page: /sync-io-node-crypto/random-uuid" + `) + } else { + expect(output).toMatchInlineSnapshot(` + "Error: Route "/sync-io-node-crypto/random-uuid" used \`require('node:crypto').randomUUID()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random + at a () + To get a more detailed stack trace and pinpoint the issue, try one of the following: + - Start the app in development mode by running \`next dev\`, then open "/sync-io-node-crypto/random-uuid" in your browser to investigate the error. + - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces. + Error occurred prerendering page "/sync-io-node-crypto/random-uuid". Read more: https://nextjs.org/docs/messages/prerender-error + Export encountered an error on /sync-io-node-crypto/random-uuid/page: /sync-io-node-crypto/random-uuid, exiting the build." + `) + } + } + }) + } + }) }) }) diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date-now/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date-now/page.tsx new file mode 100644 index 0000000000000..4e83c6d258bce --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date-now/page.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page accesses the current time `Date.now()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function DateReadingComponent() { + await new Promise((r) => process.nextTick(r)) + return
{Date.now()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date/page.tsx new file mode 100644 index 0000000000000..75978228ee36e --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/date/page.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page accesses the current time `Date()` in a Server Component which + is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function DateReadingComponent() { + await new Promise((r) => process.nextTick(r)) + return
{Date()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/layout.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/layout.tsx new file mode 100644 index 0000000000000..745e32b8a8d23 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/layout.tsx @@ -0,0 +1,9 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + +
{children}
+ + + ) +} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/new-date/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/new-date/page.tsx new file mode 100644 index 0000000000000..64d9914f27574 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-current-time/new-date/page.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page accesses the current time `new Date()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function DateReadingComponent() { + await new Promise((r) => process.nextTick(r)) + return
{new Date().toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-pair-sync/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-pair-sync/page.tsx new file mode 100644 index 0000000000000..8a2e98d3f9a96 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-pair-sync/page.tsx @@ -0,0 +1,34 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.generateKeyPairSync()` in a Server + Component which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto.generateKeyPairSync('rsa', keyGenOptions) + return
{first.publicKey}
+} + +const keyGenOptions = { + modulusLength: 512, + publicKeyEncoding: { + type: 'spki', + format: 'pem', + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem', + }, +} as const diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-sync/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-sync/page.tsx new file mode 100644 index 0000000000000..e3b815a7c379d --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-key-sync/page.tsx @@ -0,0 +1,26 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto .generateKeySync()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto + .generateKeySync('hmac', { + length: 512, + }) + .export() + return
{first.toString('hex')}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-prime-sync/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-prime-sync/page.tsx new file mode 100644 index 0000000000000..1b508e6c908ee --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/generate-prime-sync/page.tsx @@ -0,0 +1,22 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.generatePrimeSync()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = new Uint8Array(crypto.generatePrimeSync(128)) + return
{first.toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/get-random-values/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/get-random-values/page.tsx new file mode 100644 index 0000000000000..64d28dc0dc3ec --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/get-random-values/page.tsx @@ -0,0 +1,23 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.getRandomValues()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = new Uint8Array(8) + crypto.getRandomValues(first) + return
{first.toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/layout.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/layout.tsx new file mode 100644 index 0000000000000..745e32b8a8d23 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/layout.tsx @@ -0,0 +1,9 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + +
{children}
+ + + ) +} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-bytes/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-bytes/page.tsx new file mode 100644 index 0000000000000..09de0911ef8d4 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-bytes/page.tsx @@ -0,0 +1,22 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.randomBytes()` in a Server Component which + is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto.randomBytes(8) + return
{first.toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-fill-sync/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-fill-sync/page.tsx new file mode 100644 index 0000000000000..6ebaa4cd0b6fd --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-fill-sync/page.tsx @@ -0,0 +1,23 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.randomFillSync()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = new Uint8Array(16) + crypto.randomFillSync(first, 4, 8) + return
{first.toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-between/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-between/page.tsx new file mode 100644 index 0000000000000..f4ffaddf283be --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-between/page.tsx @@ -0,0 +1,22 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.randomInt(x, y)` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto.randomInt(128, 256) + return
{first}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-up-to/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-up-to/page.tsx new file mode 100644 index 0000000000000..794735ea22bc4 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-int-up-to/page.tsx @@ -0,0 +1,22 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.randomInt(x)` in a Server Component which + is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto.randomInt(128) + return
{first}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-uuid/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-uuid/page.tsx new file mode 100644 index 0000000000000..ea3d1590b5c8b --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-node-crypto/random-uuid/page.tsx @@ -0,0 +1,22 @@ +import crypto from 'node:crypto' +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses Node's `crypto.randomInt(x)` in a Server Component which + is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const first = crypto.randomUUID() + return
{first}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/layout.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/layout.tsx new file mode 100644 index 0000000000000..745e32b8a8d23 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/layout.tsx @@ -0,0 +1,9 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + +
{children}
+ + + ) +} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/math-random/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/math-random/page.tsx new file mode 100644 index 0000000000000..c90dfae6c37c2 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-random/math-random/page.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page produces a random number `Math.random()` in a Server Component + which is an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + return
{Math.random()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/get-random-value/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/get-random-value/page.tsx new file mode 100644 index 0000000000000..32182cef555cc --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/get-random-value/page.tsx @@ -0,0 +1,22 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses `crypto.getRandomValue()` in a Server Component which is + an error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + const buffer = new Uint8Array(8) + crypto.getRandomValues(buffer) + return
{buffer.toString()}
+} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/layout.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/layout.tsx new file mode 100644 index 0000000000000..745e32b8a8d23 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/layout.tsx @@ -0,0 +1,9 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + +
{children}
+ + + ) +} diff --git a/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/random-uuid/page.tsx b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/random-uuid/page.tsx new file mode 100644 index 0000000000000..854d1caf22fb2 --- /dev/null +++ b/test/e2e/app-dir/cache-components-errors/fixtures/default/app/sync-io-web-crypto/random-uuid/page.tsx @@ -0,0 +1,20 @@ +import { Suspense } from 'react' + +export default async function Page() { + return ( + <> +

+ This page uses `crypto.randomUUID()` in a Server Component which is an + error unless preceded by something else dynamic +

+ + + + + ) +} + +async function SyncIOComponent() { + await new Promise((r) => process.nextTick(r)) + return
{crypto.randomUUID()}
+} diff --git a/test/e2e/app-dir/cache-components-request-apis/cache-components-request-apis.test.ts b/test/e2e/app-dir/cache-components-request-apis/cache-components-request-apis.test.ts index b7b126558c317..d95fd4132d581 100644 --- a/test/e2e/app-dir/cache-components-request-apis/cache-components-request-apis.test.ts +++ b/test/e2e/app-dir/cache-components-request-apis/cache-components-request-apis.test.ts @@ -81,6 +81,7 @@ describe(`Request Promises`, () => { const { next, isNextDev, skipped } = nextTestSetup({ files: __dirname + '/fixtures/reject-hanging-promises-dynamic', skipStart: true, + skipDeployment: true, }) if (skipped) { @@ -95,9 +96,7 @@ describe(`Request Promises`, () => { it('should reject request APIs after the prerender is interrupted with synchronously dynamic APIs', async () => { try { await next.start() - } catch { - throw new Error('expected build not to fail for fully static project') - } + } catch {} const expectError = createExpectError(next.cliOutput) expectError( diff --git a/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-dynamic/app/[slug]/page.tsx b/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-dynamic/app/[slug]/page.tsx index 278bb942b08c5..245e70ffe175d 100644 --- a/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-dynamic/app/[slug]/page.tsx +++ b/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-dynamic/app/[slug]/page.tsx @@ -1,10 +1,6 @@ import { cookies, headers, draftMode } from 'next/headers' import { connection } from 'next/server' -export function generateStaticParams() { - return [{ slug: 'one' }] -} - export default async function Page(props: { params: Promise<{}> searchParams: Promise<{}> diff --git a/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-static/app/[slug]/page.tsx b/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-static/app/[slug]/page.tsx index f7b8ad31d19b5..88f0dc9f8effe 100644 --- a/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-static/app/[slug]/page.tsx +++ b/test/e2e/app-dir/cache-components-request-apis/fixtures/reject-hanging-promises-static/app/[slug]/page.tsx @@ -1,10 +1,6 @@ import { cookies, headers, draftMode } from 'next/headers' import { connection } from 'next/server' -export function generateStaticParams() { - return [{ slug: 'one' }] -} - export default async function Page(props: { params: Promise<{}> searchParams: Promise<{}> diff --git a/test/e2e/app-dir/cache-components/app/date/date/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/date/date/uncached/page.tsx deleted file mode 100644 index 1bd848df5b8e3..0000000000000 --- a/test/e2e/app-dir/cache-components/app/date/date/uncached/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - if (typeof window === 'undefined') { - await new Promise((r) => process.nextTick(r)) - } - const date = Date() - return ( -
- - {date} - - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/date/new-date/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/date/new-date/uncached/page.tsx deleted file mode 100644 index 0cac401bf0996..0000000000000 --- a/test/e2e/app-dir/cache-components/app/date/new-date/uncached/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - if (typeof window === 'undefined') { - await new Promise((r) => process.nextTick(r)) - } - const newDate = new Date() - return ( -
- - {newDate.toString()} - - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/date/now/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/date/now/uncached/page.tsx deleted file mode 100644 index b445bb0e9357c..0000000000000 --- a/test/e2e/app-dir/cache-components/app/date/now/uncached/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - if (typeof window === 'undefined') { - await new Promise((r) => process.nextTick(r)) - } - const now = Date.now() - return ( -
- - {now} - - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-pair-sync/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-pair-sync/uncached/page.tsx deleted file mode 100644 index 5ec8970044665..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-pair-sync/uncached/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.generateKeyPairSync('rsa', keyGenOptions) - const second = crypto.generateKeyPairSync('rsa', keyGenOptions) - return ( -
-
-
- [first] require('node:crypto').generateKeyPairSync(type, options) -
-
{first.publicKey}
-
- [second] require('node:crypto').generateKeyPairSync(type, options) -
-
{second.publicKey}
-
- - - -
- ) -} - -const keyGenOptions = { - modulusLength: 512, - publicKeyEncoding: { - type: 'spki', - format: 'pem', - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - }, -} as const diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-sync/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-sync/uncached/page.tsx deleted file mode 100644 index 28d1570745a27..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/generate-key-sync/uncached/page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto - .generateKeySync('hmac', { - length: 512, - }) - .export() - const second = crypto - .generateKeySync('hmac', { - length: 512, - }) - .export() - return ( -
-
-
[first] require('node:crypto').generateKeySync(type, options)
-
{first.toString('hex')}
-
[second] require('node:crypto').generateKeySync(type, options)
-
{second.toString('hex')}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/generate-prime-sync/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/generate-prime-sync/uncached/page.tsx deleted file mode 100644 index 0e4d84e351700..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/generate-prime-sync/uncached/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = new Uint8Array(crypto.generatePrimeSync(128)) - const second = new Uint8Array(crypto.generatePrimeSync(128)) - return ( -
-
-
[first] require('node:crypto').generatePrimeSync(size)
-
{first.toString()}
-
[second] require('node:crypto').generatePrimeSync(size)
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/get-random-values/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/get-random-values/uncached/page.tsx deleted file mode 100644 index 50d8bb7ec9bd5..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/get-random-values/uncached/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = new Uint8Array(8) - const second = new Uint8Array(8) - await crypto.getRandomValues(first) - await crypto.getRandomValues(second) - return ( -
-
-
[first] require('node:crypto').getRandomValues()
-
{first.toString()}
-
[second] require('node:crypto').getRandomValues()
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/random-bytes/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/random-bytes/uncached/page.tsx deleted file mode 100644 index d9e281d0c5219..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/random-bytes/uncached/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.randomBytes(8, undefined) as unknown as Buffer - const second = crypto.randomBytes(8) - return ( -
-
-
[first] require('node:crypto').randomBytes(size)
-
{first.toString('hex')}
-
[second] require('node:crypto').randomUUID(size)
-
{second.toString('hex')}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/random-fill-sync/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/random-fill-sync/uncached/page.tsx deleted file mode 100644 index c997b7a1c1851..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/random-fill-sync/uncached/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = new Uint8Array(16) - const second = new Uint8Array(16) - crypto.randomFillSync(first, 4, 8) - crypto.randomFillSync(second, 4, 8) - return ( -
-
-
[first] require('node:crypto').randomFillSync(buffer)
-
{first.toString()}
-
[second] require('node:crypto').randomBytes(buffer)
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/random-int/between/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/random-int/between/uncached/page.tsx deleted file mode 100644 index d93c2275bb0cb..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/random-int/between/uncached/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.randomInt(128, 256) - const second = crypto.randomInt(128, 256, undefined) as undefined as number - return ( -
-
-
[first] require('node:crypto').randomInt(min, max)
-
{first}
-
[second] require('node:crypto').randomInt(min, max)
-
{second}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/random-int/up-to/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/random-int/up-to/uncached/page.tsx deleted file mode 100644 index fa2a29a7860da..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/random-int/up-to/uncached/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.randomInt(128) - let second = crypto.randomInt(128) - while (first === second) { - // Ensure that the second value is different from the first - second = crypto.randomInt(128) - } - return ( -
-
-
[first] require('node:crypto').randomInt(max)
-
{first}
-
[second] require('node:crypto').randomInt(max)
-
{second}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/node-crypto/random-uuid/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/node-crypto/random-uuid/uncached/page.tsx deleted file mode 100644 index 05e4e0091ce09..0000000000000 --- a/test/e2e/app-dir/cache-components/app/node-crypto/random-uuid/uncached/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import crypto from 'node:crypto' - -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.randomUUID() - const second = crypto.randomUUID() - return ( -
-
-
[first] require('node:crypto').randomUUID()
-
{first.toString()}
-
[second] require('node:crypto').randomUUID()
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/random/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/random/uncached/page.tsx deleted file mode 100644 index a6c8eff216b47..0000000000000 --- a/test/e2e/app-dir/cache-components/app/random/uncached/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { SentinelValue } from '../../getSentinelValue' - -export default async function Page() { - if (typeof window === 'undefined') { - await new Promise((r) => process.nextTick(r)) - } - const random = Math.random() - return ( -
- - {random} - - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/web-crypto/get-random-values/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/web-crypto/get-random-values/uncached/page.tsx deleted file mode 100644 index 320a2c4e8cf7e..0000000000000 --- a/test/e2e/app-dir/cache-components/app/web-crypto/get-random-values/uncached/page.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = new Uint8Array(8) - const second = new Uint8Array(8) - await crypto.getRandomValues(first) - await crypto.getRandomValues(second) - return ( -
-
-
[first] crypto.getRandomValues()
-
{first.toString()}
-
[second] crypto.getRandomValues()
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/app/web-crypto/random-uuid/uncached/page.tsx b/test/e2e/app-dir/cache-components/app/web-crypto/random-uuid/uncached/page.tsx deleted file mode 100644 index 245cf3c4ba8e1..0000000000000 --- a/test/e2e/app-dir/cache-components/app/web-crypto/random-uuid/uncached/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { SentinelValue } from '../../../getSentinelValue' - -export default async function Page() { - await new Promise((r) => process.nextTick(r)) - const first = crypto.randomUUID() - const second = crypto.randomUUID() - return ( -
-
-
[first] crypto.randomUUID()
-
{first.toString()}
-
[second] crypto.randomUUID()
-
{second.toString()}
-
- - - -
- ) -} diff --git a/test/e2e/app-dir/cache-components/cache-components.date.test.ts b/test/e2e/app-dir/cache-components/cache-components.date.test.ts index 3c0e1f163fb1a..80166977a6c28 100644 --- a/test/e2e/app-dir/cache-components/cache-components.date.test.ts +++ b/test/e2e/app-dir/cache-components/cache-components.date.test.ts @@ -29,19 +29,6 @@ describe('cache-components', () => { } }) - it('should not prerender pages with uncached `Date.now()` calls', async () => { - let $ = await next.render$('/date/now/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toMatch(/^\d+$/) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toMatch(/^\d+$/) - } - }) - it('should prerender pages with cached `Date()` calls', async () => { let $ = await next.render$('/date/date/cached', {}) if (isNextDev) { @@ -55,19 +42,6 @@ describe('cache-components', () => { } }) - it('should not prerender pages with uncached `Date()` calls', async () => { - let $ = await next.render$('/date/date/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toContain('GMT') - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toContain('GMT') - } - }) - it('should prerender pages with cached `new Date()` calls', async () => { let $ = await next.render$('/date/new-date/cached', {}) if (isNextDev) { @@ -81,19 +55,6 @@ describe('cache-components', () => { } }) - it('should not prerender pages with uncached `new Date()` calls', async () => { - let $ = await next.render$('/date/new-date/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toContain('GMT') - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#value').text()).toContain('GMT') - } - }) - it('should prerender pages with cached static Date instances like `new Date(0)`', async () => { let $ = await next.render$('/date/static-date/cached', {}) if (isNextDev) { diff --git a/test/e2e/app-dir/cache-components/cache-components.node-crypto.test.ts b/test/e2e/app-dir/cache-components/cache-components.node-crypto.test.ts index 6b3f416b3b1b7..a5fb2a9719f20 100644 --- a/test/e2e/app-dir/cache-components/cache-components.node-crypto.test.ts +++ b/test/e2e/app-dir/cache-components/cache-components.node-crypto.test.ts @@ -28,19 +28,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').getRandomValues(...)` calls", async () => { - let $ = await next.render$('/node-crypto/get-random-values/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').randomUUID()` calls", async () => { let $ = await next.render$('/node-crypto/random-uuid/cached', {}) if (isNextDev) { @@ -54,19 +41,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').randomUUID()` calls", async () => { - let $ = await next.render$('/node-crypto/random-uuid/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').randomBytes(size)` calls", async () => { let $ = await next.render$('/node-crypto/random-bytes/cached', {}) if (isNextDev) { @@ -80,19 +54,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').randomBytes(size)` calls", async () => { - let $ = await next.render$('/node-crypto/random-bytes/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').randomFillSync(buffer)` calls", async () => { let $ = await next.render$('/node-crypto/random-fill-sync/cached', {}) if (isNextDev) { @@ -106,19 +67,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').randomFillSync(buffer)` calls", async () => { - let $ = await next.render$('/node-crypto/random-fill-sync/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').randomInt(max)` calls", async () => { let $ = await next.render$('/node-crypto/random-int/up-to/cached', {}) if (isNextDev) { @@ -132,19 +80,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').randomInt(max)` calls", async () => { - let $ = await next.render$('/node-crypto/random-int/up-to/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').randomInt(min, max)` calls", async () => { let $ = await next.render$('/node-crypto/random-int/between/cached', {}) if (isNextDev) { @@ -158,19 +93,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').randomInt(min, max)` calls", async () => { - let $ = await next.render$('/node-crypto/random-int/between/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').generatePrimeSync(size, options)` calls", async () => { let $ = await next.render$('/node-crypto/generate-prime-sync/cached', {}) if (isNextDev) { @@ -184,19 +106,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').generatePrimeSync(size, options)` calls", async () => { - let $ = await next.render$('/node-crypto/generate-prime-sync/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').generateKeyPairSync(type, options)` calls", async () => { let $ = await next.render$('/node-crypto/generate-key-pair-sync/cached', {}) if (isNextDev) { @@ -210,22 +119,6 @@ describe('cache-components', () => { } }) - it("should not prerender pages with uncached `require('node:crypto').generateKeyPairSync(type, options)` calls", async () => { - let $ = await next.render$( - '/node-crypto/generate-key-pair-sync/uncached', - {} - ) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it("should prerender pages with cached `require('node:crypto').generateKeySync(type, options)` calls", async () => { let $ = await next.render$('/node-crypto/generate-key-sync/cached', {}) if (isNextDev) { @@ -238,17 +131,4 @@ describe('cache-components', () => { expect($('#first').text()).not.toEqual($('#second').text()) } }) - - it("should not prerender pages with uncached `require('node:crypto').generateKeySync(type, options)` calls", async () => { - let $ = await next.render$('/node-crypto/generate-key-sync/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) }) diff --git a/test/e2e/app-dir/cache-components/cache-components.random.test.ts b/test/e2e/app-dir/cache-components/cache-components.random.test.ts index 85cd7e31546f9..6c9b91210fa5c 100644 --- a/test/e2e/app-dir/cache-components/cache-components.random.test.ts +++ b/test/e2e/app-dir/cache-components/cache-components.random.test.ts @@ -25,15 +25,4 @@ describe('cache-components', () => { expect($('#page').text()).toBe('at buildtime') } }) - - it('should not prerender pages with uncached Math.random() calls', async () => { - let $ = await next.render$('/random/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - } - }) }) diff --git a/test/e2e/app-dir/cache-components/cache-components.web-crypto.test.ts b/test/e2e/app-dir/cache-components/cache-components.web-crypto.test.ts index d3a9552ddbfb5..15133ffed886b 100644 --- a/test/e2e/app-dir/cache-components/cache-components.web-crypto.test.ts +++ b/test/e2e/app-dir/cache-components/cache-components.web-crypto.test.ts @@ -28,19 +28,6 @@ describe('cache-components', () => { } }) - it('should not prerender pages with uncached `crypto.getRandomValues(...)` calls', async () => { - let $ = await next.render$('/web-crypto/get-random-values/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) - it('should prerender pages with cached `crypto.randomUUID()` calls', async () => { let $ = await next.render$('/web-crypto/random-uuid/cached', {}) if (isNextDev) { @@ -53,17 +40,4 @@ describe('cache-components', () => { expect($('#first').text()).not.toEqual($('#second').text()) } }) - - it('should not prerender pages with uncached `crypto.randomUUID()` calls', async () => { - let $ = await next.render$('/web-crypto/random-uuid/uncached', {}) - if (isNextDev) { - expect($('#layout').text()).toBe('at runtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } else { - expect($('#layout').text()).toBe('at buildtime') - expect($('#page').text()).toBe('at runtime') - expect($('#first').text()).not.toEqual($('#second').text()) - } - }) }) diff --git a/test/e2e/app-dir/node-extensions/fixtures/random/cache-components/app/app/prerendered/uncached/page.tsx b/test/e2e/app-dir/node-extensions/fixtures/random/cache-components/app/app/prerendered/uncached/page.tsx deleted file mode 100644 index e6c1f89d38c0e..0000000000000 --- a/test/e2e/app-dir/node-extensions/fixtures/random/cache-components/app/app/prerendered/uncached/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -export default async function Page() { - if (typeof process !== 'undefined') { - // we delay the random calls to avoid triggering dynamic in other component trees - await new Promise((r) => process.nextTick(r)) - } - return ( -
    -
  • - -
  • -
  • - -
  • -
- ) -} - -async function RandomValue() { - return Math.random() -} diff --git a/test/e2e/app-dir/node-extensions/node-extensions.random.test.ts b/test/e2e/app-dir/node-extensions/node-extensions.random.test.ts index 4624f8ac1847c..2da9996f546a0 100644 --- a/test/e2e/app-dir/node-extensions/node-extensions.random.test.ts +++ b/test/e2e/app-dir/node-extensions/node-extensions.random.test.ts @@ -25,11 +25,6 @@ describe('Node Extensions', () => { it('should not error when accessing pages that use Math.random() in App Router', async () => { let res, $ - res = await next.fetch('/app/prerendered/uncached') - expect(res.status).toBe(200) - $ = await next.render$('/app/prerendered/uncached') - expect($('li').length).toBe(2) - res = await next.fetch('/app/prerendered/unstable-cache') expect(res.status).toBe(200) $ = await next.render$('/app/prerendered/unstable-cache') diff --git a/test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts b/test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts index 18f27e0bae6f5..72559d5346c6f 100644 --- a/test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts +++ b/test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts @@ -1008,7 +1008,7 @@ describe(' (runtime prefetch)', () => { path: '/errors/sync-io-after-runtime-api/quickly-expiring-public-cache', }, ])( - 'aborts the prerender and logs an error $description', + 'aborts the prerender without logging an error $description', async ({ path }) => { // In a runtime prefetch, we might encounter sync IO usages that weren't caught during build, // because they were hidden behind e.g. a cookies() call. @@ -1047,9 +1047,7 @@ describe(' (runtime prefetch)', () => { ]) if (!isNextDeploy) { - expect(getCliOutput()).toMatch( - /Error: Route ".*?" used `Date\.now\(\)` instead of using `performance` or without explicitly calling `await connection\(\)` beforehand\./ - ) + expect(getCliOutput()).not.toMatch(`Date.now()`) } // Navigate to the page diff --git a/test/e2e/app-dir/use-cache/app/(dynamic)/generate-metadata/page.tsx b/test/e2e/app-dir/use-cache/app/(dynamic)/generate-metadata/page.tsx index dc213645e3f65..bf6928fbb2d34 100644 --- a/test/e2e/app-dir/use-cache/app/(dynamic)/generate-metadata/page.tsx +++ b/test/e2e/app-dir/use-cache/app/(dynamic)/generate-metadata/page.tsx @@ -6,6 +6,8 @@ export async function generateMetadata(): Promise { // TODO: Deduping with nested caches requires #78703. // 'use cache' + await connection() + return { description: new Date().toISOString(), title: await getCachedData(), diff --git a/test/production/app-dir/build-output-prerender/build-output-prerender.test.ts b/test/production/app-dir/build-output-prerender/build-output-prerender.test.ts index 2161dd1c42c30..ea0790c87b2d7 100644 --- a/test/production/app-dir/build-output-prerender/build-output-prerender.test.ts +++ b/test/production/app-dir/build-output-prerender/build-output-prerender.test.ts @@ -222,7 +222,7 @@ describe('build-output-prerender', () => { 6 | To get a more detailed stack trace and pinpoint the issue, start the app in development mode by running \`next dev\`, then open "/client" in your browser to investigate the error. Error occurred prerendering page "/client". Read more: https://nextjs.org/docs/messages/prerender-error - Error: Route "/server" used \`Math.random()\` outside of \`"use cache"\` and without explicitly calling \`await connection()\` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random + Error: Route "/server" used \`Math.random()\` before accessing either uncached data (e.g. \`fetch()\`) or Request data (e.g. \`cookies()\`, \`headers()\`, \`connection()\`, and \`searchParams\`). Accessing random values synchronously in a Server Component requires reading one of these data sources first. Alternatively, consider moving this expression into a Client Component or Cache Component. See more info here: https://nextjs.org/docs/messages/next-prerender-random at Page (bundler:///app/server/page.tsx:13:27) 11 | await cachedDelay() 12 |