vinext 0.0.53 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/build/inline-css.d.ts +7 -0
- package/dist/build/inline-css.js +50 -0
- package/dist/build/inline-css.js.map +1 -0
- package/dist/build/prerender.js +2 -1
- package/dist/build/prerender.js.map +1 -1
- package/dist/check.js +19 -3
- package/dist/check.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +3 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/window-next.d.ts +7 -0
- package/dist/client/window-next.js.map +1 -1
- package/dist/config/next-config.d.ts +97 -2
- package/dist/config/next-config.js +155 -6
- package/dist/config/next-config.js.map +1 -1
- package/dist/config/tsconfig-paths.d.ts +12 -3
- package/dist/config/tsconfig-paths.js +55 -24
- package/dist/config/tsconfig-paths.js.map +1 -1
- package/dist/deploy.js +13 -0
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +11 -1
- package/dist/entries/app-browser-entry.js +16 -6
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +9 -1
- package/dist/entries/app-rsc-entry.js +30 -5
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +21 -1
- package/dist/entries/app-rsc-manifest.js +28 -9
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +4 -1
- package/dist/entries/pages-client-entry.js +18 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +123 -8
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +1 -10
- package/dist/entries/runtime-entry-module.js +2 -12
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +144 -44
- package/dist/index.js.map +1 -1
- package/dist/plugins/import-meta-url.d.ts +16 -0
- package/dist/plugins/import-meta-url.js +193 -0
- package/dist/plugins/import-meta-url.js.map +1 -0
- package/dist/plugins/remove-console.d.ts +16 -0
- package/dist/plugins/remove-console.js +176 -0
- package/dist/plugins/remove-console.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +24 -1
- package/dist/routing/app-route-graph.js +52 -4
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +21 -1
- package/dist/routing/file-matcher.js +39 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +1 -1
- package/dist/routing/pages-router.js +10 -3
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-browser-action-result.d.ts +9 -16
- package/dist/server/app-browser-action-result.js +25 -14
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +195 -60
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-mpa-navigation.d.ts +16 -0
- package/dist/server/app-browser-mpa-navigation.js +36 -0
- package/dist/server/app-browser-mpa-navigation.js.map +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +4 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-popstate.d.ts +3 -1
- package/dist/server/app-browser-popstate.js +15 -1
- package/dist/server/app-browser-popstate.js.map +1 -1
- package/dist/server/app-browser-state.js +2 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +13 -4
- package/dist/server/app-elements-wire.js +10 -1
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +15 -5
- package/dist/server/app-fallback-renderer.js +10 -4
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-inline-css-client.d.ts +7 -0
- package/dist/server/app-inline-css-client.js +37 -0
- package/dist/server/app-inline-css-client.js.map +1 -0
- package/dist/server/app-layout-param-observation.d.ts +30 -0
- package/dist/server/app-layout-param-observation.js +130 -0
- package/dist/server/app-layout-param-observation.js.map +1 -0
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +21 -1
- package/dist/server/app-page-boundary.js +28 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +7 -3
- package/dist/server/app-page-cache.js +7 -7
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +126 -79
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.js +12 -28
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-params.d.ts +2 -1
- package/dist/server/app-page-params.js +14 -1
- package/dist/server/app-page-params.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +12 -1
- package/dist/server/app-page-probe.js +116 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render-identity.d.ts +22 -0
- package/dist/server/app-page-render-identity.js +42 -0
- package/dist/server/app-page-render-identity.js.map +1 -0
- package/dist/server/app-page-render.d.ts +8 -1
- package/dist/server/app-page-render.js +4 -1
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +6 -3
- package/dist/server/app-page-request.js +5 -2
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +15 -0
- package/dist/server/app-page-route-wiring.js +7 -5
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +11 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +37 -5
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +3 -2
- package/dist/server/app-rsc-cache-busting.js +9 -7
- package/dist/server/app-rsc-cache-busting.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +14 -3
- package/dist/server/app-rsc-handler.js +56 -6
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +2 -1
- package/dist/server/app-rsc-request-normalization.js +3 -2
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +1 -1
- package/dist/server/app-segment-config.js +4 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +26 -3
- package/dist/server/app-server-action-execution.js +240 -29
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +22 -7
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.js +3 -3
- package/dist/server/app-ssr-error-meta.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +2 -1
- package/dist/server/app-ssr-stream.js +176 -31
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +2 -1
- package/dist/server/artifact-compatibility.js +10 -1
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/client-reuse-manifest.d.ts +9 -4
- package/dist/server/client-reuse-manifest.js +2 -1
- package/dist/server/client-reuse-manifest.js.map +1 -1
- package/dist/server/client-trace-metadata.d.ts +31 -0
- package/dist/server/client-trace-metadata.js +83 -0
- package/dist/server/client-trace-metadata.js.map +1 -0
- package/dist/server/cookie-utils.d.ts +13 -0
- package/dist/server/cookie-utils.js +20 -0
- package/dist/server/cookie-utils.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +83 -12
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/document-initial-head.d.ts +7 -0
- package/dist/server/document-initial-head.js +35 -0
- package/dist/server/document-initial-head.js.map +1 -0
- package/dist/server/html.d.ts +2 -1
- package/dist/server/html.js +6 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/isr-cache.d.ts +7 -5
- package/dist/server/isr-cache.js +17 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.js +1 -2
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/pages-document-initial-props.d.ts +89 -0
- package/dist/server/pages-document-initial-props.js +140 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-node-compat.js +1 -1
- package/dist/server/pages-page-data.js +3 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-method.d.ts +48 -0
- package/dist/server/pages-page-method.js +19 -0
- package/dist/server/pages-page-method.js.map +1 -0
- package/dist/server/pages-page-response.d.ts +20 -0
- package/dist/server/pages-page-response.js +37 -7
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/pages-serializable-props.d.ts +25 -0
- package/dist/server/pages-serializable-props.js +69 -0
- package/dist/server/pages-serializable-props.js.map +1 -0
- package/dist/server/prod-server.js +16 -6
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -2
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/skip-cache-proof.d.ts +23 -2
- package/dist/server/skip-cache-proof.js +81 -12
- package/dist/server/skip-cache-proof.js.map +1 -1
- package/dist/server/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/static-layout-client-reuse-proof.d.ts +16 -0
- package/dist/server/static-layout-client-reuse-proof.js +35 -0
- package/dist/server/static-layout-client-reuse-proof.js.map +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +4 -2
- package/dist/shims/app-router-scroll-state.js +16 -3
- package/dist/shims/app-router-scroll-state.js.map +1 -1
- package/dist/shims/app-router-scroll.d.ts +16 -2
- package/dist/shims/app-router-scroll.js +18 -3
- package/dist/shims/app-router-scroll.js.map +1 -1
- package/dist/shims/cache.d.ts +27 -1
- package/dist/shims/cache.js +108 -6
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/document.d.ts +6 -0
- package/dist/shims/document.js +7 -8
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error-boundary.js +27 -28
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +16 -5
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/hash-scroll.d.ts +4 -1
- package/dist/shims/hash-scroll.js +13 -1
- package/dist/shims/hash-scroll.js.map +1 -1
- package/dist/shims/head-state.d.ts +1 -0
- package/dist/shims/head-state.js +18 -3
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +35 -1
- package/dist/shims/head.js +113 -14
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +7 -0
- package/dist/shims/headers.js +9 -1
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/internal/app-route-detection.d.ts +37 -0
- package/dist/shims/internal/app-route-detection.js +69 -0
- package/dist/shims/internal/app-route-detection.js.map +1 -0
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +56 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js +70 -0
- package/dist/shims/internal/pages-data-fetch-dedup.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +98 -8
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +7 -6
- package/dist/shims/metadata.js +9 -5
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +40 -3
- package/dist/shims/navigation.js +124 -25
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +51 -21
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +75 -6
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -2
- package/dist/shims/thenable-params.js +25 -1
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +3 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/client-build-manifest.d.ts +15 -0
- package/dist/utils/client-build-manifest.js +54 -0
- package/dist/utils/client-build-manifest.js.map +1 -0
- package/dist/utils/hash.js +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/path.d.ts +13 -0
- package/dist/utils/path.js +16 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/vite-version.d.ts +11 -0
- package/dist/utils/vite-version.js +36 -0
- package/dist/utils/vite-version.js.map +1 -0
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@ import { normalizeStaticPathname } from "../routing/route-pattern.js";
|
|
|
2
2
|
import { buildCacheStateHeaders } from "./cache-headers.js";
|
|
3
3
|
import { buildPagesCacheValue } from "./isr-cache.js";
|
|
4
4
|
import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
|
|
5
|
+
import { isSerializableProps } from "./pages-serializable-props.js";
|
|
5
6
|
import { buildCachedRevalidateCacheControl } from "./cache-control.js";
|
|
6
7
|
import { buildPagesNextDataScript } from "./pages-page-response.js";
|
|
7
8
|
//#region src/server/pages-page-data.ts
|
|
@@ -136,6 +137,7 @@ async function resolvePagesPageData(options) {
|
|
|
136
137
|
kind: "response",
|
|
137
138
|
response: options.isDataReq ? buildPagesDataNotFoundResponse() : buildPagesNotFoundResponse()
|
|
138
139
|
};
|
|
140
|
+
if (result?.props !== void 0) isSerializableProps(options.routePattern, "getServerSideProps", pageProps);
|
|
139
141
|
gsspRes = res;
|
|
140
142
|
}
|
|
141
143
|
let isrRevalidateSeconds = null;
|
|
@@ -204,6 +206,7 @@ async function resolvePagesPageData(options) {
|
|
|
204
206
|
kind: "response",
|
|
205
207
|
response: options.isDataReq ? buildPagesDataNotFoundResponse() : buildPagesNotFoundResponse()
|
|
206
208
|
};
|
|
209
|
+
if (result?.props !== void 0) isSerializableProps(options.routePattern, "getStaticProps", pageProps);
|
|
207
210
|
if (typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
|
|
208
211
|
}
|
|
209
212
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages-page-data.js","names":[],"sources":["../../src/server/pages-page-data.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { normalizeStaticPathname } from \"../routing/route-pattern.js\";\nimport type { CachedPagesValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport { buildCachedRevalidateCacheControl } from \"./cache-control.js\";\nimport { buildCacheStateHeaders } from \"./cache-headers.js\";\nimport { buildPagesCacheValue, type ISRCacheEntry } from \"./isr-cache.js\";\nimport {\n buildPagesNextDataScript,\n type PagesGsspResponse,\n type PagesI18nRenderContext,\n} from \"./pages-page-response.js\";\nimport { buildDefaultPagesNotFoundResponse } from \"./pages-default-404.js\";\n\ntype PagesRedirectResult = {\n destination: string;\n permanent?: boolean;\n statusCode?: number;\n};\n\n// Next.js allows `paths` entries to be either an object with a `params` key\n// or a raw string path. We keep a local variant of `StaticPathsEntry` here\n// because at request time we compare against the actual request `params`\n// (whose value type is `unknown` from the route matcher) rather than the\n// `string | string[]` shape used at build time. The shared\n// `normalizeStaticPathname` helper from `../routing/route-pattern.js` is used\n// to canonicalize the string-entry comparison.\ntype PagesStaticPathsEntry = string | { params?: Record<string, unknown>; locale?: string };\n\ntype PagesStaticPathsResult = {\n fallback?: boolean | \"blocking\";\n paths?: PagesStaticPathsEntry[];\n};\n\ntype PagesPagePropsResult = {\n props?: Record<string, unknown>;\n redirect?: PagesRedirectResult;\n notFound?: boolean;\n revalidate?: number;\n};\n\nexport type PagesMutableGsspResponse = {\n headersSent: boolean;\n} & PagesGsspResponse;\n\nexport type PagesGsspContextResponse = {\n req: unknown;\n res: PagesMutableGsspResponse;\n responsePromise: Promise<Response>;\n};\n\nexport type PagesPageModule = {\n default?: unknown;\n getStaticPaths?: (context: {\n locales: string[];\n defaultLocale: string;\n }) => Promise<PagesStaticPathsResult> | PagesStaticPathsResult;\n /**\n * Pages Router data-fetching context.\n *\n * `params` is `null` for non-dynamic routes (no `[param]` segments) to\n * match Next.js. User code typically falls back via `params || null`, so\n * passing `null` (rather than `{}`) is required for the value to be\n * observable as `null` once the data flows through to the page props.\n *\n * See: test/e2e/edge-pages-support/index.test.ts in Next.js for the\n * authoritative assertion (`expect(props.params).toBe(null)`).\n */\n getServerSideProps?: (context: {\n params: Record<string, unknown> | null;\n req: unknown;\n res: PagesMutableGsspResponse;\n query: Record<string, unknown>;\n resolvedUrl: string;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;\n getStaticProps?: (context: {\n params: Record<string, unknown> | null;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n /**\n * Indicates why `getStaticProps` was invoked.\n *\n * - `\"build\"`: initial build-time prerender (before runtime traffic).\n * - `\"on-demand\"`: triggered by `res.revalidate()` from an API route.\n * - `\"stale\"`: stale-while-revalidate background regeneration.\n *\n * Mirrors Next.js `render.tsx`'s `revalidateReason` on the\n * `GetStaticPropsContext` type — see\n * `.nextjs-ref/packages/next/src/types.ts`.\n */\n revalidateReason?: \"build\" | \"on-demand\" | \"stale\";\n }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;\n};\n\ntype RenderPagesIsrHtmlOptions = {\n buildId: string | null;\n cachedHtml: string;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n i18n: PagesI18nRenderContext;\n pageProps: Record<string, unknown>;\n params: Record<string, unknown>;\n renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;\n routePattern: string;\n safeJsonStringify: (value: unknown) => string;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\nexport type ResolvePagesPageDataOptions = {\n applyRequestContexts: () => void;\n buildId: string | null;\n /**\n * When true, this is a `/_next/data/<buildId>/<page>.json` request. Callers\n * that respond with a JSON envelope (`{ pageProps }`) instead of HTML must\n * bypass the HTML ISR cache: a cached HTML body cannot be reshaped into the\n * expected JSON shape, and storing JSON in the HTML cache would corrupt\n * subsequent HTML hits. Next.js handles this the same way — see\n * `isNextDataRequest` checks in `packages/next/src/server/base-server.ts`.\n */\n isDataReq?: boolean;\n createGsspReqRes: () => PagesGsspContextResponse;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n fontLinkHeader: string;\n i18n: PagesI18nRenderContext;\n isrCacheKey: (router: string, pathname: string) => string;\n isrGet: (key: string) => Promise<ISRCacheEntry | null>;\n isrSet: (\n key: string,\n data: CachedPagesValue,\n revalidateSeconds: number,\n tags?: string[],\n expireSeconds?: number,\n ) => Promise<void>;\n expireSeconds?: number;\n /**\n * When true, this dispatch corresponds to a build-time prerender (the\n * `vinext` build phase fetches each statically generated page through the\n * production server). Maps to `revalidateReason: \"build\"` when\n * `getStaticProps` is invoked. Mirrors Next.js's\n * `renderOpts.isBuildTimePrerendering` flag — see\n * `.nextjs-ref/packages/next/src/server/render.tsx`.\n */\n isBuildTimePrerendering?: boolean;\n /**\n * When true, this dispatch was triggered by an on-demand revalidation\n * request (e.g. `res.revalidate()` in a Pages Router API route, or an\n * equivalent webhook). Maps to `revalidateReason: \"on-demand\"` when\n * `getStaticProps` is invoked. Mirrors Next.js's\n * `renderOpts.isOnDemandRevalidate` flag — see\n * `.nextjs-ref/packages/next/src/server/render.tsx`.\n *\n * Forward-looking plumbing: no caller currently sets this — `res.revalidate()`\n * is not yet implemented in vinext. The `\"on-demand\"` branch in the\n * `revalidateReason` resolver is intentionally unreachable today; keeping the\n * typed contract here means wiring it up will be a one-line change once the\n * trigger lands.\n */\n isOnDemandRevalidate?: boolean;\n pageModule: PagesPageModule;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n route: Pick<Route, \"isDynamic\">;\n routePattern: string;\n routeUrl: string;\n runInFreshUnifiedContext: <T>(callback: () => Promise<T>) => Promise<T>;\n safeJsonStringify: (value: unknown) => string;\n sanitizeDestination: (destination: string) => string;\n scriptNonce?: string;\n statusCode?: number;\n triggerBackgroundRegeneration: (\n key: string,\n renderFn: () => Promise<void>,\n errorContext?: { routerKind: \"Pages Router\"; routePath: string; routeType: \"render\" },\n ) => void;\n renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\ntype ResolvePagesPageDataRenderResult = {\n kind: \"render\";\n gsspRes: PagesGsspResponse | null;\n isrRevalidateSeconds: number | null;\n pageProps: Record<string, unknown>;\n /**\n * True when `getStaticPaths` returned `fallback: true` AND the requested path\n * is not in the pre-rendered list. The caller renders a loading shell with\n * empty props and `useRouter().isFallback === true` (matching Next.js's\n * `render.tsx` — `getStaticProps` is skipped on the fallback render).\n */\n isFallback: boolean;\n};\n\ntype ResolvePagesPageDataResponseResult = {\n kind: \"response\";\n response: Response;\n};\n\ntype ResolvePagesPageDataResult =\n | ResolvePagesPageDataRenderResult\n | ResolvePagesPageDataResponseResult;\n\nfunction buildPagesNotFoundResponse(): Response {\n return buildDefaultPagesNotFoundResponse();\n}\n\nfunction buildPagesDataNotFoundResponse(): Response {\n // Matches Next.js: `/_next/data/<buildId>/<page>.json` 404 responses use\n // application/json with an empty object body so clients can call\n // `res.json()` without throwing before inspecting the status code.\n return new Response(\"{}\", {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction resolvePagesRedirectStatus(redirect: PagesRedirectResult): number {\n return redirect.statusCode != null ? redirect.statusCode : redirect.permanent ? 308 : 307;\n}\n\n/**\n * Compare a `getStaticPaths` entry against the actual request params.\n *\n * Handles both shapes Next.js allows:\n * - { params: { ... } }\n * - \"string-path\"\n *\n * For a string entry, compare the entry against the current request URL using\n * the shared `normalizeStaticPathname` helper from\n * `../routing/route-pattern.ts` (which mirrors the Next.js\n * `removeTrailingSlash` behaviour in\n * `.nextjs-ref/packages/next/src/build/static-paths/pages.ts`). For an object\n * entry with a missing `params` key, return false rather than throwing — the\n * caller will respond with a 404 just like Next.js does for unlisted paths.\n */\nfunction matchesPagesStaticPath(\n pathEntry: PagesStaticPathsEntry,\n params: Record<string, unknown>,\n routeUrl: string,\n): boolean {\n if (typeof pathEntry === \"string\") {\n return normalizeStaticPathname(pathEntry) === normalizeStaticPathname(routeUrl);\n }\n const entryParams = pathEntry.params;\n if (entryParams === undefined || entryParams === null) {\n return false;\n }\n return Object.entries(entryParams).every(([key, value]) => {\n const actual = params[key];\n if (Array.isArray(value)) {\n return Array.isArray(actual) && value.join(\"/\") === actual.join(\"/\");\n }\n return String(value) === String(actual);\n });\n}\n\nfunction buildPagesCacheResponse(\n html: string,\n cacheState: \"HIT\" | \"STALE\",\n fontLinkHeader: string,\n revalidateSeconds?: number,\n expireSeconds?: number,\n cacheControl?: CacheControlMetadata,\n status?: number,\n): Response {\n // Legacy cache entries written before cacheControl metadata existed can still\n // hit this path without a persisted revalidate value; keep the historic\n // 60-second fallback for that migration window.\n const effectiveRevalidateSeconds = cacheControl?.revalidate ?? revalidateSeconds ?? 60;\n const effectiveExpireSeconds =\n cacheControl === undefined ? undefined : (cacheControl.expire ?? expireSeconds);\n const headers: Record<string, string> = {\n \"Content-Type\": \"text/html\",\n ...buildCacheStateHeaders(cacheState),\n \"Cache-Control\": buildCachedRevalidateCacheControl(\n cacheState,\n effectiveRevalidateSeconds,\n effectiveExpireSeconds,\n ),\n };\n\n if (fontLinkHeader) {\n headers.Link = fontLinkHeader;\n }\n\n return new Response(html, {\n status: status ?? 200,\n headers,\n });\n}\n\nfunction rewritePagesCachedHtml(\n cachedHtml: string,\n freshBody: string,\n nextDataScript: string,\n): string {\n const bodyMarker = '<div id=\"__next\">';\n const bodyStart = cachedHtml.indexOf(bodyMarker);\n const contentStart = bodyStart >= 0 ? bodyStart + bodyMarker.length : -1;\n // This intentionally looks for the bare inline __NEXT_DATA__ marker.\n // Pages responses with scriptNonce are excluded from ISR writes, so cached\n // HTML should never contain nonce-prefixed __NEXT_DATA__ scripts here.\n const nextDataMarker = \"<script>window.__NEXT_DATA__\";\n const nextDataStart = cachedHtml.indexOf(nextDataMarker);\n\n if (contentStart >= 0 && nextDataStart >= 0) {\n const region = cachedHtml.slice(contentStart, nextDataStart);\n const lastCloseDiv = region.lastIndexOf(\"</div>\");\n const gap = lastCloseDiv >= 0 ? region.slice(lastCloseDiv + 6) : \"\";\n const nextDataEnd = cachedHtml.indexOf(\"</script>\", nextDataStart) + 9;\n const tail = cachedHtml.slice(nextDataEnd);\n\n return cachedHtml.slice(0, contentStart) + freshBody + \"</div>\" + gap + nextDataScript + tail;\n }\n\n return (\n '<!DOCTYPE html>\\n<html>\\n<head>\\n</head>\\n<body>\\n <div id=\"__next\">' +\n freshBody +\n \"</div>\\n \" +\n nextDataScript +\n \"\\n</body>\\n</html>\"\n );\n}\n\nexport async function renderPagesIsrHtml(options: RenderPagesIsrHtmlOptions): Promise<string> {\n const freshBody = await options.renderIsrPassToStringAsync(\n options.createPageElement(options.pageProps),\n );\n const nextDataScript = buildPagesNextDataScript({\n buildId: options.buildId,\n i18n: options.i18n,\n pageProps: options.pageProps,\n params: options.params,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n vinext: options.vinext,\n });\n\n return rewritePagesCachedHtml(options.cachedHtml, freshBody, nextDataScript);\n}\n\nexport async function resolvePagesPageData(\n options: ResolvePagesPageDataOptions,\n): Promise<ResolvePagesPageDataResult> {\n // Next.js passes `params: null` (effectively) to gSSP/gSP context for\n // non-dynamic routes — see render.tsx's `...(pageIsDynamic ? { params } : undefined)`.\n // Internal bookkeeping (route param hydration, ISR HTML, getStaticPaths\n // validation) still uses the matched-but-empty object — only user-facing\n // data-fetching contexts surface `null`.\n const userFacingParams: Record<string, unknown> | null = options.route.isDynamic\n ? options.params\n : null;\n\n // Set when `getStaticPaths: { fallback: true }` is configured and the\n // requested path is NOT in the pre-rendered list. When true, we render the\n // loading shell with empty props and `useRouter().isFallback === true`,\n // skipping `getStaticProps`. Matches Next.js `render.tsx`'s\n // `if (isSSG && !isFallback)` gate around `getStaticProps`. Data requests\n // (`/_next/data/...json`) still call `getStaticProps` so the client can\n // hydrate the page after the fallback shell ships.\n let isFallback = false;\n\n if (typeof options.pageModule.getStaticPaths === \"function\" && options.route.isDynamic) {\n const pathsResult = await options.pageModule.getStaticPaths({\n locales: options.i18n.locales ?? [],\n defaultLocale: options.i18n.defaultLocale ?? \"\",\n });\n const fallback = pathsResult?.fallback ?? false;\n const paths = pathsResult?.paths ?? [];\n const isValidPath = paths.some((pathEntry) =>\n matchesPagesStaticPath(pathEntry, options.params, options.routeUrl),\n );\n\n if (fallback === false && !isValidPath) {\n // For data requests (`/_next/data/...json`), return a JSON-shaped 404\n // so the client router can `res.json()` without blowing up — matches\n // Next.js' behavior. HTML navigations still get the HTML 404 page.\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n // Render the fallback shell for unlisted paths under `fallback: true`.\n // Data requests resolve props normally so the client can fill in after\n // the loading shell ships (`fallback: 'blocking'` keeps SSRing as before).\n if (fallback === true && !isValidPath && !options.isDataReq) {\n isFallback = true;\n }\n }\n\n let pageProps: Record<string, unknown> = {};\n let gsspRes: PagesMutableGsspResponse | null = null;\n\n if (isFallback) {\n return {\n kind: \"render\",\n gsspRes: null,\n isrRevalidateSeconds: null,\n pageProps,\n isFallback: true,\n };\n }\n\n if (typeof options.pageModule.getServerSideProps === \"function\") {\n const { req, res, responsePromise } = options.createGsspReqRes();\n const result = await options.pageModule.getServerSideProps({\n params: userFacingParams,\n req,\n res,\n query: options.query,\n resolvedUrl: options.routeUrl,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n });\n\n if (res.headersSent) {\n return {\n kind: \"response\",\n response: await responsePromise,\n };\n }\n\n if (result?.props) {\n // Next.js explicitly supports a Promise value for `props`. Await it\n // before serialising; otherwise pageProps would be a Promise and the\n // rendered page would receive empty props. See\n // packages/next/src/server/render.tsx (deferredContent).\n pageProps = (await Promise.resolve(result.props)) as Record<string, unknown>;\n }\n\n if (result?.redirect) {\n return {\n kind: \"response\",\n response: new Response(null, {\n status: resolvePagesRedirectStatus(result.redirect),\n headers: { Location: options.sanitizeDestination(result.redirect.destination) },\n }),\n };\n }\n\n if (result?.notFound) {\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n gsspRes = res;\n }\n\n let isrRevalidateSeconds: number | null = null;\n\n if (typeof options.pageModule.getStaticProps === \"function\") {\n const pathname = options.routeUrl.split(\"?\")[0];\n const cacheKey = options.isrCacheKey(\"pages\", pathname);\n const cached = await options.isrGet(cacheKey);\n const cachedValue = cached?.value.value;\n\n if (\n cachedValue?.kind === \"PAGES\" &&\n cached &&\n !cached.isStale &&\n !options.scriptNonce &&\n !options.isDataReq\n ) {\n return {\n kind: \"response\",\n response: buildPagesCacheResponse(\n cachedValue.html,\n \"HIT\",\n options.fontLinkHeader,\n undefined,\n options.expireSeconds,\n cached.value.cacheControl,\n cachedValue.status,\n ),\n };\n }\n\n if (\n cachedValue?.kind === \"PAGES\" &&\n cached &&\n cached.isStale &&\n !options.scriptNonce &&\n !options.isDataReq\n ) {\n options.triggerBackgroundRegeneration(\n cacheKey,\n async function () {\n return options.runInFreshUnifiedContext(async () => {\n const freshResult = await options.pageModule.getStaticProps?.({\n params: userFacingParams,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n // Background regeneration for an entry that is already in the\n // cache is always a stale-while-revalidate refresh — mirrors\n // Next.js `render.tsx` (`isBuildTimeSSG ? \"build\" : \"stale\"`,\n // and we're not at build time here).\n revalidateReason: \"stale\",\n });\n\n if (\n freshResult?.props &&\n typeof freshResult.revalidate === \"number\" &&\n freshResult.revalidate > 0\n ) {\n options.applyRequestContexts();\n const freshHtml = await renderPagesIsrHtml({\n buildId: options.buildId,\n cachedHtml: cachedValue.html,\n createPageElement: options.createPageElement,\n i18n: options.i18n,\n pageProps: freshResult.props,\n params: options.params,\n renderIsrPassToStringAsync: options.renderIsrPassToStringAsync,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n vinext: options.vinext,\n });\n\n await options.isrSet(\n cacheKey,\n buildPagesCacheValue(freshHtml, freshResult.props, options.statusCode),\n freshResult.revalidate,\n undefined,\n options.expireSeconds,\n );\n }\n });\n },\n {\n routerKind: \"Pages Router\",\n routePath: options.routePattern,\n routeType: \"render\",\n },\n );\n\n return {\n kind: \"response\",\n response: buildPagesCacheResponse(\n cachedValue.html,\n \"STALE\",\n options.fontLinkHeader,\n undefined,\n options.expireSeconds,\n cached.value.cacheControl,\n cachedValue.status,\n ),\n };\n }\n\n const result = await options.pageModule.getStaticProps({\n params: userFacingParams,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n // Maps Next.js's resolution in `render.tsx`:\n // isOnDemandRevalidate ? \"on-demand\"\n // : isBuildTimeSSG ? \"build\"\n // : \"stale\"\n // We pick \"stale\" as the default at runtime so existing-but-missing\n // (cache evicted) entries surface as a regeneration rather than a build.\n revalidateReason: options.isOnDemandRevalidate\n ? \"on-demand\"\n : options.isBuildTimePrerendering\n ? \"build\"\n : \"stale\",\n });\n\n if (result?.props) {\n pageProps = result.props;\n }\n\n if (result?.redirect) {\n return {\n kind: \"response\",\n response: new Response(null, {\n status: resolvePagesRedirectStatus(result.redirect),\n headers: { Location: options.sanitizeDestination(result.redirect.destination) },\n }),\n };\n }\n\n if (result?.notFound) {\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n if (typeof result?.revalidate === \"number\" && result.revalidate > 0) {\n isrRevalidateSeconds = result.revalidate;\n }\n }\n\n return {\n kind: \"render\",\n gsspRes,\n isrRevalidateSeconds,\n pageProps,\n isFallback: false,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pages-page-data.js","names":[],"sources":["../../src/server/pages-page-data.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport { normalizeStaticPathname } from \"../routing/route-pattern.js\";\nimport type { CachedPagesValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport { buildCachedRevalidateCacheControl } from \"./cache-control.js\";\nimport { buildCacheStateHeaders } from \"./cache-headers.js\";\nimport { buildPagesCacheValue, type ISRCacheEntry } from \"./isr-cache.js\";\nimport {\n buildPagesNextDataScript,\n type PagesGsspResponse,\n type PagesI18nRenderContext,\n} from \"./pages-page-response.js\";\nimport { buildDefaultPagesNotFoundResponse } from \"./pages-default-404.js\";\nimport { isSerializableProps } from \"./pages-serializable-props.js\";\n\ntype PagesRedirectResult = {\n destination: string;\n permanent?: boolean;\n statusCode?: number;\n};\n\n// Next.js allows `paths` entries to be either an object with a `params` key\n// or a raw string path. We keep a local variant of `StaticPathsEntry` here\n// because at request time we compare against the actual request `params`\n// (whose value type is `unknown` from the route matcher) rather than the\n// `string | string[]` shape used at build time. The shared\n// `normalizeStaticPathname` helper from `../routing/route-pattern.js` is used\n// to canonicalize the string-entry comparison.\ntype PagesStaticPathsEntry = string | { params?: Record<string, unknown>; locale?: string };\n\ntype PagesStaticPathsResult = {\n fallback?: boolean | \"blocking\";\n paths?: PagesStaticPathsEntry[];\n};\n\ntype PagesPagePropsResult = {\n props?: Record<string, unknown>;\n redirect?: PagesRedirectResult;\n notFound?: boolean;\n revalidate?: number;\n};\n\nexport type PagesMutableGsspResponse = {\n headersSent: boolean;\n} & PagesGsspResponse;\n\nexport type PagesGsspContextResponse = {\n req: unknown;\n res: PagesMutableGsspResponse;\n responsePromise: Promise<Response>;\n};\n\nexport type PagesPageModule = {\n default?: unknown;\n getStaticPaths?: (context: {\n locales: string[];\n defaultLocale: string;\n }) => Promise<PagesStaticPathsResult> | PagesStaticPathsResult;\n /**\n * Pages Router data-fetching context.\n *\n * `params` is `null` for non-dynamic routes (no `[param]` segments) to\n * match Next.js. User code typically falls back via `params || null`, so\n * passing `null` (rather than `{}`) is required for the value to be\n * observable as `null` once the data flows through to the page props.\n *\n * See: test/e2e/edge-pages-support/index.test.ts in Next.js for the\n * authoritative assertion (`expect(props.params).toBe(null)`).\n */\n getServerSideProps?: (context: {\n params: Record<string, unknown> | null;\n req: unknown;\n res: PagesMutableGsspResponse;\n query: Record<string, unknown>;\n resolvedUrl: string;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;\n getStaticProps?: (context: {\n params: Record<string, unknown> | null;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n /**\n * Indicates why `getStaticProps` was invoked.\n *\n * - `\"build\"`: initial build-time prerender (before runtime traffic).\n * - `\"on-demand\"`: triggered by `res.revalidate()` from an API route.\n * - `\"stale\"`: stale-while-revalidate background regeneration.\n *\n * Mirrors Next.js `render.tsx`'s `revalidateReason` on the\n * `GetStaticPropsContext` type — see\n * `.nextjs-ref/packages/next/src/types.ts`.\n */\n revalidateReason?: \"build\" | \"on-demand\" | \"stale\";\n }) => Promise<PagesPagePropsResult> | PagesPagePropsResult;\n};\n\ntype RenderPagesIsrHtmlOptions = {\n buildId: string | null;\n cachedHtml: string;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n i18n: PagesI18nRenderContext;\n pageProps: Record<string, unknown>;\n params: Record<string, unknown>;\n renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;\n routePattern: string;\n safeJsonStringify: (value: unknown) => string;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\nexport type ResolvePagesPageDataOptions = {\n applyRequestContexts: () => void;\n buildId: string | null;\n /**\n * When true, this is a `/_next/data/<buildId>/<page>.json` request. Callers\n * that respond with a JSON envelope (`{ pageProps }`) instead of HTML must\n * bypass the HTML ISR cache: a cached HTML body cannot be reshaped into the\n * expected JSON shape, and storing JSON in the HTML cache would corrupt\n * subsequent HTML hits. Next.js handles this the same way — see\n * `isNextDataRequest` checks in `packages/next/src/server/base-server.ts`.\n */\n isDataReq?: boolean;\n createGsspReqRes: () => PagesGsspContextResponse;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n fontLinkHeader: string;\n i18n: PagesI18nRenderContext;\n isrCacheKey: (router: string, pathname: string) => string;\n isrGet: (key: string) => Promise<ISRCacheEntry | null>;\n isrSet: (\n key: string,\n data: CachedPagesValue,\n revalidateSeconds: number,\n tags?: string[],\n expireSeconds?: number,\n ) => Promise<void>;\n expireSeconds?: number;\n /**\n * When true, this dispatch corresponds to a build-time prerender (the\n * `vinext` build phase fetches each statically generated page through the\n * production server). Maps to `revalidateReason: \"build\"` when\n * `getStaticProps` is invoked. Mirrors Next.js's\n * `renderOpts.isBuildTimePrerendering` flag — see\n * `.nextjs-ref/packages/next/src/server/render.tsx`.\n */\n isBuildTimePrerendering?: boolean;\n /**\n * When true, this dispatch was triggered by an on-demand revalidation\n * request (e.g. `res.revalidate()` in a Pages Router API route, or an\n * equivalent webhook). Maps to `revalidateReason: \"on-demand\"` when\n * `getStaticProps` is invoked. Mirrors Next.js's\n * `renderOpts.isOnDemandRevalidate` flag — see\n * `.nextjs-ref/packages/next/src/server/render.tsx`.\n *\n * Forward-looking plumbing: no caller currently sets this — `res.revalidate()`\n * is not yet implemented in vinext. The `\"on-demand\"` branch in the\n * `revalidateReason` resolver is intentionally unreachable today; keeping the\n * typed contract here means wiring it up will be a one-line change once the\n * trigger lands.\n */\n isOnDemandRevalidate?: boolean;\n pageModule: PagesPageModule;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n route: Pick<Route, \"isDynamic\">;\n routePattern: string;\n routeUrl: string;\n runInFreshUnifiedContext: <T>(callback: () => Promise<T>) => Promise<T>;\n safeJsonStringify: (value: unknown) => string;\n sanitizeDestination: (destination: string) => string;\n scriptNonce?: string;\n statusCode?: number;\n triggerBackgroundRegeneration: (\n key: string,\n renderFn: () => Promise<void>,\n errorContext?: { routerKind: \"Pages Router\"; routePath: string; routeType: \"render\" },\n ) => void;\n renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\ntype ResolvePagesPageDataRenderResult = {\n kind: \"render\";\n gsspRes: PagesGsspResponse | null;\n isrRevalidateSeconds: number | null;\n pageProps: Record<string, unknown>;\n /**\n * True when `getStaticPaths` returned `fallback: true` AND the requested path\n * is not in the pre-rendered list. The caller renders a loading shell with\n * empty props and `useRouter().isFallback === true` (matching Next.js's\n * `render.tsx` — `getStaticProps` is skipped on the fallback render).\n */\n isFallback: boolean;\n};\n\ntype ResolvePagesPageDataResponseResult = {\n kind: \"response\";\n response: Response;\n};\n\ntype ResolvePagesPageDataResult =\n | ResolvePagesPageDataRenderResult\n | ResolvePagesPageDataResponseResult;\n\nfunction buildPagesNotFoundResponse(): Response {\n return buildDefaultPagesNotFoundResponse();\n}\n\nfunction buildPagesDataNotFoundResponse(): Response {\n // Matches Next.js: `/_next/data/<buildId>/<page>.json` 404 responses use\n // application/json with an empty object body so clients can call\n // `res.json()` without throwing before inspecting the status code.\n return new Response(\"{}\", {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction resolvePagesRedirectStatus(redirect: PagesRedirectResult): number {\n return redirect.statusCode != null ? redirect.statusCode : redirect.permanent ? 308 : 307;\n}\n\n/**\n * Compare a `getStaticPaths` entry against the actual request params.\n *\n * Handles both shapes Next.js allows:\n * - { params: { ... } }\n * - \"string-path\"\n *\n * For a string entry, compare the entry against the current request URL using\n * the shared `normalizeStaticPathname` helper from\n * `../routing/route-pattern.ts` (which mirrors the Next.js\n * `removeTrailingSlash` behaviour in\n * `.nextjs-ref/packages/next/src/build/static-paths/pages.ts`). For an object\n * entry with a missing `params` key, return false rather than throwing — the\n * caller will respond with a 404 just like Next.js does for unlisted paths.\n */\nfunction matchesPagesStaticPath(\n pathEntry: PagesStaticPathsEntry,\n params: Record<string, unknown>,\n routeUrl: string,\n): boolean {\n if (typeof pathEntry === \"string\") {\n return normalizeStaticPathname(pathEntry) === normalizeStaticPathname(routeUrl);\n }\n const entryParams = pathEntry.params;\n if (entryParams === undefined || entryParams === null) {\n return false;\n }\n return Object.entries(entryParams).every(([key, value]) => {\n const actual = params[key];\n if (Array.isArray(value)) {\n return Array.isArray(actual) && value.join(\"/\") === actual.join(\"/\");\n }\n return String(value) === String(actual);\n });\n}\n\nfunction buildPagesCacheResponse(\n html: string,\n cacheState: \"HIT\" | \"STALE\",\n fontLinkHeader: string,\n revalidateSeconds?: number,\n expireSeconds?: number,\n cacheControl?: CacheControlMetadata,\n status?: number,\n): Response {\n // Legacy cache entries written before cacheControl metadata existed can still\n // hit this path without a persisted revalidate value; keep the historic\n // 60-second fallback for that migration window.\n const effectiveRevalidateSeconds = cacheControl?.revalidate ?? revalidateSeconds ?? 60;\n const effectiveExpireSeconds =\n cacheControl === undefined ? undefined : (cacheControl.expire ?? expireSeconds);\n const headers: Record<string, string> = {\n \"Content-Type\": \"text/html\",\n ...buildCacheStateHeaders(cacheState),\n \"Cache-Control\": buildCachedRevalidateCacheControl(\n cacheState,\n effectiveRevalidateSeconds,\n effectiveExpireSeconds,\n ),\n };\n\n if (fontLinkHeader) {\n headers.Link = fontLinkHeader;\n }\n\n return new Response(html, {\n status: status ?? 200,\n headers,\n });\n}\n\nfunction rewritePagesCachedHtml(\n cachedHtml: string,\n freshBody: string,\n nextDataScript: string,\n): string {\n const bodyMarker = '<div id=\"__next\">';\n const bodyStart = cachedHtml.indexOf(bodyMarker);\n const contentStart = bodyStart >= 0 ? bodyStart + bodyMarker.length : -1;\n // This intentionally looks for the bare inline __NEXT_DATA__ marker.\n // Pages responses with scriptNonce are excluded from ISR writes, so cached\n // HTML should never contain nonce-prefixed __NEXT_DATA__ scripts here.\n const nextDataMarker = \"<script>window.__NEXT_DATA__\";\n const nextDataStart = cachedHtml.indexOf(nextDataMarker);\n\n if (contentStart >= 0 && nextDataStart >= 0) {\n const region = cachedHtml.slice(contentStart, nextDataStart);\n const lastCloseDiv = region.lastIndexOf(\"</div>\");\n const gap = lastCloseDiv >= 0 ? region.slice(lastCloseDiv + 6) : \"\";\n const nextDataEnd = cachedHtml.indexOf(\"</script>\", nextDataStart) + 9;\n const tail = cachedHtml.slice(nextDataEnd);\n\n return cachedHtml.slice(0, contentStart) + freshBody + \"</div>\" + gap + nextDataScript + tail;\n }\n\n return (\n '<!DOCTYPE html>\\n<html>\\n<head>\\n</head>\\n<body>\\n <div id=\"__next\">' +\n freshBody +\n \"</div>\\n \" +\n nextDataScript +\n \"\\n</body>\\n</html>\"\n );\n}\n\nexport async function renderPagesIsrHtml(options: RenderPagesIsrHtmlOptions): Promise<string> {\n const freshBody = await options.renderIsrPassToStringAsync(\n options.createPageElement(options.pageProps),\n );\n const nextDataScript = buildPagesNextDataScript({\n buildId: options.buildId,\n i18n: options.i18n,\n pageProps: options.pageProps,\n params: options.params,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n vinext: options.vinext,\n });\n\n return rewritePagesCachedHtml(options.cachedHtml, freshBody, nextDataScript);\n}\n\nexport async function resolvePagesPageData(\n options: ResolvePagesPageDataOptions,\n): Promise<ResolvePagesPageDataResult> {\n // Next.js passes `params: null` (effectively) to gSSP/gSP context for\n // non-dynamic routes — see render.tsx's `...(pageIsDynamic ? { params } : undefined)`.\n // Internal bookkeeping (route param hydration, ISR HTML, getStaticPaths\n // validation) still uses the matched-but-empty object — only user-facing\n // data-fetching contexts surface `null`.\n const userFacingParams: Record<string, unknown> | null = options.route.isDynamic\n ? options.params\n : null;\n\n // Set when `getStaticPaths: { fallback: true }` is configured and the\n // requested path is NOT in the pre-rendered list. When true, we render the\n // loading shell with empty props and `useRouter().isFallback === true`,\n // skipping `getStaticProps`. Matches Next.js `render.tsx`'s\n // `if (isSSG && !isFallback)` gate around `getStaticProps`. Data requests\n // (`/_next/data/...json`) still call `getStaticProps` so the client can\n // hydrate the page after the fallback shell ships.\n let isFallback = false;\n\n if (typeof options.pageModule.getStaticPaths === \"function\" && options.route.isDynamic) {\n const pathsResult = await options.pageModule.getStaticPaths({\n locales: options.i18n.locales ?? [],\n defaultLocale: options.i18n.defaultLocale ?? \"\",\n });\n const fallback = pathsResult?.fallback ?? false;\n const paths = pathsResult?.paths ?? [];\n const isValidPath = paths.some((pathEntry) =>\n matchesPagesStaticPath(pathEntry, options.params, options.routeUrl),\n );\n\n if (fallback === false && !isValidPath) {\n // For data requests (`/_next/data/...json`), return a JSON-shaped 404\n // so the client router can `res.json()` without blowing up — matches\n // Next.js' behavior. HTML navigations still get the HTML 404 page.\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n // Render the fallback shell for unlisted paths under `fallback: true`.\n // Data requests resolve props normally so the client can fill in after\n // the loading shell ships (`fallback: 'blocking'` keeps SSRing as before).\n if (fallback === true && !isValidPath && !options.isDataReq) {\n isFallback = true;\n }\n }\n\n let pageProps: Record<string, unknown> = {};\n let gsspRes: PagesMutableGsspResponse | null = null;\n\n if (isFallback) {\n return {\n kind: \"render\",\n gsspRes: null,\n isrRevalidateSeconds: null,\n pageProps,\n isFallback: true,\n };\n }\n\n if (typeof options.pageModule.getServerSideProps === \"function\") {\n const { req, res, responsePromise } = options.createGsspReqRes();\n const result = await options.pageModule.getServerSideProps({\n params: userFacingParams,\n req,\n res,\n query: options.query,\n resolvedUrl: options.routeUrl,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n });\n\n if (res.headersSent) {\n return {\n kind: \"response\",\n response: await responsePromise,\n };\n }\n\n if (result?.props) {\n // Next.js explicitly supports a Promise value for `props`. Await it\n // before serialising; otherwise pageProps would be a Promise and the\n // rendered page would receive empty props. See\n // packages/next/src/server/render.tsx (deferredContent).\n pageProps = (await Promise.resolve(result.props)) as Record<string, unknown>;\n }\n\n if (result?.redirect) {\n return {\n kind: \"response\",\n response: new Response(null, {\n status: resolvePagesRedirectStatus(result.redirect),\n headers: { Location: options.sanitizeDestination(result.redirect.destination) },\n }),\n };\n }\n\n if (result?.notFound) {\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n // Mirrors Next.js render.tsx's `isSerializableProps(pathname, \"getServerSideProps\", data.props)`\n // check, gated on `!metadata.isRedirect && !metadata.isNotFound` (both\n // short-circuit above). Throws a friendly `SerializableError` so the\n // caller's existing try/catch surfaces a clear 500 instead of rendering\n // an empty page. See\n // .nextjs-ref/packages/next/src/server/render.tsx (~line 1200) and\n // .nextjs-ref/packages/next/src/lib/is-serializable-props.ts. Tracked in\n // vinext#1478.\n if (result?.props !== undefined) {\n isSerializableProps(options.routePattern, \"getServerSideProps\", pageProps);\n }\n\n gsspRes = res;\n }\n\n let isrRevalidateSeconds: number | null = null;\n\n if (typeof options.pageModule.getStaticProps === \"function\") {\n const pathname = options.routeUrl.split(\"?\")[0];\n const cacheKey = options.isrCacheKey(\"pages\", pathname);\n const cached = await options.isrGet(cacheKey);\n const cachedValue = cached?.value.value;\n\n if (\n cachedValue?.kind === \"PAGES\" &&\n cached &&\n !cached.isStale &&\n !options.scriptNonce &&\n !options.isDataReq\n ) {\n return {\n kind: \"response\",\n response: buildPagesCacheResponse(\n cachedValue.html,\n \"HIT\",\n options.fontLinkHeader,\n undefined,\n options.expireSeconds,\n cached.value.cacheControl,\n cachedValue.status,\n ),\n };\n }\n\n if (\n cachedValue?.kind === \"PAGES\" &&\n cached &&\n cached.isStale &&\n !options.scriptNonce &&\n !options.isDataReq\n ) {\n options.triggerBackgroundRegeneration(\n cacheKey,\n async function () {\n return options.runInFreshUnifiedContext(async () => {\n const freshResult = await options.pageModule.getStaticProps?.({\n params: userFacingParams,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n // Background regeneration for an entry that is already in the\n // cache is always a stale-while-revalidate refresh — mirrors\n // Next.js `render.tsx` (`isBuildTimeSSG ? \"build\" : \"stale\"`,\n // and we're not at build time here).\n revalidateReason: \"stale\",\n });\n\n if (\n freshResult?.props &&\n typeof freshResult.revalidate === \"number\" &&\n freshResult.revalidate > 0\n ) {\n options.applyRequestContexts();\n const freshHtml = await renderPagesIsrHtml({\n buildId: options.buildId,\n cachedHtml: cachedValue.html,\n createPageElement: options.createPageElement,\n i18n: options.i18n,\n pageProps: freshResult.props,\n params: options.params,\n renderIsrPassToStringAsync: options.renderIsrPassToStringAsync,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n vinext: options.vinext,\n });\n\n await options.isrSet(\n cacheKey,\n buildPagesCacheValue(freshHtml, freshResult.props, options.statusCode),\n freshResult.revalidate,\n undefined,\n options.expireSeconds,\n );\n }\n });\n },\n {\n routerKind: \"Pages Router\",\n routePath: options.routePattern,\n routeType: \"render\",\n },\n );\n\n return {\n kind: \"response\",\n response: buildPagesCacheResponse(\n cachedValue.html,\n \"STALE\",\n options.fontLinkHeader,\n undefined,\n options.expireSeconds,\n cached.value.cacheControl,\n cachedValue.status,\n ),\n };\n }\n\n const result = await options.pageModule.getStaticProps({\n params: userFacingParams,\n locale: options.i18n.locale,\n locales: options.i18n.locales,\n defaultLocale: options.i18n.defaultLocale,\n // Maps Next.js's resolution in `render.tsx`:\n // isOnDemandRevalidate ? \"on-demand\"\n // : isBuildTimeSSG ? \"build\"\n // : \"stale\"\n // We pick \"stale\" as the default at runtime so existing-but-missing\n // (cache evicted) entries surface as a regeneration rather than a build.\n revalidateReason: options.isOnDemandRevalidate\n ? \"on-demand\"\n : options.isBuildTimePrerendering\n ? \"build\"\n : \"stale\",\n });\n\n if (result?.props) {\n pageProps = result.props;\n }\n\n if (result?.redirect) {\n return {\n kind: \"response\",\n response: new Response(null, {\n status: resolvePagesRedirectStatus(result.redirect),\n headers: { Location: options.sanitizeDestination(result.redirect.destination) },\n }),\n };\n }\n\n if (result?.notFound) {\n return {\n kind: \"response\",\n response: options.isDataReq\n ? buildPagesDataNotFoundResponse()\n : buildPagesNotFoundResponse(),\n };\n }\n\n // Mirrors Next.js render.tsx's `isSerializableProps(pathname, \"getStaticProps\", data.props)`\n // check, gated on `!metadata.isNotFound` (notFound + redirect both\n // short-circuit above). Throws a friendly `SerializableError` so the\n // caller's existing try/catch surfaces a clear 500 instead of rendering\n // an empty page. See\n // .nextjs-ref/packages/next/src/server/render.tsx (~line 982) and\n // .nextjs-ref/packages/next/src/lib/is-serializable-props.ts. Tracked in\n // vinext#1478.\n if (result?.props !== undefined) {\n isSerializableProps(options.routePattern, \"getStaticProps\", pageProps);\n }\n\n if (typeof result?.revalidate === \"number\" && result.revalidate > 0) {\n isrRevalidateSeconds = result.revalidate;\n }\n }\n\n return {\n kind: \"render\",\n gsspRes,\n isrRevalidateSeconds,\n pageProps,\n isFallback: false,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/server/pages-page-method.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pages Router method-allow policy.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors Next.js's behavior in
|
|
6
|
+
* `.nextjs-ref/packages/next/src/server/base-server.ts` around L2277:
|
|
7
|
+
*
|
|
8
|
+
* if (
|
|
9
|
+
* !isPossibleServerAction &&
|
|
10
|
+
* !minimalPostponed &&
|
|
11
|
+
* !is404Page &&
|
|
12
|
+
* !is500Page &&
|
|
13
|
+
* pathname !== '/_error' &&
|
|
14
|
+
* req.method !== 'HEAD' &&
|
|
15
|
+
* req.method !== 'GET' &&
|
|
16
|
+
* (typeof components.Component === 'string' || isSSG)
|
|
17
|
+
* ) {
|
|
18
|
+
* res.statusCode = 405
|
|
19
|
+
* res.setHeader('Allow', ['GET', 'HEAD'])
|
|
20
|
+
* res.body('Method Not Allowed').send()
|
|
21
|
+
* return null
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* In vinext, a Pages Router route is "static" (no SSR per-request work) when
|
|
25
|
+
* it does not export `getServerSideProps`. Such routes — including plain
|
|
26
|
+
* components and `getStaticProps` (GSP) pages — must reject non-GET/HEAD
|
|
27
|
+
* requests with 405 + `Allow: GET, HEAD`.
|
|
28
|
+
*
|
|
29
|
+
* Server Actions (Pages Router supports `"use server"` for forms in newer
|
|
30
|
+
* Next.js versions) are out of scope here: vinext's Pages Router does not
|
|
31
|
+
* implement them, so there's no carve-out to add. If/when it does, this
|
|
32
|
+
* helper should grow an `isPossibleServerAction` opt-out parameter mirroring
|
|
33
|
+
* the App Router's `resolveAppPageMethodResponse`.
|
|
34
|
+
*
|
|
35
|
+
* Refs #1463.
|
|
36
|
+
*/
|
|
37
|
+
type PagesPageMethodOptions = {
|
|
38
|
+
hasGetServerSideProps: boolean;
|
|
39
|
+
method: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Returns a 405 `Response` when the request method is not allowed for a
|
|
43
|
+
* static (no `getServerSideProps`) Pages Router page, otherwise `null`.
|
|
44
|
+
*/
|
|
45
|
+
declare function resolvePagesPageMethodResponse(options: PagesPageMethodOptions): Response | null;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { resolvePagesPageMethodResponse };
|
|
48
|
+
//# sourceMappingURL=pages-page-method.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { methodNotAllowedResponse } from "./http-error-responses.js";
|
|
2
|
+
//#region src/server/pages-page-method.ts
|
|
3
|
+
function isNonGetOrHead(method) {
|
|
4
|
+
const normalizedMethod = method.toUpperCase();
|
|
5
|
+
return normalizedMethod !== "GET" && normalizedMethod !== "HEAD";
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Returns a 405 `Response` when the request method is not allowed for a
|
|
9
|
+
* static (no `getServerSideProps`) Pages Router page, otherwise `null`.
|
|
10
|
+
*/
|
|
11
|
+
function resolvePagesPageMethodResponse(options) {
|
|
12
|
+
if (!isNonGetOrHead(options.method)) return null;
|
|
13
|
+
if (options.hasGetServerSideProps) return null;
|
|
14
|
+
return methodNotAllowedResponse("GET, HEAD");
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { resolvePagesPageMethodResponse };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=pages-page-method.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages-page-method.js","names":[],"sources":["../../src/server/pages-page-method.ts"],"sourcesContent":["import { methodNotAllowedResponse } from \"./http-error-responses.js\";\n\n/**\n * Pages Router method-allow policy.\n *\n * Mirrors Next.js's behavior in\n * `.nextjs-ref/packages/next/src/server/base-server.ts` around L2277:\n *\n * if (\n * !isPossibleServerAction &&\n * !minimalPostponed &&\n * !is404Page &&\n * !is500Page &&\n * pathname !== '/_error' &&\n * req.method !== 'HEAD' &&\n * req.method !== 'GET' &&\n * (typeof components.Component === 'string' || isSSG)\n * ) {\n * res.statusCode = 405\n * res.setHeader('Allow', ['GET', 'HEAD'])\n * res.body('Method Not Allowed').send()\n * return null\n * }\n *\n * In vinext, a Pages Router route is \"static\" (no SSR per-request work) when\n * it does not export `getServerSideProps`. Such routes — including plain\n * components and `getStaticProps` (GSP) pages — must reject non-GET/HEAD\n * requests with 405 + `Allow: GET, HEAD`.\n *\n * Server Actions (Pages Router supports `\"use server\"` for forms in newer\n * Next.js versions) are out of scope here: vinext's Pages Router does not\n * implement them, so there's no carve-out to add. If/when it does, this\n * helper should grow an `isPossibleServerAction` opt-out parameter mirroring\n * the App Router's `resolveAppPageMethodResponse`.\n *\n * Refs #1463.\n */\n\ntype PagesPageMethodOptions = {\n hasGetServerSideProps: boolean;\n method: string;\n};\n\nfunction isNonGetOrHead(method: string): boolean {\n const normalizedMethod = method.toUpperCase();\n return normalizedMethod !== \"GET\" && normalizedMethod !== \"HEAD\";\n}\n\n/**\n * Returns a 405 `Response` when the request method is not allowed for a\n * static (no `getServerSideProps`) Pages Router page, otherwise `null`.\n */\nexport function resolvePagesPageMethodResponse(options: PagesPageMethodOptions): Response | null {\n if (!isNonGetOrHead(options.method)) {\n return null;\n }\n\n if (options.hasGetServerSideProps) {\n return null;\n }\n\n return methodNotAllowedResponse(\"GET, HEAD\");\n}\n"],"mappings":";;AA2CA,SAAS,eAAe,QAAyB;CAC/C,MAAM,mBAAmB,OAAO,aAAa;CAC7C,OAAO,qBAAqB,SAAS,qBAAqB;;;;;;AAO5D,SAAgB,+BAA+B,SAAkD;CAC/F,IAAI,CAAC,eAAe,QAAQ,OAAO,EACjC,OAAO;CAGT,IAAI,QAAQ,uBACV,OAAO;CAGT,OAAO,yBAAyB,YAAY"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VinextNextData } from "../client/vinext-next-data.js";
|
|
2
2
|
import { CachedPagesValue } from "../shims/cache.js";
|
|
3
|
+
import { RenderPageEnhancers } from "./pages-document-initial-props.js";
|
|
3
4
|
import { ComponentType, ReactNode } from "react";
|
|
4
5
|
|
|
5
6
|
//#region src/server/pages-page-response.d.ts
|
|
@@ -22,6 +23,18 @@ type RenderPagesPageResponseOptions = {
|
|
|
22
23
|
buildId: string | null;
|
|
23
24
|
clearSsrContext: () => void;
|
|
24
25
|
createPageElement: (pageProps: Record<string, unknown>) => ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* Build the page React tree with optional App/Component enhancers applied,
|
|
28
|
+
* supporting the Pages Router `_document.getInitialProps` contract:
|
|
29
|
+
*
|
|
30
|
+
* ctx.renderPage({ enhanceApp, enhanceComponent })
|
|
31
|
+
*
|
|
32
|
+
* Used by CSS-in-JS libraries (styled-components, emotion) to wrap the
|
|
33
|
+
* App/Component tree so styles can be collected during SSR. When omitted,
|
|
34
|
+
* `renderPage` falls back to rendering the plain `createPageElement` tree
|
|
35
|
+
* (enhancers are ignored).
|
|
36
|
+
*/
|
|
37
|
+
enhancePageElement?: ((opts: RenderPageEnhancers) => ReactNode) | undefined;
|
|
25
38
|
DocumentComponent: ComponentType | null;
|
|
26
39
|
flushPreloads?: (() => Promise<void> | void) | undefined;
|
|
27
40
|
fontLinkHeader: string;
|
|
@@ -29,6 +42,13 @@ type RenderPagesPageResponseOptions = {
|
|
|
29
42
|
getFontLinks: () => string[];
|
|
30
43
|
getFontStyles: () => string[];
|
|
31
44
|
getSSRHeadHTML?: (() => string) | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Allow-list of OpenTelemetry propagation keys (from
|
|
47
|
+
* `experimental.clientTraceMetadata`) to emit as `<meta>` tags in the SSR
|
|
48
|
+
* head. Undefined or empty disables emission.
|
|
49
|
+
*/
|
|
50
|
+
clientTraceMetadata?: readonly string[] | undefined;
|
|
51
|
+
setDocumentInitialHead?: ((head: ReactNode[]) => void) | undefined;
|
|
32
52
|
gsspRes: PagesGsspResponse | null;
|
|
33
53
|
isrCacheKey: (router: string, pathname: string) => string;
|
|
34
54
|
expireSeconds?: number;
|
|
@@ -3,8 +3,11 @@ import { reportRequestError } from "./instrumentation.js";
|
|
|
3
3
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
4
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
5
5
|
import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from "./html.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
|
|
7
7
|
import { readStreamAsText } from "../utils/text-stream.js";
|
|
8
|
+
import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
|
|
9
|
+
import { callDocumentGetInitialProps } from "./document-initial-head.js";
|
|
10
|
+
import { buildRevalidateCacheControl } from "./cache-control.js";
|
|
8
11
|
import React from "react";
|
|
9
12
|
//#region src/server/pages-page-response.ts
|
|
10
13
|
function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
|
|
@@ -35,7 +38,9 @@ function buildPagesNextDataScript(options) {
|
|
|
35
38
|
}
|
|
36
39
|
async function buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, options) {
|
|
37
40
|
if (options.DocumentComponent) {
|
|
38
|
-
|
|
41
|
+
const docProps = options.resolvedDocProps ?? await loadUserDocumentInitialProps(options.DocumentComponent);
|
|
42
|
+
const docElement = docProps ? React.createElement(options.DocumentComponent, docProps) : React.createElement(options.DocumentComponent);
|
|
43
|
+
let html = await options.renderDocumentToString(docElement);
|
|
39
44
|
html = html.replace("__NEXT_MAIN__", bodyMarker);
|
|
40
45
|
if (options.ssrHeadHTML || options.assetTags || fontHeadHTML) html = html.replace("</head>", ` ${fontHeadHTML}${options.ssrHeadHTML}\n ${options.assetTags}\n</head>`);
|
|
41
46
|
html = html.replace("<!-- __NEXT_SCRIPTS__ -->", nextDataScript);
|
|
@@ -45,8 +50,6 @@ async function buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, opt
|
|
|
45
50
|
return `<!DOCTYPE html>
|
|
46
51
|
<html>
|
|
47
52
|
<head>
|
|
48
|
-
<meta charset="utf-8" />
|
|
49
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
50
53
|
${fontHeadHTML}${options.ssrHeadHTML}\n ${options.assetTags}\n</head>
|
|
51
54
|
<body>
|
|
52
55
|
<div id="__next">${bodyMarker}</div>\n ${nextDataScript}\n</body>
|
|
@@ -113,7 +116,6 @@ function applyGsspHeaders(headers, gsspRes, statusCode) {
|
|
|
113
116
|
return statusCode ?? gsspRes.statusCode;
|
|
114
117
|
}
|
|
115
118
|
async function renderPagesPageResponse(options) {
|
|
116
|
-
const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)), options.scriptNonce);
|
|
117
119
|
options.resetSSRHead?.();
|
|
118
120
|
await options.flushPreloads?.();
|
|
119
121
|
const fontHeadHTML = buildPagesFontHeadHtml(options.getFontLinks(), options.fontPreloads, options.getFontStyles(), options.scriptNonce);
|
|
@@ -129,12 +131,40 @@ async function renderPagesPageResponse(options) {
|
|
|
129
131
|
vinext: options.vinext
|
|
130
132
|
});
|
|
131
133
|
const bodyMarker = "<!--VINEXT_STREAM_BODY-->";
|
|
132
|
-
const
|
|
134
|
+
const documentRenderPage = await runDocumentRenderPage({
|
|
135
|
+
DocumentComponent: options.DocumentComponent,
|
|
136
|
+
enhancePageElement: options.enhancePageElement,
|
|
137
|
+
renderToReadableStream: options.renderToReadableStream,
|
|
138
|
+
renderStylesToString: async (element) => readStreamAsText(await options.renderToReadableStream(element)),
|
|
139
|
+
scriptNonce: options.scriptNonce,
|
|
140
|
+
context: {
|
|
141
|
+
pathname: options.routePattern,
|
|
142
|
+
query: options.params,
|
|
143
|
+
asPath: options.routeUrl
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
let bodyStream;
|
|
147
|
+
if (documentRenderPage.status === "rendered") bodyStream = new ReadableStream({ start(controller) {
|
|
148
|
+
controller.enqueue(new TextEncoder().encode(documentRenderPage.bodyHtml));
|
|
149
|
+
controller.close();
|
|
150
|
+
} });
|
|
151
|
+
else {
|
|
152
|
+
const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)), options.scriptNonce);
|
|
153
|
+
bodyStream = await options.renderToReadableStream(pageElement);
|
|
154
|
+
}
|
|
155
|
+
if (documentRenderPage.status === "skipped") await callDocumentGetInitialProps(options.DocumentComponent, options.setDocumentInitialHead);
|
|
156
|
+
else options.setDocumentInitialHead?.(documentRenderPage.head);
|
|
157
|
+
const headFromShim = options.getSSRHeadHTML?.() ?? "";
|
|
158
|
+
const traceMetaHTML = getClientTraceMetadataHTML(options.clientTraceMetadata);
|
|
159
|
+
let ssrHeadHTML = headFromShim;
|
|
160
|
+
if (traceMetaHTML) ssrHeadHTML += `\n ${traceMetaHTML}`;
|
|
161
|
+
if (documentRenderPage.status === "rendered" && documentRenderPage.stylesHTML) ssrHeadHTML += `\n ${documentRenderPage.stylesHTML}`;
|
|
133
162
|
const shellHtml = await buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, {
|
|
134
163
|
assetTags: options.assetTags,
|
|
135
164
|
DocumentComponent: options.DocumentComponent,
|
|
136
165
|
renderDocumentToString: options.renderDocumentToString,
|
|
137
|
-
ssrHeadHTML
|
|
166
|
+
ssrHeadHTML,
|
|
167
|
+
resolvedDocProps: documentRenderPage.status === "skipped" ? null : documentRenderPage.docProps
|
|
138
168
|
});
|
|
139
169
|
options.clearSsrContext();
|
|
140
170
|
const markerIndex = shellHtml.indexOf(bodyMarker);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages-page-response.js","names":[],"sources":["../../src/server/pages-page-response.ts"],"sourcesContent":["import React, { type ComponentType, type ReactNode } from \"react\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\nimport type { CachedPagesValue } from \"vinext/shims/cache\";\nimport { withScriptNonce } from \"vinext/shims/script-nonce-context\";\nimport { getRequestExecutionContext } from \"vinext/shims/request-context\";\nimport { buildRevalidateCacheControl } from \"./cache-control.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from \"./html.js\";\nimport { reportRequestError } from \"./instrumentation.js\";\nimport { readStreamAsText } from \"../utils/text-stream.js\";\n\ntype PagesFontPreload = {\n href: string;\n type: string;\n};\n\nexport type PagesI18nRenderContext = {\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n domainLocales?: unknown;\n};\n\nexport type PagesGsspResponse = {\n statusCode: number;\n getHeaders(): Record<string, string | number | boolean | string[]>;\n};\n\ntype PagesStreamedHtmlResponse = {\n __vinextStreamedHtmlResponse?: boolean;\n} & Response;\n\ntype RenderPagesPageResponseOptions = {\n assetTags: string;\n buildId: string | null;\n clearSsrContext: () => void;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n DocumentComponent: ComponentType | null;\n flushPreloads?: (() => Promise<void> | void) | undefined;\n fontLinkHeader: string;\n fontPreloads: PagesFontPreload[];\n getFontLinks: () => string[];\n getFontStyles: () => string[];\n getSSRHeadHTML?: (() => string) | undefined;\n gsspRes: PagesGsspResponse | null;\n isrCacheKey: (router: string, pathname: string) => string;\n expireSeconds?: number;\n isrRevalidateSeconds: number | null;\n isrSet: (\n key: string,\n data: CachedPagesValue,\n revalidateSeconds: number,\n tags?: string[],\n expireSeconds?: number,\n ) => Promise<void>;\n i18n: PagesI18nRenderContext;\n /**\n * True when rendering a `getStaticPaths` fallback shell for a path that\n * isn't pre-rendered (`fallback: true` + unlisted path). Forwarded to\n * `buildPagesNextDataScript` so the client serialises `isFallback: true`\n * into `__NEXT_DATA__`, then later hydrates by fetching the data URL.\n */\n isFallback?: boolean;\n pageProps: Record<string, unknown>;\n params: Record<string, unknown>;\n renderDocumentToString: (element: ReactNode) => Promise<string>;\n renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;\n resetSSRHead?: (() => void) | undefined;\n routePattern: string;\n routeUrl: string;\n safeJsonStringify: (value: unknown) => string;\n scriptNonce?: string;\n statusCode?: number;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\nfunction buildPagesFontHeadHtml(\n fontLinks: string[],\n fontPreloads: PagesFontPreload[],\n fontStyles: string[],\n scriptNonce?: string,\n): string {\n let html = \"\";\n const nonceAttr = createNonceAttribute(scriptNonce);\n\n for (const link of fontLinks) {\n html += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(link)}\" />\\n `;\n }\n\n for (const preload of fontPreloads) {\n html += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n `;\n }\n\n if (fontStyles.length > 0) {\n html += `<style data-vinext-fonts${nonceAttr}>${fontStyles.join(\"\\n\")}</style>\\n `;\n }\n\n return html;\n}\n\nexport function buildPagesNextDataScript(\n options: Pick<\n RenderPagesPageResponseOptions,\n | \"buildId\"\n | \"i18n\"\n | \"isFallback\"\n | \"pageProps\"\n | \"params\"\n | \"routePattern\"\n | \"safeJsonStringify\"\n | \"scriptNonce\"\n > & {\n vinext?: VinextNextData[\"__vinext\"];\n },\n): string {\n const nextDataPayload: Record<string, unknown> = {\n props: { pageProps: options.pageProps },\n page: options.routePattern,\n query: options.params,\n buildId: options.buildId,\n isFallback: options.isFallback === true,\n };\n\n if (options.i18n.locales) {\n nextDataPayload.locale = options.i18n.locale;\n nextDataPayload.locales = options.i18n.locales;\n nextDataPayload.defaultLocale = options.i18n.defaultLocale;\n nextDataPayload.domainLocales = options.i18n.domainLocales;\n }\n\n if (options.vinext) {\n nextDataPayload.__vinext = options.vinext;\n }\n\n const localeGlobals = options.i18n.locales\n ? `;window.__VINEXT_LOCALE__=${options.safeJsonStringify(options.i18n.locale)}` +\n `;window.__VINEXT_LOCALES__=${options.safeJsonStringify(options.i18n.locales)}` +\n `;window.__VINEXT_DEFAULT_LOCALE__=${options.safeJsonStringify(options.i18n.defaultLocale)}`\n : \"\";\n\n return createInlineScriptTag(\n `window.__NEXT_DATA__ = ${options.safeJsonStringify(nextDataPayload)}${localeGlobals}`,\n options.scriptNonce,\n );\n}\n\nasync function buildPagesShellHtml(\n bodyMarker: string,\n fontHeadHTML: string,\n nextDataScript: string,\n options: Pick<\n RenderPagesPageResponseOptions,\n \"assetTags\" | \"DocumentComponent\" | \"renderDocumentToString\"\n > & {\n ssrHeadHTML: string;\n },\n): Promise<string> {\n if (options.DocumentComponent) {\n let html = await options.renderDocumentToString(React.createElement(options.DocumentComponent));\n html = html.replace(\"__NEXT_MAIN__\", bodyMarker);\n if (options.ssrHeadHTML || options.assetTags || fontHeadHTML) {\n html = html.replace(\n \"</head>\",\n ` ${fontHeadHTML}${options.ssrHeadHTML}\\n ${options.assetTags}\\n</head>`,\n );\n }\n html = html.replace(\"<!-- __NEXT_SCRIPTS__ -->\", nextDataScript);\n if (!html.includes(\"__NEXT_DATA__\")) {\n html = html.replace(\"</body>\", ` ${nextDataScript}\\n</body>`);\n }\n return html;\n }\n\n return (\n \"<!DOCTYPE html>\\n<html>\\n<head>\\n\" +\n ' <meta charset=\"utf-8\" />\\n' +\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\\n' +\n ` ${fontHeadHTML}${options.ssrHeadHTML}\\n` +\n ` ${options.assetTags}\\n` +\n \"</head>\\n<body>\\n\" +\n ` <div id=\"__next\">${bodyMarker}</div>\\n` +\n ` ${nextDataScript}\\n` +\n \"</body>\\n</html>\"\n );\n}\n\nasync function buildPagesCompositeStream(\n bodyStream: ReadableStream<Uint8Array>,\n shellPrefix: string,\n shellSuffix: string,\n): Promise<ReadableStream<Uint8Array>> {\n const encoder = new TextEncoder();\n\n return new ReadableStream({\n async start(controller) {\n controller.enqueue(encoder.encode(shellPrefix));\n const reader = bodyStream.getReader();\n try {\n for (;;) {\n const chunk = await reader.read();\n if (chunk.done) {\n break;\n }\n controller.enqueue(chunk.value);\n }\n } finally {\n reader.releaseLock();\n }\n controller.enqueue(encoder.encode(shellSuffix));\n controller.close();\n },\n });\n}\n\nasync function reportPagesIsrCacheWriteError(\n error: unknown,\n cacheKey: string,\n routePattern: string,\n): Promise<void> {\n console.error(`[vinext] Pages ISR cache write failed for ${cacheKey}:`, error);\n try {\n await reportRequestError(\n error instanceof Error ? error : new Error(String(error)),\n { path: cacheKey, method: \"GET\", headers: {} },\n {\n routerKind: \"Pages Router\",\n routePath: routePattern,\n routeType: \"render\",\n },\n );\n } catch {\n // Cache-write failure reporting must never make the background task reject.\n }\n}\n\nfunction schedulePagesIsrCacheWrite(options: {\n cacheKey: string;\n expireSeconds?: number;\n pageData: Record<string, unknown>;\n revalidateSeconds: number;\n routePattern: string;\n shellPrefix: string;\n shellSuffix: string;\n status: number;\n stream: ReadableStream<Uint8Array>;\n setCache: RenderPagesPageResponseOptions[\"isrSet\"];\n}): void {\n const cacheWritePromise = readStreamAsText(options.stream)\n .then((bodyHtml) =>\n options.setCache(\n options.cacheKey,\n {\n kind: \"PAGES\",\n html: options.shellPrefix + bodyHtml + options.shellSuffix,\n pageData: options.pageData,\n headers: undefined,\n status: options.status,\n },\n options.revalidateSeconds,\n undefined,\n options.expireSeconds,\n ),\n )\n .catch((error: unknown) =>\n reportPagesIsrCacheWriteError(error, options.cacheKey, options.routePattern),\n );\n\n getRequestExecutionContext()?.waitUntil(cacheWritePromise);\n}\n\nfunction applyGsspHeaders(\n headers: Headers,\n gsspRes: PagesGsspResponse | null,\n statusCode?: number,\n): number {\n if (!gsspRes) {\n return statusCode ?? 200;\n }\n\n const gsspHeaders = gsspRes.getHeaders();\n for (const key of Object.keys(gsspHeaders)) {\n const value = gsspHeaders[key];\n const lowerKey = key.toLowerCase();\n if (lowerKey === \"set-cookie\" && Array.isArray(value)) {\n for (const cookie of value) {\n headers.append(\"set-cookie\", String(cookie));\n }\n continue;\n }\n if (Array.isArray(value)) {\n headers.set(key, value.join(\", \"));\n continue;\n }\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n headers.set(key, String(value));\n }\n }\n headers.set(\"Content-Type\", \"text/html\");\n return statusCode ?? gsspRes.statusCode;\n}\n\nexport async function renderPagesPageResponse(\n options: RenderPagesPageResponseOptions,\n): Promise<Response> {\n const pageElement = withScriptNonce(\n React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)),\n options.scriptNonce,\n );\n\n options.resetSSRHead?.();\n await options.flushPreloads?.();\n\n const fontHeadHTML = buildPagesFontHeadHtml(\n options.getFontLinks(),\n options.fontPreloads,\n options.getFontStyles(),\n options.scriptNonce,\n );\n const nextDataScript = buildPagesNextDataScript({\n buildId: options.buildId,\n i18n: options.i18n,\n isFallback: options.isFallback,\n pageProps: options.pageProps,\n params: options.params,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n scriptNonce: options.scriptNonce,\n vinext: options.vinext,\n });\n const bodyMarker = \"<!--VINEXT_STREAM_BODY-->\";\n // Render the page FIRST so that <Head> and other SSR state collectors\n // (e.g. styled-jsx, useServerInsertedHTML) are populated before we read\n // them. This fixes a race condition where head styles were silently dropped\n // because they were collected before the page had finished rendering.\n // Mirrors Next.js fix: vercel/next.js@9853944\n const bodyStream = await options.renderToReadableStream(pageElement);\n\n const shellHtml = await buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, {\n assetTags: options.assetTags,\n DocumentComponent: options.DocumentComponent,\n renderDocumentToString: options.renderDocumentToString,\n ssrHeadHTML: options.getSSRHeadHTML?.() ?? \"\",\n });\n\n options.clearSsrContext();\n\n const markerIndex = shellHtml.indexOf(bodyMarker);\n const shellPrefix = shellHtml.slice(0, markerIndex);\n const shellSuffix = shellHtml.slice(markerIndex + bodyMarker.length);\n const responseHeaders = new Headers({ \"Content-Type\": \"text/html\" });\n const finalStatus = applyGsspHeaders(responseHeaders, options.gsspRes, options.statusCode);\n\n let responseBodyStream = bodyStream;\n if (\n // Keep nonce-bearing pages out of ISR writes: rewritePagesCachedHtml()\n // later matches the cached __NEXT_DATA__ block via a bare <script> marker.\n !options.scriptNonce &&\n options.isrRevalidateSeconds !== null &&\n options.isrRevalidateSeconds > 0\n ) {\n const cacheBodyStreamPair = bodyStream.tee();\n responseBodyStream = cacheBodyStreamPair[0];\n const cacheBodyStream = cacheBodyStreamPair[1];\n const isrPathname = options.routeUrl.split(\"?\")[0];\n const cacheKey = options.isrCacheKey(\"pages\", isrPathname);\n\n schedulePagesIsrCacheWrite({\n cacheKey,\n expireSeconds: options.expireSeconds,\n pageData: options.pageProps,\n revalidateSeconds: options.isrRevalidateSeconds,\n routePattern: options.routePattern,\n setCache: options.isrSet,\n shellPrefix,\n shellSuffix,\n status: finalStatus,\n stream: cacheBodyStream,\n });\n }\n\n const compositeStream = await buildPagesCompositeStream(\n responseBodyStream,\n shellPrefix,\n shellSuffix,\n );\n\n // Capture user-set Cache-Control (from getServerSideProps's res.setHeader)\n // so a downstream user override survives the gssp default below, and only\n // the default, never ISR/nonce Cache-Control which the runtime owns. Matches\n // Next.js's pages-handler.ts: `if (!res.getHeader('Cache-Control'))`.\n // responseHeaders/finalStatus are declared above so finalStatus can also feed\n // the ISR cache write; applyGsspHeaders is the only Cache-Control writer before\n // this point, so the captured value matches main's original capture site.\n const userSetCacheControl = responseHeaders.has(\"Cache-Control\");\n\n if (options.scriptNonce) {\n responseHeaders.set(\"Cache-Control\", \"no-store, must-revalidate\");\n } else if (options.isrRevalidateSeconds) {\n responseHeaders.set(\n \"Cache-Control\",\n buildRevalidateCacheControl(options.isrRevalidateSeconds, options.expireSeconds),\n );\n setCacheStateHeaders(responseHeaders, \"MISS\");\n } else if (options.gsspRes && !userSetCacheControl) {\n // Default for getServerSideProps responses, matching Next.js\n // pages-handler.ts (revalidate: 0 → getCacheControlHeader). Without this,\n // CDNs and browsers could cache per-request gssp responses.\n responseHeaders.set(\"Cache-Control\", \"private, no-cache, no-store, max-age=0, must-revalidate\");\n }\n if (options.fontLinkHeader) {\n responseHeaders.set(\"Link\", options.fontLinkHeader);\n }\n\n const response: PagesStreamedHtmlResponse = Object.assign(\n new Response(compositeStream, {\n status: finalStatus,\n headers: responseHeaders,\n }),\n {\n __vinextStreamedHtmlResponse: true,\n },\n );\n // Mark the normal streamed HTML render so the Node prod server can strip\n // stale Content-Length only for this path, not for custom gSSP responses.\n return response;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pages-page-response.js","names":[],"sources":["../../src/server/pages-page-response.ts"],"sourcesContent":["import React, { type ComponentType, type ReactNode } from \"react\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\nimport type { CachedPagesValue } from \"vinext/shims/cache\";\nimport { withScriptNonce } from \"vinext/shims/script-nonce-context\";\nimport { getRequestExecutionContext } from \"vinext/shims/request-context\";\nimport { buildRevalidateCacheControl } from \"./cache-control.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from \"./html.js\";\nimport { getClientTraceMetadataHTML } from \"./client-trace-metadata.js\";\nimport { reportRequestError } from \"./instrumentation.js\";\nimport {\n loadUserDocumentInitialProps,\n type RenderPageEnhancers,\n runDocumentRenderPage,\n} from \"./pages-document-initial-props.js\";\nimport { readStreamAsText } from \"../utils/text-stream.js\";\nimport { callDocumentGetInitialProps } from \"./document-initial-head.js\";\n\ntype PagesFontPreload = {\n href: string;\n type: string;\n};\n\nexport type PagesI18nRenderContext = {\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n domainLocales?: unknown;\n};\n\nexport type PagesGsspResponse = {\n statusCode: number;\n getHeaders(): Record<string, string | number | boolean | string[]>;\n};\n\ntype PagesStreamedHtmlResponse = {\n __vinextStreamedHtmlResponse?: boolean;\n} & Response;\n\ntype RenderPagesPageResponseOptions = {\n assetTags: string;\n buildId: string | null;\n clearSsrContext: () => void;\n createPageElement: (pageProps: Record<string, unknown>) => ReactNode;\n /**\n * Build the page React tree with optional App/Component enhancers applied,\n * supporting the Pages Router `_document.getInitialProps` contract:\n *\n * ctx.renderPage({ enhanceApp, enhanceComponent })\n *\n * Used by CSS-in-JS libraries (styled-components, emotion) to wrap the\n * App/Component tree so styles can be collected during SSR. When omitted,\n * `renderPage` falls back to rendering the plain `createPageElement` tree\n * (enhancers are ignored).\n */\n enhancePageElement?: ((opts: RenderPageEnhancers) => ReactNode) | undefined;\n DocumentComponent: ComponentType | null;\n flushPreloads?: (() => Promise<void> | void) | undefined;\n fontLinkHeader: string;\n fontPreloads: PagesFontPreload[];\n getFontLinks: () => string[];\n getFontStyles: () => string[];\n getSSRHeadHTML?: (() => string) | undefined;\n /**\n * Allow-list of OpenTelemetry propagation keys (from\n * `experimental.clientTraceMetadata`) to emit as `<meta>` tags in the SSR\n * head. Undefined or empty disables emission.\n */\n clientTraceMetadata?: readonly string[] | undefined;\n setDocumentInitialHead?: ((head: ReactNode[]) => void) | undefined;\n gsspRes: PagesGsspResponse | null;\n isrCacheKey: (router: string, pathname: string) => string;\n expireSeconds?: number;\n isrRevalidateSeconds: number | null;\n isrSet: (\n key: string,\n data: CachedPagesValue,\n revalidateSeconds: number,\n tags?: string[],\n expireSeconds?: number,\n ) => Promise<void>;\n i18n: PagesI18nRenderContext;\n /**\n * True when rendering a `getStaticPaths` fallback shell for a path that\n * isn't pre-rendered (`fallback: true` + unlisted path). Forwarded to\n * `buildPagesNextDataScript` so the client serialises `isFallback: true`\n * into `__NEXT_DATA__`, then later hydrates by fetching the data URL.\n */\n isFallback?: boolean;\n pageProps: Record<string, unknown>;\n params: Record<string, unknown>;\n renderDocumentToString: (element: ReactNode) => Promise<string>;\n renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;\n resetSSRHead?: (() => void) | undefined;\n routePattern: string;\n routeUrl: string;\n safeJsonStringify: (value: unknown) => string;\n scriptNonce?: string;\n statusCode?: number;\n vinext?: VinextNextData[\"__vinext\"];\n};\n\nfunction buildPagesFontHeadHtml(\n fontLinks: string[],\n fontPreloads: PagesFontPreload[],\n fontStyles: string[],\n scriptNonce?: string,\n): string {\n let html = \"\";\n const nonceAttr = createNonceAttribute(scriptNonce);\n\n for (const link of fontLinks) {\n html += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(link)}\" />\\n `;\n }\n\n for (const preload of fontPreloads) {\n html += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n `;\n }\n\n if (fontStyles.length > 0) {\n html += `<style data-vinext-fonts${nonceAttr}>${fontStyles.join(\"\\n\")}</style>\\n `;\n }\n\n return html;\n}\n\nexport function buildPagesNextDataScript(\n options: Pick<\n RenderPagesPageResponseOptions,\n | \"buildId\"\n | \"i18n\"\n | \"isFallback\"\n | \"pageProps\"\n | \"params\"\n | \"routePattern\"\n | \"safeJsonStringify\"\n | \"scriptNonce\"\n > & {\n vinext?: VinextNextData[\"__vinext\"];\n },\n): string {\n const nextDataPayload: Record<string, unknown> = {\n props: { pageProps: options.pageProps },\n page: options.routePattern,\n query: options.params,\n buildId: options.buildId,\n isFallback: options.isFallback === true,\n };\n\n if (options.i18n.locales) {\n nextDataPayload.locale = options.i18n.locale;\n nextDataPayload.locales = options.i18n.locales;\n nextDataPayload.defaultLocale = options.i18n.defaultLocale;\n nextDataPayload.domainLocales = options.i18n.domainLocales;\n }\n\n if (options.vinext) {\n nextDataPayload.__vinext = options.vinext;\n }\n\n const localeGlobals = options.i18n.locales\n ? `;window.__VINEXT_LOCALE__=${options.safeJsonStringify(options.i18n.locale)}` +\n `;window.__VINEXT_LOCALES__=${options.safeJsonStringify(options.i18n.locales)}` +\n `;window.__VINEXT_DEFAULT_LOCALE__=${options.safeJsonStringify(options.i18n.defaultLocale)}`\n : \"\";\n\n return createInlineScriptTag(\n `window.__NEXT_DATA__ = ${options.safeJsonStringify(nextDataPayload)}${localeGlobals}`,\n options.scriptNonce,\n );\n}\n\nasync function buildPagesShellHtml(\n bodyMarker: string,\n fontHeadHTML: string,\n nextDataScript: string,\n options: Pick<\n RenderPagesPageResponseOptions,\n \"assetTags\" | \"DocumentComponent\" | \"renderDocumentToString\"\n > & {\n ssrHeadHTML: string;\n /**\n * Document props already resolved by `runDocumentRenderPage`. When set,\n * `getInitialProps` was consumed by the renderPage path and must not be\n * re-invoked via `loadUserDocumentInitialProps` (which would call it a\n * second time). `null` means use the normal fast path.\n */\n resolvedDocProps?: Record<string, unknown> | null;\n },\n): Promise<string> {\n if (options.DocumentComponent) {\n const docProps =\n options.resolvedDocProps ?? (await loadUserDocumentInitialProps(options.DocumentComponent));\n const docElement = docProps\n ? React.createElement(options.DocumentComponent, docProps)\n : React.createElement(options.DocumentComponent);\n let html = await options.renderDocumentToString(docElement);\n html = html.replace(\"__NEXT_MAIN__\", bodyMarker);\n if (options.ssrHeadHTML || options.assetTags || fontHeadHTML) {\n html = html.replace(\n \"</head>\",\n ` ${fontHeadHTML}${options.ssrHeadHTML}\\n ${options.assetTags}\\n</head>`,\n );\n }\n html = html.replace(\"<!-- __NEXT_SCRIPTS__ -->\", nextDataScript);\n if (!html.includes(\"__NEXT_DATA__\")) {\n html = html.replace(\"</body>\", ` ${nextDataScript}\\n</body>`);\n }\n return html;\n }\n\n // charset + viewport are emitted via getSSRHeadHTML() (next/head's\n // defaultHead seeds them with data-next-head=\"\"), matching Next.js's\n // canonical ordering. Don't duplicate them here.\n return (\n \"<!DOCTYPE html>\\n<html>\\n<head>\\n\" +\n ` ${fontHeadHTML}${options.ssrHeadHTML}\\n` +\n ` ${options.assetTags}\\n` +\n \"</head>\\n<body>\\n\" +\n ` <div id=\"__next\">${bodyMarker}</div>\\n` +\n ` ${nextDataScript}\\n` +\n \"</body>\\n</html>\"\n );\n}\n\nasync function buildPagesCompositeStream(\n bodyStream: ReadableStream<Uint8Array>,\n shellPrefix: string,\n shellSuffix: string,\n): Promise<ReadableStream<Uint8Array>> {\n const encoder = new TextEncoder();\n\n return new ReadableStream({\n async start(controller) {\n controller.enqueue(encoder.encode(shellPrefix));\n const reader = bodyStream.getReader();\n try {\n for (;;) {\n const chunk = await reader.read();\n if (chunk.done) {\n break;\n }\n controller.enqueue(chunk.value);\n }\n } finally {\n reader.releaseLock();\n }\n controller.enqueue(encoder.encode(shellSuffix));\n controller.close();\n },\n });\n}\n\nasync function reportPagesIsrCacheWriteError(\n error: unknown,\n cacheKey: string,\n routePattern: string,\n): Promise<void> {\n console.error(`[vinext] Pages ISR cache write failed for ${cacheKey}:`, error);\n try {\n await reportRequestError(\n error instanceof Error ? error : new Error(String(error)),\n { path: cacheKey, method: \"GET\", headers: {} },\n {\n routerKind: \"Pages Router\",\n routePath: routePattern,\n routeType: \"render\",\n },\n );\n } catch {\n // Cache-write failure reporting must never make the background task reject.\n }\n}\n\nfunction schedulePagesIsrCacheWrite(options: {\n cacheKey: string;\n expireSeconds?: number;\n pageData: Record<string, unknown>;\n revalidateSeconds: number;\n routePattern: string;\n shellPrefix: string;\n shellSuffix: string;\n status: number;\n stream: ReadableStream<Uint8Array>;\n setCache: RenderPagesPageResponseOptions[\"isrSet\"];\n}): void {\n const cacheWritePromise = readStreamAsText(options.stream)\n .then((bodyHtml) =>\n options.setCache(\n options.cacheKey,\n {\n kind: \"PAGES\",\n html: options.shellPrefix + bodyHtml + options.shellSuffix,\n pageData: options.pageData,\n headers: undefined,\n status: options.status,\n },\n options.revalidateSeconds,\n undefined,\n options.expireSeconds,\n ),\n )\n .catch((error: unknown) =>\n reportPagesIsrCacheWriteError(error, options.cacheKey, options.routePattern),\n );\n\n getRequestExecutionContext()?.waitUntil(cacheWritePromise);\n}\n\nfunction applyGsspHeaders(\n headers: Headers,\n gsspRes: PagesGsspResponse | null,\n statusCode?: number,\n): number {\n if (!gsspRes) {\n return statusCode ?? 200;\n }\n\n const gsspHeaders = gsspRes.getHeaders();\n for (const key of Object.keys(gsspHeaders)) {\n const value = gsspHeaders[key];\n const lowerKey = key.toLowerCase();\n if (lowerKey === \"set-cookie\" && Array.isArray(value)) {\n for (const cookie of value) {\n headers.append(\"set-cookie\", String(cookie));\n }\n continue;\n }\n if (Array.isArray(value)) {\n headers.set(key, value.join(\", \"));\n continue;\n }\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n headers.set(key, String(value));\n }\n }\n headers.set(\"Content-Type\", \"text/html\");\n return statusCode ?? gsspRes.statusCode;\n}\n\nexport async function renderPagesPageResponse(\n options: RenderPagesPageResponseOptions,\n): Promise<Response> {\n options.resetSSRHead?.();\n await options.flushPreloads?.();\n\n const fontHeadHTML = buildPagesFontHeadHtml(\n options.getFontLinks(),\n options.fontPreloads,\n options.getFontStyles(),\n options.scriptNonce,\n );\n const nextDataScript = buildPagesNextDataScript({\n buildId: options.buildId,\n i18n: options.i18n,\n isFallback: options.isFallback,\n pageProps: options.pageProps,\n params: options.params,\n routePattern: options.routePattern,\n safeJsonStringify: options.safeJsonStringify,\n scriptNonce: options.scriptNonce,\n vinext: options.vinext,\n });\n const bodyMarker = \"<!--VINEXT_STREAM_BODY-->\";\n\n // Custom `_document.getInitialProps()` may opt in to wrapping the page tree\n // via `ctx.renderPage({ enhanceApp, enhanceComponent })` (e.g. for\n // styled-components / emotion style collection). When that contract is in\n // use the body must be a single complete string before `_document` renders\n // — Next.js does this in `loadDocumentInitialProps` and we mirror it here.\n // The streaming path stays as the default for the common case where the\n // user does not define `getInitialProps`. The contract (including\n // `withScriptNonce` and `styles` rendering) lives in the shared helper so\n // prod and dev stay in lockstep.\n const documentRenderPage = await runDocumentRenderPage({\n DocumentComponent: options.DocumentComponent,\n enhancePageElement: options.enhancePageElement,\n renderToReadableStream: options.renderToReadableStream,\n // Render the collected `styles` fragment with the plain stream renderer\n // rather than the full `<Document>` shell renderer — the styles tree is a\n // standalone fragment, so it doesn't need the heavier document pipeline.\n // Mirrors the dev path, which passes its `renderToStringAsync` wrapper.\n renderStylesToString: async (element) =>\n readStreamAsText(await options.renderToReadableStream(element)),\n scriptNonce: options.scriptNonce,\n context: {\n pathname: options.routePattern,\n query: options.params,\n asPath: options.routeUrl,\n },\n });\n\n let bodyStream: ReadableStream<Uint8Array>;\n if (documentRenderPage.status === \"rendered\") {\n bodyStream = new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(new TextEncoder().encode(documentRenderPage.bodyHtml));\n controller.close();\n },\n });\n } else {\n // Render the page FIRST so that <Head> and other SSR state collectors\n // (e.g. styled-jsx, useServerInsertedHTML) are populated before we read\n // them. This fixes a race condition where head styles were silently dropped\n // because they were collected before the page had finished rendering.\n // Mirrors Next.js fix: vercel/next.js@9853944\n //\n // Built lazily here: when the renderPage contract produced the body\n // (`rendered`), this element is never used, so there's no point\n // constructing the tree on that path.\n const pageElement = withScriptNonce(\n React.createElement(React.Fragment, null, options.createPageElement(options.pageProps)),\n options.scriptNonce,\n );\n bodyStream = await options.renderToReadableStream(pageElement);\n }\n\n // Fold any head tags returned by `_document.getInitialProps()` into the\n // dedupe pipeline before getSSRHeadHTML serialises the final <head>. Mirrors\n // Next.js's `_document` contract. `runDocumentRenderPage` already invokes\n // `getInitialProps` for the renderPage contract (rendered/consumed), so reuse\n // the head it surfaced rather than calling it a second time. Only the\n // `skipped` path (no override, or no `enhancePageElement` wired) falls back to\n // the standalone helper — which itself skips the unmodified default shim.\n if (documentRenderPage.status === \"skipped\") {\n await callDocumentGetInitialProps(options.DocumentComponent, options.setDocumentInitialHead);\n } else {\n options.setDocumentInitialHead?.(documentRenderPage.head);\n }\n\n const headFromShim = options.getSSRHeadHTML?.() ?? \"\";\n // Trace meta tags from the active OpenTelemetry context. When the\n // allow-list is unset (the common case) or OTel is not installed,\n // `getClientTraceMetadataHTML` returns \"\" and we forward the head HTML\n // verbatim — keeping the no-op path zero-overhead.\n const traceMetaHTML = getClientTraceMetadataHTML(options.clientTraceMetadata);\n let ssrHeadHTML = headFromShim;\n if (traceMetaHTML) ssrHeadHTML += `\\n ${traceMetaHTML}`;\n // `styles` returned by `_document.getInitialProps()` (e.g. collected\n // styled-components / emotion <style> tags) is already rendered to a string\n // by the shared helper, ready to merge into the SSR head.\n if (documentRenderPage.status === \"rendered\" && documentRenderPage.stylesHTML) {\n ssrHeadHTML += `\\n ${documentRenderPage.stylesHTML}`;\n }\n const shellHtml = await buildPagesShellHtml(bodyMarker, fontHeadHTML, nextDataScript, {\n assetTags: options.assetTags,\n DocumentComponent: options.DocumentComponent,\n renderDocumentToString: options.renderDocumentToString,\n ssrHeadHTML,\n // When the renderPage path already invoked getInitialProps (rendered or\n // consumed), reuse its resolved props instead of calling it a second time.\n // `skipped` means it was never invoked → fall through to the fast path.\n resolvedDocProps: documentRenderPage.status === \"skipped\" ? null : documentRenderPage.docProps,\n });\n\n options.clearSsrContext();\n\n const markerIndex = shellHtml.indexOf(bodyMarker);\n const shellPrefix = shellHtml.slice(0, markerIndex);\n const shellSuffix = shellHtml.slice(markerIndex + bodyMarker.length);\n const responseHeaders = new Headers({ \"Content-Type\": \"text/html\" });\n const finalStatus = applyGsspHeaders(responseHeaders, options.gsspRes, options.statusCode);\n\n let responseBodyStream = bodyStream;\n if (\n // Keep nonce-bearing pages out of ISR writes: rewritePagesCachedHtml()\n // later matches the cached __NEXT_DATA__ block via a bare <script> marker.\n !options.scriptNonce &&\n options.isrRevalidateSeconds !== null &&\n options.isrRevalidateSeconds > 0\n ) {\n const cacheBodyStreamPair = bodyStream.tee();\n responseBodyStream = cacheBodyStreamPair[0];\n const cacheBodyStream = cacheBodyStreamPair[1];\n const isrPathname = options.routeUrl.split(\"?\")[0];\n const cacheKey = options.isrCacheKey(\"pages\", isrPathname);\n\n schedulePagesIsrCacheWrite({\n cacheKey,\n expireSeconds: options.expireSeconds,\n pageData: options.pageProps,\n revalidateSeconds: options.isrRevalidateSeconds,\n routePattern: options.routePattern,\n setCache: options.isrSet,\n shellPrefix,\n shellSuffix,\n status: finalStatus,\n stream: cacheBodyStream,\n });\n }\n\n const compositeStream = await buildPagesCompositeStream(\n responseBodyStream,\n shellPrefix,\n shellSuffix,\n );\n\n // Capture user-set Cache-Control (from getServerSideProps's res.setHeader)\n // so a downstream user override survives the gssp default below, and only\n // the default, never ISR/nonce Cache-Control which the runtime owns. Matches\n // Next.js's pages-handler.ts: `if (!res.getHeader('Cache-Control'))`.\n // responseHeaders/finalStatus are declared above so finalStatus can also feed\n // the ISR cache write; applyGsspHeaders is the only Cache-Control writer before\n // this point, so the captured value matches main's original capture site.\n const userSetCacheControl = responseHeaders.has(\"Cache-Control\");\n\n if (options.scriptNonce) {\n responseHeaders.set(\"Cache-Control\", \"no-store, must-revalidate\");\n } else if (options.isrRevalidateSeconds) {\n responseHeaders.set(\n \"Cache-Control\",\n buildRevalidateCacheControl(options.isrRevalidateSeconds, options.expireSeconds),\n );\n setCacheStateHeaders(responseHeaders, \"MISS\");\n } else if (options.gsspRes && !userSetCacheControl) {\n // Default for getServerSideProps responses, matching Next.js\n // pages-handler.ts (revalidate: 0 → getCacheControlHeader). Without this,\n // CDNs and browsers could cache per-request gssp responses.\n responseHeaders.set(\"Cache-Control\", \"private, no-cache, no-store, max-age=0, must-revalidate\");\n }\n if (options.fontLinkHeader) {\n responseHeaders.set(\"Link\", options.fontLinkHeader);\n }\n\n const response: PagesStreamedHtmlResponse = Object.assign(\n new Response(compositeStream, {\n status: finalStatus,\n headers: responseHeaders,\n }),\n {\n __vinextStreamedHtmlResponse: true,\n },\n );\n // Mark the normal streamed HTML render so the Node prod server can strip\n // stale Content-Length only for this path, not for custom gSSP responses.\n return response;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/server/pages-serializable-props.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validate that the value returned as `props` from `getStaticProps` /
|
|
4
|
+
* `getServerSideProps` is JSON-serializable. Throws a friendly
|
|
5
|
+
* `SerializableError` matching Next.js's error shape if it isn't.
|
|
6
|
+
*
|
|
7
|
+
* Ported from Next.js:
|
|
8
|
+
* .nextjs-ref/packages/next/src/lib/is-serializable-props.ts
|
|
9
|
+
* .nextjs-ref/packages/next/src/shared/lib/is-plain-object.ts
|
|
10
|
+
*
|
|
11
|
+
* Tested in Next.js by `test/unit/is-serializable-props.test.ts` and the
|
|
12
|
+
* `non-json` / `non-json-blocking` cases in `test/e2e/prerender.test.ts`.
|
|
13
|
+
*
|
|
14
|
+
* Next.js calls this from `packages/next/src/server/render.tsx` for both
|
|
15
|
+
* `getStaticProps` and `getServerSideProps`. We do the same in
|
|
16
|
+
* `pages-page-data.ts` so users see a clear error instead of an empty page
|
|
17
|
+
* when they accidentally return a `Date`, `Map`, or class instance.
|
|
18
|
+
*/
|
|
19
|
+
declare class SerializableError extends Error {
|
|
20
|
+
constructor(page: string, method: string, path: string, message: string);
|
|
21
|
+
}
|
|
22
|
+
declare function isSerializableProps(page: string, method: string, input: unknown): true;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { SerializableError, isSerializableProps };
|
|
25
|
+
//# sourceMappingURL=pages-serializable-props.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region src/server/pages-serializable-props.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validate that the value returned as `props` from `getStaticProps` /
|
|
4
|
+
* `getServerSideProps` is JSON-serializable. Throws a friendly
|
|
5
|
+
* `SerializableError` matching Next.js's error shape if it isn't.
|
|
6
|
+
*
|
|
7
|
+
* Ported from Next.js:
|
|
8
|
+
* .nextjs-ref/packages/next/src/lib/is-serializable-props.ts
|
|
9
|
+
* .nextjs-ref/packages/next/src/shared/lib/is-plain-object.ts
|
|
10
|
+
*
|
|
11
|
+
* Tested in Next.js by `test/unit/is-serializable-props.test.ts` and the
|
|
12
|
+
* `non-json` / `non-json-blocking` cases in `test/e2e/prerender.test.ts`.
|
|
13
|
+
*
|
|
14
|
+
* Next.js calls this from `packages/next/src/server/render.tsx` for both
|
|
15
|
+
* `getStaticProps` and `getServerSideProps`. We do the same in
|
|
16
|
+
* `pages-page-data.ts` so users see a clear error instead of an empty page
|
|
17
|
+
* when they accidentally return a `Date`, `Map`, or class instance.
|
|
18
|
+
*/
|
|
19
|
+
function getObjectClassLabel(value) {
|
|
20
|
+
return Object.prototype.toString.call(value);
|
|
21
|
+
}
|
|
22
|
+
function isPlainObject(value) {
|
|
23
|
+
if (getObjectClassLabel(value) !== "[object Object]") return false;
|
|
24
|
+
const prototype = Object.getPrototypeOf(value);
|
|
25
|
+
return prototype === null || Object.prototype.hasOwnProperty.call(prototype, "isPrototypeOf");
|
|
26
|
+
}
|
|
27
|
+
const REGEX_PLAIN_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
28
|
+
var SerializableError = class extends Error {
|
|
29
|
+
constructor(page, method, path, message) {
|
|
30
|
+
super(path ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}`);
|
|
31
|
+
this.name = "SerializableError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
function isSerializableProps(page, method, input) {
|
|
35
|
+
if (!isPlainObject(input)) throw new SerializableError(page, method, "", `Props must be returned as a plain object from ${method}: \`{ props: { ... } }\` (received: \`${getObjectClassLabel(input)}\`).`);
|
|
36
|
+
function visit(visited, value, path) {
|
|
37
|
+
if (visited.has(value)) throw new SerializableError(page, method, path, `Circular references cannot be expressed in JSON (references: \`${visited.get(value) || "(self)"}\`).`);
|
|
38
|
+
visited.set(value, path);
|
|
39
|
+
}
|
|
40
|
+
function isSerializable(refs, value, path) {
|
|
41
|
+
const type = typeof value;
|
|
42
|
+
if (value === null || type === "boolean" || type === "number" || type === "string") return true;
|
|
43
|
+
if (type === "undefined") throw new SerializableError(page, method, path, "`undefined` cannot be serialized as JSON. Please use `null` or omit this value.");
|
|
44
|
+
if (isPlainObject(value)) {
|
|
45
|
+
visit(refs, value, path);
|
|
46
|
+
const entries = Object.entries(value);
|
|
47
|
+
for (const [key, nestedValue] of entries) {
|
|
48
|
+
const nextPath = REGEX_PLAIN_IDENTIFIER.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
|
|
49
|
+
const newRefs = new Map(refs);
|
|
50
|
+
isSerializable(newRefs, key, nextPath);
|
|
51
|
+
isSerializable(newRefs, nestedValue, nextPath);
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
visit(refs, value, path);
|
|
57
|
+
value.forEach((nestedValue, index) => {
|
|
58
|
+
isSerializable(new Map(refs), nestedValue, `${path}[${index}]`);
|
|
59
|
+
});
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
throw new SerializableError(page, method, path, `\`${type}\`${type === "object" ? ` ("${Object.prototype.toString.call(value)}")` : ""} cannot be serialized as JSON. Please only return JSON serializable data types.`);
|
|
63
|
+
}
|
|
64
|
+
return isSerializable(/* @__PURE__ */ new Map(), input, "");
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { SerializableError, isSerializableProps };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=pages-serializable-props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages-serializable-props.js","names":[],"sources":["../../src/server/pages-serializable-props.ts"],"sourcesContent":["/**\n * Validate that the value returned as `props` from `getStaticProps` /\n * `getServerSideProps` is JSON-serializable. Throws a friendly\n * `SerializableError` matching Next.js's error shape if it isn't.\n *\n * Ported from Next.js:\n * .nextjs-ref/packages/next/src/lib/is-serializable-props.ts\n * .nextjs-ref/packages/next/src/shared/lib/is-plain-object.ts\n *\n * Tested in Next.js by `test/unit/is-serializable-props.test.ts` and the\n * `non-json` / `non-json-blocking` cases in `test/e2e/prerender.test.ts`.\n *\n * Next.js calls this from `packages/next/src/server/render.tsx` for both\n * `getStaticProps` and `getServerSideProps`. We do the same in\n * `pages-page-data.ts` so users see a clear error instead of an empty page\n * when they accidentally return a `Date`, `Map`, or class instance.\n */\n\nfunction getObjectClassLabel(value: unknown): string {\n return Object.prototype.toString.call(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (getObjectClassLabel(value) !== \"[object Object]\") {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n\n // Mirrors Next.js's resilient prototype check — see the docstring in\n // .nextjs-ref/packages/next/src/shared/lib/is-plain-object.ts for the\n // explanation. `prototype.hasOwnProperty('isPrototypeOf')` lets us treat\n // cross-realm `Object` instances (vm boundaries, structuredClone) as plain.\n return prototype === null || Object.prototype.hasOwnProperty.call(prototype, \"isPrototypeOf\");\n}\n\nconst REGEX_PLAIN_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\nexport class SerializableError extends Error {\n constructor(page: string, method: string, path: string, message: string) {\n super(\n path\n ? `Error serializing \\`${path}\\` returned from \\`${method}\\` in \"${page}\".\\nReason: ${message}`\n : `Error serializing props returned from \\`${method}\\` in \"${page}\".\\nReason: ${message}`,\n );\n this.name = \"SerializableError\";\n }\n}\n\nexport function isSerializableProps(page: string, method: string, input: unknown): true {\n if (!isPlainObject(input)) {\n throw new SerializableError(\n page,\n method,\n \"\",\n `Props must be returned as a plain object from ${method}: \\`{ props: { ... } }\\` (received: \\`${getObjectClassLabel(\n input,\n )}\\`).`,\n );\n }\n\n function visit(visited: Map<unknown, string>, value: unknown, path: string): void {\n if (visited.has(value)) {\n throw new SerializableError(\n page,\n method,\n path,\n `Circular references cannot be expressed in JSON (references: \\`${\n visited.get(value) || \"(self)\"\n }\\`).`,\n );\n }\n visited.set(value, path);\n }\n\n function isSerializable(refs: Map<unknown, string>, value: unknown, path: string): true {\n const type = typeof value;\n if (\n // `null` is JSON-serializable, but `undefined` is not.\n value === null ||\n // `bigint`, `function`, `symbol`, and `undefined` are not serializable;\n // `object` is special-cased below.\n type === \"boolean\" ||\n type === \"number\" ||\n type === \"string\"\n ) {\n return true;\n }\n\n if (type === \"undefined\") {\n throw new SerializableError(\n page,\n method,\n path,\n \"`undefined` cannot be serialized as JSON. Please use `null` or omit this value.\",\n );\n }\n\n if (isPlainObject(value)) {\n visit(refs, value, path);\n\n const entries = Object.entries(value);\n for (const [key, nestedValue] of entries) {\n const nextPath = REGEX_PLAIN_IDENTIFIER.test(key)\n ? `${path}.${key}`\n : `${path}[${JSON.stringify(key)}]`;\n const newRefs = new Map(refs);\n isSerializable(newRefs, key, nextPath);\n isSerializable(newRefs, nestedValue, nextPath);\n }\n return true;\n }\n\n if (Array.isArray(value)) {\n visit(refs, value, path);\n\n value.forEach((nestedValue, index) => {\n const newRefs = new Map(refs);\n isSerializable(newRefs, nestedValue, `${path}[${index}]`);\n });\n return true;\n }\n\n throw new SerializableError(\n page,\n method,\n path,\n `\\`${type}\\`${\n type === \"object\" ? ` (\"${Object.prototype.toString.call(value)}\")` : \"\"\n } cannot be serialized as JSON. Please only return JSON serializable data types.`,\n );\n }\n\n return isSerializable(new Map(), input, \"\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAS,oBAAoB,OAAwB;CACnD,OAAO,OAAO,UAAU,SAAS,KAAK,MAAM;;AAG9C,SAAS,cAAc,OAAkD;CACvE,IAAI,oBAAoB,MAAM,KAAK,mBACjC,OAAO;CAET,MAAM,YAAY,OAAO,eAAe,MAAM;CAM9C,OAAO,cAAc,QAAQ,OAAO,UAAU,eAAe,KAAK,WAAW,gBAAgB;;AAG/F,MAAM,yBAAyB;AAE/B,IAAa,oBAAb,cAAuC,MAAM;CAC3C,YAAY,MAAc,QAAgB,MAAc,SAAiB;EACvE,MACE,OACI,uBAAuB,KAAK,qBAAqB,OAAO,SAAS,KAAK,cAAc,YACpF,2CAA2C,OAAO,SAAS,KAAK,cAAc,UACnF;EACD,KAAK,OAAO;;;AAIhB,SAAgB,oBAAoB,MAAc,QAAgB,OAAsB;CACtF,IAAI,CAAC,cAAc,MAAM,EACvB,MAAM,IAAI,kBACR,MACA,QACA,IACA,iDAAiD,OAAO,wCAAwC,oBAC9F,MACD,CAAC,MACH;CAGH,SAAS,MAAM,SAA+B,OAAgB,MAAoB;EAChF,IAAI,QAAQ,IAAI,MAAM,EACpB,MAAM,IAAI,kBACR,MACA,QACA,MACA,kEACE,QAAQ,IAAI,MAAM,IAAI,SACvB,MACF;EAEH,QAAQ,IAAI,OAAO,KAAK;;CAG1B,SAAS,eAAe,MAA4B,OAAgB,MAAoB;EACtF,MAAM,OAAO,OAAO;EACpB,IAEE,UAAU,QAGV,SAAS,aACT,SAAS,YACT,SAAS,UAET,OAAO;EAGT,IAAI,SAAS,aACX,MAAM,IAAI,kBACR,MACA,QACA,MACA,kFACD;EAGH,IAAI,cAAc,MAAM,EAAE;GACxB,MAAM,MAAM,OAAO,KAAK;GAExB,MAAM,UAAU,OAAO,QAAQ,MAAM;GACrC,KAAK,MAAM,CAAC,KAAK,gBAAgB,SAAS;IACxC,MAAM,WAAW,uBAAuB,KAAK,IAAI,GAC7C,GAAG,KAAK,GAAG,QACX,GAAG,KAAK,GAAG,KAAK,UAAU,IAAI,CAAC;IACnC,MAAM,UAAU,IAAI,IAAI,KAAK;IAC7B,eAAe,SAAS,KAAK,SAAS;IACtC,eAAe,SAAS,aAAa,SAAS;;GAEhD,OAAO;;EAGT,IAAI,MAAM,QAAQ,MAAM,EAAE;GACxB,MAAM,MAAM,OAAO,KAAK;GAExB,MAAM,SAAS,aAAa,UAAU;IAEpC,eAAe,IADK,IAAI,KACF,EAAE,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG;KACzD;GACF,OAAO;;EAGT,MAAM,IAAI,kBACR,MACA,QACA,MACA,KAAK,KAAK,IACR,SAAS,WAAW,MAAM,OAAO,UAAU,SAAS,KAAK,MAAM,CAAC,MAAM,GACvE,iFACF;;CAGH,OAAO,+BAAe,IAAI,KAAK,EAAE,OAAO,GAAG"}
|