diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 06b76d6e2b544..305eea8843844 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -36,6 +36,7 @@ import loadCustomRoutes, { normalizeRouteRegex, Redirect, Rewrite, + RouteHas, RouteType, } from '../lib/load-custom-routes' import { getRedirectStatus, modifyRouteRegex } from '../lib/redirect-status' @@ -130,6 +131,7 @@ import { flatReaddir } from '../lib/flat-readdir' import { eventSwcPlugins } from '../telemetry/events/swc-plugins' import { normalizeAppPath } from '../shared/lib/router/utils/app-paths' import { + ACTION, NEXT_ROUTER_PREFETCH, RSC, RSC_CONTENT_TYPE_HEADER, @@ -160,6 +162,7 @@ export type SsgRoute = { dataRoute: string | null initialStatus?: number initialHeaders?: Record + experimentalBypassFor?: RouteHas[] } export type DynamicSsgRoute = { @@ -167,6 +170,7 @@ export type DynamicSsgRoute = { fallback: string | null | false dataRoute: string | null dataRouteRegex: string | null + experimentalBypassFor?: RouteHas[] } export type PrerenderManifest = { @@ -1612,14 +1616,6 @@ export default async function build( `Using edge runtime on a page currently disables static generation for that page` ) } else { - // If a page has action and it is static, we need to - // change it to SSG to keep the worker created. - // TODO: This is a workaround for now, we should have a - // dedicated worker defined in a heuristic way. - const hasAction = entriesWithAction?.has( - 'app' + originalAppPath - ) - if ( workerResult.encodedPrerenderRoutes && workerResult.prerenderRoutes @@ -1638,47 +1634,39 @@ export default async function build( const appConfig = workerResult.appConfig || {} if (appConfig.revalidate !== 0) { - if (hasAction) { - Log.warnOnce( - `Using server actions on a page currently disables static generation for that page` + const isDynamic = isDynamicRoute(page) + const hasGenerateStaticParams = + !!workerResult.prerenderRoutes?.length + + if ( + config.output === 'export' && + isDynamic && + !hasGenerateStaticParams + ) { + throw new Error( + `Page "${page}" is missing "generateStaticParams()" so it cannot be used with "output: export" config.` ) - } else { - const isDynamic = isDynamicRoute(page) - const hasGenerateStaticParams = - !!workerResult.prerenderRoutes?.length - - if ( - config.output === 'export' && - isDynamic && - !hasGenerateStaticParams - ) { - throw new Error( - `Page "${page}" is missing "generateStaticParams()" so it cannot be used with "output: export" config.` - ) - } - - if ( - // Mark the app as static if: - // - It has no dynamic param - // - It doesn't have generateStaticParams but `dynamic` is set to - // `error` or `force-static` - !isDynamic - ) { - appStaticPaths.set(originalAppPath, [page]) - appStaticPathsEncoded.set(originalAppPath, [ - page, - ]) - isStatic = true - } else if ( - isDynamic && - !hasGenerateStaticParams && - (appConfig.dynamic === 'error' || - appConfig.dynamic === 'force-static') - ) { - appStaticPaths.set(originalAppPath, []) - appStaticPathsEncoded.set(originalAppPath, []) - isStatic = true - } + } + + if ( + // Mark the app as static if: + // - It has no dynamic param + // - It doesn't have generateStaticParams but `dynamic` is set to + // `error` or `force-static` + !isDynamic + ) { + appStaticPaths.set(originalAppPath, [page]) + appStaticPathsEncoded.set(originalAppPath, [page]) + isStatic = true + } else if ( + isDynamic && + !hasGenerateStaticParams && + (appConfig.dynamic === 'error' || + appConfig.dynamic === 'force-static') + ) { + appStaticPaths.set(originalAppPath, []) + appStaticPathsEncoded.set(originalAppPath, []) + isStatic = true } } @@ -2681,6 +2669,17 @@ export default async function build( const isRouteHandler = isAppRouteRoute(originalAppPath) + // this flag is used to selectively bypass the static cache and invoke the lambda directly + // to enable server actions on static routes + const bypassFor: RouteHas[] = [ + { type: 'header', key: ACTION }, + { + type: 'header', + key: 'content-type', + value: 'multipart/form-data', + }, + ] + routes.forEach((route) => { if (isDynamicRoute(page) && route === page) return if (route === '/_not-found') return @@ -2708,10 +2707,7 @@ export default async function build( ? null : path.posix.join(`${normalizedRoute}.rsc`) - const routeMeta: { - initialStatus?: SsgRoute['initialStatus'] - initialHeaders?: SsgRoute['initialHeaders'] - } = {} + const routeMeta: Partial = {} const exportRouteMeta: { status?: number @@ -2748,6 +2744,7 @@ export default async function build( finalPrerenderRoutes[route] = { ...routeMeta, + experimentalBypassFor: bypassFor, initialRevalidateSeconds: revalidate, srcRoute: page, dataRoute, @@ -2771,6 +2768,7 @@ export default async function build( // TODO: create a separate manifest to allow enforcing // dynamicParams for non-static paths? finalDynamicRoutes[page] = { + experimentalBypassFor: bypassFor, routeRegex: normalizeRouteRegex( getNamedRouteRegex(page, false).re.source ), diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 11c094e6691de..cd0d1c5d279c8 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -187,6 +187,16 @@ export async function renderToHTMLOrFlight( appDirDevErrorLogger, } = renderOpts + // We need to expose the bundled `require` API globally for + // react-server-dom-webpack. This is a hack until we find a better way. + if (ComponentMod.__next_app__) { + // @ts-ignore + globalThis.__next_require__ = ComponentMod.__next_app__.require + + // @ts-ignore + globalThis.__next_chunk_load__ = ComponentMod.__next_app__.loadChunk + } + const extraRenderResultMeta: RenderResultMetadata = {} const appUsingSizeAdjust = !!nextFontManifest?.appUsingSizeAdjust diff --git a/packages/next/src/server/app-render/create-server-components-renderer.tsx b/packages/next/src/server/app-render/create-server-components-renderer.tsx index 0d11231ed110d..dbee850836d45 100644 --- a/packages/next/src/server/app-render/create-server-components-renderer.tsx +++ b/packages/next/src/server/app-render/create-server-components-renderer.tsx @@ -34,16 +34,6 @@ export function createServerComponentRenderer( serverComponentsErrorHandler: ReturnType, nonce?: string ): (props: Props) => JSX.Element { - // We need to expose the bundled `require` API globally for - // react-server-dom-webpack. This is a hack until we find a better way. - if (ComponentMod.__next_app__) { - // @ts-ignore - globalThis.__next_require__ = ComponentMod.__next_app__.require - - // @ts-ignore - globalThis.__next_chunk_load__ = ComponentMod.__next_app__.loadChunk - } - let RSCStream: ReadableStream const createRSCStream = (props: Props) => { if (!RSCStream) { diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index d5adfc9de38b4..76a8fc98cadb1 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -15,6 +15,7 @@ export type StaticGenerationContext = { nextExport?: boolean fetchCache?: StaticGenerationStore['fetchCache'] isDraftMode?: boolean + isServerAction?: boolean /** * A hack around accessing the store value outside the context of the @@ -49,11 +50,15 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper< * * 3.) If the request is in draft mode, we must generate dynamic HTML. * + * 4.) If the request is a server action, we must generate dynamic HTML. + * * These rules help ensure that other existing features like request caching, * coalescing, and ISR continue working as intended. */ const isStaticGeneration = - !renderOpts.supportsDynamicHTML && !renderOpts.isDraftMode + !renderOpts.supportsDynamicHTML && + !renderOpts.isDraftMode && + !renderOpts.isServerAction const store: StaticGenerationStore = { isStaticGeneration, diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index e7b8473908401..10bf0c1a9bbd3 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -85,6 +85,7 @@ import { RSC_VARY_HEADER, FLIGHT_PARAMETERS, NEXT_RSC_UNION_QUERY, + ACTION, NEXT_ROUTER_PREFETCH, RSC_CONTENT_TYPE_HEADER, } from '../client/components/app-router-headers' @@ -1588,7 +1589,15 @@ export default abstract class Server { const isAppPath = components.isAppPath === true const hasServerProps = !!components.getServerSideProps let hasStaticPaths = !!components.getStaticPaths - + const actionId = req.headers[ACTION.toLowerCase()] as string + const contentType = req.headers['content-type'] + const isMultipartAction = + req.method === 'POST' && contentType?.startsWith('multipart/form-data') + const isFetchAction = + actionId !== undefined && + typeof actionId === 'string' && + req.method === 'POST' + const isServerAction = isFetchAction || isMultipartAction const hasGetInitialProps = !!components.Component?.getInitialProps let isSSG = !!components.getStaticProps @@ -1725,6 +1734,7 @@ export default abstract class Server { // requests so ensure we respond with 405 for // invalid requests if ( + !isServerAction && !is404Page && !is500Page && pathname !== '/_error' && @@ -1879,8 +1889,8 @@ export default abstract class Server { } let ssgCacheKey = - isPreviewMode || !isSSG || opts.supportsDynamicHTML - ? null // Preview mode, on-demand revalidate, flight request can bypass the cache + isPreviewMode || !isSSG || opts.supportsDynamicHTML || isServerAction + ? null // Preview mode, on-demand revalidate, server actions, flight request can bypass the cache : `${locale ? `/${locale}` : ''}${ (pathname === '/' || resolvedUrlPathname === '/') && locale ? '' @@ -1996,6 +2006,7 @@ export default abstract class Server { supportsDynamicHTML, isOnDemandRevalidate, isDraftMode: isPreviewMode, + isServerAction, } // Legacy render methods will return a render result that needs to be diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 0cd5c24f09245..228ed9172227e 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -274,6 +274,7 @@ export type RenderOptsPartial = { strictNextHead: boolean isDraftMode?: boolean deploymentId?: string + isServerAction?: boolean } export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial diff --git a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts index d44ea986cad65..b8f14648cbb57 100644 --- a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts +++ b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts @@ -70,7 +70,7 @@ export function appendMutableCookies( } // Return a new response that extends the response with - // the modified cookies as fallbacks. `res`' cookies + // the modified cookies as fallbacks. `res` cookies // will still take precedence. const resCookies = new ResponseCookies(headers) const returnedCookies = resCookies.getAll() diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 3048856ed2af6..e2a61af7f30cd 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -20,14 +20,6 @@ createNextDescribe( }, }, ({ next, isNextDev, isNextStart, isNextDeploy }) => { - if (isNextStart) { - it('should warn for server actions + ISR incompat', async () => { - expect(next.cliOutput).toContain( - 'Using server actions on a page currently disables static generation for that page' - ) - }) - } - it('should handle basic actions correctly', async () => { const browser = await next.browser('/server') @@ -499,6 +491,17 @@ createNextDescribe( }) describe('fetch actions', () => { + it('should handle a fetch action initiated from a static page', async () => { + const browser = await next.browser('/client-static') + await check(() => browser.elementByCss('#count').text(), '0') + + await browser.elementByCss('#increment').click() + await check(() => browser.elementByCss('#count').text(), '1') + + await browser.elementByCss('#increment').click() + await check(() => browser.elementByCss('#count').text(), '2') + }) + it('should handle redirect to a relative URL in a single pass', async () => { const browser = await next.browser('/client') diff --git a/test/e2e/app-dir/actions/app/client-static/[[...path]]/page.js b/test/e2e/app-dir/actions/app/client-static/[[...path]]/page.js new file mode 100644 index 0000000000000..d6e70a48be223 --- /dev/null +++ b/test/e2e/app-dir/actions/app/client-static/[[...path]]/page.js @@ -0,0 +1,16 @@ +import { Counter } from '../../../components/Counter' +import { incrementCounter } from '../actions' + +export default function Page() { + return ( +
+ +
+ ) +} + +export const revalidate = 60 + +export async function generateStaticParams() { + return [{ path: ['asdf'] }] +} diff --git a/test/e2e/app-dir/actions/app/client-static/actions.js b/test/e2e/app-dir/actions/app/client-static/actions.js new file mode 100644 index 0000000000000..6af73c620fcf0 --- /dev/null +++ b/test/e2e/app-dir/actions/app/client-static/actions.js @@ -0,0 +1,10 @@ +'use server' + +let counter = 0 + +export async function incrementCounter() { + console.log('Button clicked!') + + counter++ + return counter +} diff --git a/test/e2e/app-dir/actions/app/client-static/layout.js b/test/e2e/app-dir/actions/app/client-static/layout.js new file mode 100644 index 0000000000000..df3717d33e78f --- /dev/null +++ b/test/e2e/app-dir/actions/app/client-static/layout.js @@ -0,0 +1,3 @@ +export default function Layout({ children }) { + return children +} diff --git a/test/e2e/app-dir/actions/components/Counter.tsx b/test/e2e/app-dir/actions/components/Counter.tsx new file mode 100644 index 0000000000000..a16ff45a0e0e3 --- /dev/null +++ b/test/e2e/app-dir/actions/components/Counter.tsx @@ -0,0 +1,20 @@ +'use client' +import React from 'react' + +export function Counter({ onClick }) { + const [count, setCount] = React.useState(0) + return ( + <> +

{count}

+ + + ) +} diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index cf880727952a1..ea05292513bac 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -734,315 +734,848 @@ createNextDescribe( } expect(curManifest.version).toBe(4) - expect(curManifest.routes).toEqual({ - '/': { - initialRevalidateSeconds: false, - srcRoute: '/', - dataRoute: '/index.rsc', - }, - '/blog/tim': { - initialRevalidateSeconds: 10, - srcRoute: '/blog/[author]', - dataRoute: '/blog/tim.rsc', - }, - '/blog/seb': { - initialRevalidateSeconds: 10, - srcRoute: '/blog/[author]', - dataRoute: '/blog/seb.rsc', - }, - '/blog/styfle': { - initialRevalidateSeconds: 10, - srcRoute: '/blog/[author]', - dataRoute: '/blog/styfle.rsc', - }, - '/blog/tim/first-post': { - initialRevalidateSeconds: false, - srcRoute: '/blog/[author]/[slug]', - dataRoute: '/blog/tim/first-post.rsc', - }, - '/blog/seb/second-post': { - initialRevalidateSeconds: false, - srcRoute: '/blog/[author]/[slug]', - dataRoute: '/blog/seb/second-post.rsc', - }, - '/blog/styfle/first-post': { - initialRevalidateSeconds: false, - srcRoute: '/blog/[author]/[slug]', - dataRoute: '/blog/styfle/first-post.rsc', - }, - '/blog/styfle/second-post': { - initialRevalidateSeconds: false, - srcRoute: '/blog/[author]/[slug]', - dataRoute: '/blog/styfle/second-post.rsc', - }, - '/force-cache': { - dataRoute: '/force-cache.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/force-cache', - }, - '/hooks/use-pathname/slug': { - dataRoute: '/hooks/use-pathname/slug.rsc', - initialRevalidateSeconds: false, - srcRoute: '/hooks/use-pathname/[slug]', - }, - '/hooks/use-search-params': { - dataRoute: '/hooks/use-search-params.rsc', - initialRevalidateSeconds: false, - srcRoute: '/hooks/use-search-params', - }, - '/hooks/use-search-params/force-static': { - dataRoute: '/hooks/use-search-params/force-static.rsc', - initialRevalidateSeconds: false, - srcRoute: '/hooks/use-search-params/force-static', - }, - '/hooks/use-search-params/with-suspense': { - dataRoute: '/hooks/use-search-params/with-suspense.rsc', - initialRevalidateSeconds: false, - srcRoute: '/hooks/use-search-params/with-suspense', - }, - '/partial-gen-params-no-additional-lang/en/RAND': { - dataRoute: '/partial-gen-params-no-additional-lang/en/RAND.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-lang/en/first': { - dataRoute: '/partial-gen-params-no-additional-lang/en/first.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-lang/en/second': { - dataRoute: '/partial-gen-params-no-additional-lang/en/second.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-lang/fr/RAND': { - dataRoute: '/partial-gen-params-no-additional-lang/fr/RAND.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-lang/fr/first': { - dataRoute: '/partial-gen-params-no-additional-lang/fr/first.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-lang/fr/second': { - dataRoute: '/partial-gen-params-no-additional-lang/fr/second.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-lang/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/en/RAND': { - dataRoute: '/partial-gen-params-no-additional-slug/en/RAND.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/en/first': { - dataRoute: '/partial-gen-params-no-additional-slug/en/first.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/en/second': { - dataRoute: '/partial-gen-params-no-additional-slug/en/second.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/fr/RAND': { - dataRoute: '/partial-gen-params-no-additional-slug/fr/RAND.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/fr/first': { - dataRoute: '/partial-gen-params-no-additional-slug/fr/first.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/partial-gen-params-no-additional-slug/fr/second': { - dataRoute: '/partial-gen-params-no-additional-slug/fr/second.rsc', - initialRevalidateSeconds: false, - srcRoute: '/partial-gen-params-no-additional-slug/[lang]/[slug]', - }, - '/ssg-draft-mode': { - dataRoute: '/ssg-draft-mode.rsc', - initialRevalidateSeconds: false, - srcRoute: '/ssg-draft-mode/[[...route]]', - }, - '/ssg-draft-mode/test': { - dataRoute: '/ssg-draft-mode/test.rsc', - initialRevalidateSeconds: false, - srcRoute: '/ssg-draft-mode/[[...route]]', - }, - '/ssg-draft-mode/test-2': { - dataRoute: '/ssg-draft-mode/test-2.rsc', - initialRevalidateSeconds: false, - srcRoute: '/ssg-draft-mode/[[...route]]', - }, - '/force-static/first': { - dataRoute: '/force-static/first.rsc', - initialRevalidateSeconds: false, - srcRoute: '/force-static/[slug]', - }, - '/force-static/second': { - dataRoute: '/force-static/second.rsc', - initialRevalidateSeconds: false, - srcRoute: '/force-static/[slug]', - }, - '/gen-params-dynamic-revalidate/one': { - dataRoute: '/gen-params-dynamic-revalidate/one.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/gen-params-dynamic-revalidate/[slug]', - }, - '/route-handler/revalidate-360-isr': { - dataRoute: null, - initialHeaders: { - 'content-type': 'application/json', - 'x-next-cache-tags': - 'thankyounext,_N_T_/layout,_N_T_/route-handler/layout,_N_T_/route-handler/revalidate-360-isr/layout,_N_T_/route-handler/revalidate-360-isr/route,_N_T_/route-handler/revalidate-360-isr', + expect(curManifest.routes).toMatchInlineSnapshot(` + Object { + "/": Object { + "dataRoute": "/index.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/", }, - initialRevalidateSeconds: 10, - srcRoute: '/route-handler/revalidate-360-isr', - }, - '/route-handler/static-cookies': { - dataRoute: null, - initialHeaders: { - 'set-cookie': 'theme=light; Path=/,my_company=ACME; Path=/', - 'x-next-cache-tags': - '_N_T_/layout,_N_T_/route-handler/layout,_N_T_/route-handler/static-cookies/layout,_N_T_/route-handler/static-cookies/route,_N_T_/route-handler/static-cookies', + "/blog/seb": Object { + "dataRoute": "/blog/seb.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/blog/[author]", }, - initialRevalidateSeconds: false, - srcRoute: '/route-handler/static-cookies', - }, - '/variable-config-revalidate/revalidate-3': { - dataRoute: '/variable-config-revalidate/revalidate-3.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/variable-config-revalidate/revalidate-3', - }, - '/variable-revalidate/authorization': { - dataRoute: '/variable-revalidate/authorization.rsc', - initialRevalidateSeconds: 10, - srcRoute: '/variable-revalidate/authorization', - }, - '/variable-revalidate/cookie': { - dataRoute: '/variable-revalidate/cookie.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/variable-revalidate/cookie', - }, - '/variable-revalidate/encoding': { - dataRoute: '/variable-revalidate/encoding.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/variable-revalidate/encoding', - }, - '/variable-revalidate/headers-instance': { - dataRoute: '/variable-revalidate/headers-instance.rsc', - initialRevalidateSeconds: 10, - srcRoute: '/variable-revalidate/headers-instance', - }, - '/variable-revalidate/post-method': { - dataRoute: '/variable-revalidate/post-method.rsc', - initialRevalidateSeconds: 10, - srcRoute: '/variable-revalidate/post-method', - }, - '/variable-revalidate/revalidate-3': { - dataRoute: '/variable-revalidate/revalidate-3.rsc', - initialRevalidateSeconds: 3, - srcRoute: '/variable-revalidate/revalidate-3', - }, - '/variable-revalidate/revalidate-360-isr': { - dataRoute: '/variable-revalidate/revalidate-360-isr.rsc', - initialRevalidateSeconds: 10, - srcRoute: '/variable-revalidate/revalidate-360-isr', - }, - }) - expect(curManifest.dynamicRoutes).toEqual({ - '/blog/[author]/[slug]': { - routeRegex: normalizeRegEx('^/blog/([^/]+?)/([^/]+?)(?:/)?$'), - dataRoute: '/blog/[author]/[slug].rsc', - fallback: null, - dataRouteRegex: normalizeRegEx('^/blog/([^/]+?)/([^/]+?)\\.rsc$'), - }, - '/blog/[author]': { - dataRoute: '/blog/[author].rsc', - dataRouteRegex: normalizeRegEx('^\\/blog\\/([^\\/]+?)\\.rsc$'), - fallback: false, - routeRegex: normalizeRegEx('^\\/blog\\/([^\\/]+?)(?:\\/)?$'), - }, - '/dynamic-error/[id]': { - dataRoute: '/dynamic-error/[id].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/dynamic\\-error\\/([^\\/]+?)\\.rsc$' - ), - fallback: null, - routeRegex: normalizeRegEx( - '^\\/dynamic\\-error\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/gen-params-dynamic-revalidate/[slug]': { - dataRoute: '/gen-params-dynamic-revalidate/[slug].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)\\.rsc$' - ), - fallback: null, - routeRegex: normalizeRegEx( - '^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/hooks/use-pathname/[slug]': { - dataRoute: '/hooks/use-pathname/[slug].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/hooks\\/use\\-pathname\\/([^\\/]+?)\\.rsc$' - ), - fallback: null, - routeRegex: normalizeRegEx( - '^\\/hooks\\/use\\-pathname\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/partial-gen-params-no-additional-lang/[lang]/[slug]': { - dataRoute: - '/partial-gen-params-no-additional-lang/[lang]/[slug].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/partial\\-gen\\-params\\-no\\-additional\\-lang\\/([^\\/]+?)\\/([^\\/]+?)\\.rsc$' - ), - fallback: false, - routeRegex: normalizeRegEx( - '^\\/partial\\-gen\\-params\\-no\\-additional\\-lang\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/partial-gen-params-no-additional-slug/[lang]/[slug]': { - dataRoute: - '/partial-gen-params-no-additional-slug/[lang]/[slug].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/partial\\-gen\\-params\\-no\\-additional\\-slug\\/([^\\/]+?)\\/([^\\/]+?)\\.rsc$' - ), - fallback: false, - routeRegex: normalizeRegEx( - '^\\/partial\\-gen\\-params\\-no\\-additional\\-slug\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/ssg-draft-mode/[[...route]]': { - dataRoute: '/ssg-draft-mode/[[...route]].rsc', - dataRouteRegex: '^\\/ssg\\-draft\\-mode(?:\\/(.+?))?\\.rsc$', - fallback: null, - routeRegex: '^\\/ssg\\-draft\\-mode(?:\\/(.+?))?(?:\\/)?$', - }, - '/force-static/[slug]': { - dataRoute: '/force-static/[slug].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/force\\-static\\/([^\\/]+?)\\.rsc$' - ), - fallback: null, - routeRegex: normalizeRegEx( - '^\\/force\\-static\\/([^\\/]+?)(?:\\/)?$' - ), - }, - '/static-to-dynamic-error-forced/[id]': { - dataRoute: '/static-to-dynamic-error-forced/[id].rsc', - dataRouteRegex: normalizeRegEx( - '^\\/static\\-to\\-dynamic\\-error\\-forced\\/([^\\/]+?)\\.rsc$' - ), - fallback: null, - routeRegex: normalizeRegEx( - '^\\/static\\-to\\-dynamic\\-error\\-forced\\/([^\\/]+?)(?:\\/)?$' - ), - }, - }) + "/blog/seb/second-post": Object { + "dataRoute": "/blog/seb/second-post.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/blog/[author]/[slug]", + }, + "/blog/styfle": Object { + "dataRoute": "/blog/styfle.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/blog/[author]", + }, + "/blog/styfle/first-post": Object { + "dataRoute": "/blog/styfle/first-post.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/blog/[author]/[slug]", + }, + "/blog/styfle/second-post": Object { + "dataRoute": "/blog/styfle/second-post.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/blog/[author]/[slug]", + }, + "/blog/tim": Object { + "dataRoute": "/blog/tim.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/blog/[author]", + }, + "/blog/tim/first-post": Object { + "dataRoute": "/blog/tim/first-post.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/blog/[author]/[slug]", + }, + "/force-cache": Object { + "dataRoute": "/force-cache.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/force-cache", + }, + "/force-static/first": Object { + "dataRoute": "/force-static/first.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/force-static/[slug]", + }, + "/force-static/second": Object { + "dataRoute": "/force-static/second.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/force-static/[slug]", + }, + "/gen-params-dynamic-revalidate/one": Object { + "dataRoute": "/gen-params-dynamic-revalidate/one.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/gen-params-dynamic-revalidate/[slug]", + }, + "/hooks/use-pathname/slug": Object { + "dataRoute": "/hooks/use-pathname/slug.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/hooks/use-pathname/[slug]", + }, + "/hooks/use-search-params": Object { + "dataRoute": "/hooks/use-search-params.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/hooks/use-search-params", + }, + "/hooks/use-search-params/force-static": Object { + "dataRoute": "/hooks/use-search-params/force-static.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/hooks/use-search-params/force-static", + }, + "/hooks/use-search-params/with-suspense": Object { + "dataRoute": "/hooks/use-search-params/with-suspense.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/hooks/use-search-params/with-suspense", + }, + "/partial-gen-params-no-additional-lang/en/RAND": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/en/RAND.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-lang/en/first": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/en/first.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-lang/en/second": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/en/second.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-lang/fr/RAND": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/fr/RAND.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-lang/fr/first": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/fr/first.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-lang/fr/second": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/fr/second.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/en/RAND": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/en/RAND.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/en/first": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/en/first.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/en/second": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/en/second.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/fr/RAND": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/fr/RAND.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/fr/first": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/fr/first.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/partial-gen-params-no-additional-slug/fr/second": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/fr/second.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug]", + }, + "/route-handler/revalidate-360-isr": Object { + "dataRoute": null, + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialHeaders": Object { + "content-type": "application/json", + "x-next-cache-tags": "thankyounext,_N_T_/layout,_N_T_/route-handler/layout,_N_T_/route-handler/revalidate-360-isr/layout,_N_T_/route-handler/revalidate-360-isr/route,_N_T_/route-handler/revalidate-360-isr", + }, + "initialRevalidateSeconds": 10, + "srcRoute": "/route-handler/revalidate-360-isr", + }, + "/route-handler/static-cookies": Object { + "dataRoute": null, + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialHeaders": Object { + "set-cookie": "theme=light; Path=/,my_company=ACME; Path=/", + "x-next-cache-tags": "_N_T_/layout,_N_T_/route-handler/layout,_N_T_/route-handler/static-cookies/layout,_N_T_/route-handler/static-cookies/route,_N_T_/route-handler/static-cookies", + }, + "initialRevalidateSeconds": false, + "srcRoute": "/route-handler/static-cookies", + }, + "/ssg-draft-mode": Object { + "dataRoute": "/ssg-draft-mode.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/ssg-draft-mode/[[...route]]", + }, + "/ssg-draft-mode/test": Object { + "dataRoute": "/ssg-draft-mode/test.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/ssg-draft-mode/[[...route]]", + }, + "/ssg-draft-mode/test-2": Object { + "dataRoute": "/ssg-draft-mode/test-2.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": false, + "srcRoute": "/ssg-draft-mode/[[...route]]", + }, + "/variable-config-revalidate/revalidate-3": Object { + "dataRoute": "/variable-config-revalidate/revalidate-3.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/variable-config-revalidate/revalidate-3", + }, + "/variable-revalidate/authorization": Object { + "dataRoute": "/variable-revalidate/authorization.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/variable-revalidate/authorization", + }, + "/variable-revalidate/cookie": Object { + "dataRoute": "/variable-revalidate/cookie.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/variable-revalidate/cookie", + }, + "/variable-revalidate/encoding": Object { + "dataRoute": "/variable-revalidate/encoding.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/variable-revalidate/encoding", + }, + "/variable-revalidate/headers-instance": Object { + "dataRoute": "/variable-revalidate/headers-instance.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/variable-revalidate/headers-instance", + }, + "/variable-revalidate/post-method": Object { + "dataRoute": "/variable-revalidate/post-method.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/variable-revalidate/post-method", + }, + "/variable-revalidate/revalidate-3": Object { + "dataRoute": "/variable-revalidate/revalidate-3.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 3, + "srcRoute": "/variable-revalidate/revalidate-3", + }, + "/variable-revalidate/revalidate-360-isr": Object { + "dataRoute": "/variable-revalidate/revalidate-360-isr.rsc", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "initialRevalidateSeconds": 10, + "srcRoute": "/variable-revalidate/revalidate-360-isr", + }, + } + `) + expect(curManifest.dynamicRoutes).toMatchInlineSnapshot(` + Object { + "/blog/[author]": Object { + "dataRoute": "/blog/[author].rsc", + "dataRouteRegex": "^\\\\/blog\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": false, + "routeRegex": "^\\\\/blog\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/blog/[author]/[slug]": Object { + "dataRoute": "/blog/[author]/[slug].rsc", + "dataRouteRegex": "^\\\\/blog\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/blog\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/dynamic-error/[id]": Object { + "dataRoute": "/dynamic-error/[id].rsc", + "dataRouteRegex": "^\\\\/dynamic\\\\-error\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/dynamic\\\\-error\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/force-static/[slug]": Object { + "dataRoute": "/force-static/[slug].rsc", + "dataRouteRegex": "^\\\\/force\\\\-static\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/force\\\\-static\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/gen-params-dynamic-revalidate/[slug]": Object { + "dataRoute": "/gen-params-dynamic-revalidate/[slug].rsc", + "dataRouteRegex": "^\\\\/gen\\\\-params\\\\-dynamic\\\\-revalidate\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/gen\\\\-params\\\\-dynamic\\\\-revalidate\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/hooks/use-pathname/[slug]": Object { + "dataRoute": "/hooks/use-pathname/[slug].rsc", + "dataRouteRegex": "^\\\\/hooks\\\\/use\\\\-pathname\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/hooks\\\\/use\\\\-pathname\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/partial-gen-params-no-additional-lang/[lang]/[slug]": Object { + "dataRoute": "/partial-gen-params-no-additional-lang/[lang]/[slug].rsc", + "dataRouteRegex": "^\\\\/partial\\\\-gen\\\\-params\\\\-no\\\\-additional\\\\-lang\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": false, + "routeRegex": "^\\\\/partial\\\\-gen\\\\-params\\\\-no\\\\-additional\\\\-lang\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/partial-gen-params-no-additional-slug/[lang]/[slug]": Object { + "dataRoute": "/partial-gen-params-no-additional-slug/[lang]/[slug].rsc", + "dataRouteRegex": "^\\\\/partial\\\\-gen\\\\-params\\\\-no\\\\-additional\\\\-slug\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": false, + "routeRegex": "^\\\\/partial\\\\-gen\\\\-params\\\\-no\\\\-additional\\\\-slug\\\\/([^\\\\/]+?)\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + "/ssg-draft-mode/[[...route]]": Object { + "dataRoute": "/ssg-draft-mode/[[...route]].rsc", + "dataRouteRegex": "^\\\\/ssg\\\\-draft\\\\-mode(?:\\\\/(.+?))?\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/ssg\\\\-draft\\\\-mode(?:\\\\/(.+?))?(?:\\\\/)?$", + }, + "/static-to-dynamic-error-forced/[id]": Object { + "dataRoute": "/static-to-dynamic-error-forced/[id].rsc", + "dataRouteRegex": "^\\\\/static\\\\-to\\\\-dynamic\\\\-error\\\\-forced\\\\/([^\\\\/]+?)\\\\.rsc$", + "experimentalBypassFor": Array [ + Object { + "key": "Next-Action", + "type": "header", + }, + Object { + "key": "content-type", + "type": "header", + "value": "multipart/form-data", + }, + ], + "fallback": null, + "routeRegex": "^\\\\/static\\\\-to\\\\-dynamic\\\\-error\\\\-forced\\\\/([^\\\\/]+?)(?:\\\\/)?$", + }, + } + `) }) it('should output debug info for static bailouts', async () => {