vinext 0.0.52 → 0.0.54
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 -1
- package/dist/build/clean-output.d.ts +14 -0
- package/dist/build/clean-output.js +36 -0
- package/dist/build/clean-output.js.map +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.d.ts +6 -2
- package/dist/build/prerender.js +51 -12
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/run-prerender.js +10 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/static-export.d.ts +5 -0
- package/dist/build/static-export.js +8 -3
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.js +4 -0
- package/dist/check.js.map +1 -1
- package/dist/cli.js +19 -4
- package/dist/cli.js.map +1 -1
- package/dist/client/instrumentation-client-inject.d.ts +34 -0
- package/dist/client/instrumentation-client-inject.js +57 -0
- package/dist/client/instrumentation-client-inject.js.map +1 -0
- package/dist/client/navigation-runtime.d.ts +16 -2
- package/dist/client/navigation-runtime.js +16 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/vinext-next-data.js.map +1 -1
- package/dist/client/window-next.d.ts +17 -2
- package/dist/client/window-next.js.map +1 -1
- package/dist/cloudflare/tpr.js +1 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.js +2 -1
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +95 -4
- package/dist/config/next-config.js +173 -14
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +42 -7
- 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 +12 -3
- package/dist/entries/app-rsc-entry.js +41 -8
- 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 +6 -4
- 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 +40 -3
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +292 -34
- 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 +91 -10
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.js +25 -2
- package/dist/plugins/fonts.js.map +1 -1
- 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/routing/route-trie.js +13 -18
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/utils.d.ts +11 -1
- package/dist/routing/utils.js +15 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +19 -10
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-action-result.d.ts +16 -1
- package/dist/server/app-browser-action-result.js +15 -1
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +47 -28
- package/dist/server/app-browser-entry.js.map +1 -1
- 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-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 +27 -8
- package/dist/server/app-fallback-renderer.js +19 -8
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-history-state.js +6 -2
- package/dist/server/app-history-state.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-interception-context-header.d.ts +33 -0
- package/dist/server/app-interception-context-header.js +44 -0
- package/dist/server/app-interception-context-header.js.map +1 -0
- package/dist/server/app-mounted-slots-header.d.ts +19 -0
- package/dist/server/app-mounted-slots-header.js +40 -1
- package/dist/server/app-mounted-slots-header.js.map +1 -1
- package/dist/server/app-optimistic-routing.js +26 -18
- package/dist/server/app-optimistic-routing.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +2 -0
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +22 -1
- package/dist/server/app-page-boundary.js +30 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +9 -3
- package/dist/server/app-page-cache.js +14 -8
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +13 -1
- package/dist/server/app-page-dispatch.js +136 -82
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +2 -1
- package/dist/server/app-page-element-builder.js +17 -30
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +1 -0
- package/dist/server/app-page-execution.js +2 -0
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +1 -0
- package/dist/server/app-page-head.js +8 -0
- package/dist/server/app-page-head.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-observation.js +1 -1
- package/dist/server/app-page-render.d.ts +9 -1
- package/dist/server/app-page-render.js +8 -2
- 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.d.ts +11 -1
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +16 -0
- package/dist/server/app-page-route-wiring.js +25 -10
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +12 -0
- package/dist/server/app-page-stream.js +3 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +3 -0
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +38 -6
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +16 -3
- package/dist/server/app-rsc-handler.js +60 -11
- 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 +6 -4
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +4 -1
- package/dist/server/app-segment-config.js +6 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +22 -3
- package/dist/server/app-server-action-execution.js +46 -7
- 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 +57 -6
- 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 +25 -1
- package/dist/server/app-ssr-stream.js +237 -19
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +2 -1
- package/dist/server/app-static-generation.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/default-not-found-module.d.ts +20 -0
- package/dist/server/default-not-found-module.js +20 -0
- package/dist/server/default-not-found-module.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +56 -11
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/headers.d.ts +5 -1
- package/dist/server/headers.js +5 -1
- package/dist/server/headers.js.map +1 -1
- 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/image-optimization.d.ts +13 -4
- package/dist/server/image-optimization.js +15 -4
- package/dist/server/image-optimization.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/middleware.js +1 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +18 -0
- package/dist/server/pages-api-route.js +3 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-body-parser-config.d.ts +60 -0
- package/dist/server/pages-body-parser-config.js +79 -0
- package/dist/server/pages-body-parser-config.js.map +1 -0
- package/dist/server/pages-data-route.js +1 -0
- package/dist/server/pages-data-route.js.map +1 -1
- package/dist/server/pages-default-404.d.ts +31 -0
- package/dist/server/pages-default-404.js +40 -0
- package/dist/server/pages-default-404.js.map +1 -0
- package/dist/server/pages-document-initial-props.d.ts +7 -0
- package/dist/server/pages-document-initial-props.js +14 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-node-compat.d.ts +10 -0
- package/dist/server/pages-node-compat.js +12 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +40 -0
- package/dist/server/pages-page-data.js +19 -14
- 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 +8 -0
- package/dist/server/pages-page-response.js +21 -11
- 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/prerender-route-params.d.ts +14 -0
- package/dist/server/prerender-route-params.js +94 -0
- package/dist/server/prerender-route-params.js.map +1 -0
- package/dist/server/prod-server.d.ts +3 -23
- package/dist/server/prod-server.js +43 -57
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/proxy-trust.d.ts +41 -0
- package/dist/server/proxy-trust.js +70 -0
- package/dist/server/proxy-trust.js.map +1 -0
- package/dist/server/request-pipeline.d.ts +3 -3
- package/dist/server/request-pipeline.js +5 -4
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/seed-cache.js +12 -6
- package/dist/server/seed-cache.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/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/streaming-metadata.d.ts +5 -0
- package/dist/server/streaming-metadata.js +10 -0
- package/dist/server/streaming-metadata.js.map +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +14 -0
- package/dist/shims/app-router-scroll-state.js +51 -0
- package/dist/shims/app-router-scroll-state.js.map +1 -0
- package/dist/shims/app-router-scroll.d.ts +28 -0
- package/dist/shims/app-router-scroll.js +115 -0
- package/dist/shims/app-router-scroll.js.map +1 -0
- package/dist/shims/before-interactive-context.d.ts +30 -0
- package/dist/shims/before-interactive-context.js +10 -0
- package/dist/shims/before-interactive-context.js.map +1 -0
- package/dist/shims/cache-runtime.d.ts +1 -1
- package/dist/shims/cache-runtime.js +14 -1
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +6 -0
- package/dist/shims/cache.js +7 -0
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/default-not-found.d.ts +12 -0
- package/dist/shims/default-not-found.js +61 -0
- package/dist/shims/default-not-found.js.map +1 -0
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/font-local.d.ts +5 -0
- package/dist/shims/font-local.js +6 -2
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/head.js +4 -4
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +13 -2
- package/dist/shims/headers.js +73 -22
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.d.ts +1 -1
- package/dist/shims/image.js +4 -4
- package/dist/shims/image.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-target.d.ts +58 -0
- package/dist/shims/internal/pages-data-target.js +91 -0
- package/dist/shims/internal/pages-data-target.js.map +1 -0
- package/dist/shims/internal/pages-data-url.d.ts +42 -0
- package/dist/shims/internal/pages-data-url.js +73 -0
- package/dist/shims/internal/pages-data-url.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +129 -15
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +9 -7
- package/dist/shims/metadata.js +70 -7
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +1 -2
- package/dist/shims/navigation.js +94 -20
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +389 -80
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +158 -15
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.js +1 -0
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/url-utils.d.ts +2 -1
- package/dist/shims/url-utils.js +15 -4
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/html-limited-bots.d.ts +5 -0
- package/dist/utils/html-limited-bots.js +15 -0
- package/dist/utils/html-limited-bots.js.map +1 -0
- 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/query.d.ts +6 -0
- package/dist/utils/query.js +10 -1
- package/dist/utils/query.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport \"./server-globals.js\";\nimport type { ReactNode } from \"react\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { Fragment, createElement as createReactElement, use } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"vinext/shims/navigation\";\nimport {\n ServerInsertedHTMLContext,\n appRouterInstance,\n clearServerInsertedHTML,\n renderServerInsertedHTML,\n setNavigationContext,\n useServerInsertedHTML,\n} from \"vinext/shims/navigation\";\nimport { runWithNavigationContext } from \"vinext/shims/navigation-state\";\nimport { runWithRootParamsScope, type RootParams } from \"vinext/shims/root-params\";\nimport { isOpenRedirectShaped } from \"./request-pipeline.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { withScriptNonce } from \"vinext/shims/script-nonce-context\";\nimport {\n createInlineScriptTag,\n createNonceAttribute,\n escapeHtmlAttr,\n safeJsonStringify,\n} from \"./html.js\";\nimport {\n createNavigationRuntimeRscMetadataScript,\n createRscEmbedTransform,\n createTickBufferedTransform,\n} from \"./app-ssr-stream.js\";\nimport { deferUntilStreamConsumed } from \"./app-page-stream.js\";\nimport { createSsrErrorMetaRenderer } from \"./app-ssr-error-meta.js\";\nimport { AppElementsWire, type AppWireElements } from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"vinext/shims/slot\";\nimport { AppRouterContext } from \"vinext/shims/internal/app-router-context\";\nimport { createClientReferencePreloader } from \"./app-client-reference-preloader.js\";\nimport { RSC_FORM_STATE_GLOBAL } from \"./app-browser-hydration.js\";\n\nexport type FontPreload = {\n href: string;\n type: string;\n};\n\nexport type FontData = {\n links?: string[];\n styles?: string[];\n preloads?: FontPreload[];\n};\n\nconst clientReferencePreloader = createClientReferencePreloader({\n getReferences() {\n return clientReferences;\n },\n getClientRequire() {\n return globalThis.__vite_rsc_client_require__;\n },\n onPreloadError(id, error) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n },\n});\n\nfunction ssrErrorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return Object.prototype.toString.call(error);\n}\n\nfunction renderInsertedHtml(insertedElements: readonly unknown[]): string {\n let insertedHTML = \"\";\n\n for (const element of insertedElements) {\n try {\n insertedHTML += renderToStaticMarkup(\n createReactElement(Fragment, null, element as ReactNode),\n );\n } catch {\n // Ignore individual callback failures so the rest of the page can render.\n }\n }\n\n return insertedHTML;\n}\n\nfunction renderFontHtml(fontData?: FontData, nonce?: string): string {\n if (!fontData) return \"\";\n\n let fontHTML = \"\";\n const nonceAttr = createNonceAttribute(nonce);\n\n for (const url of fontData.links ?? []) {\n fontHTML += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(url)}\" />\\n`;\n }\n\n for (const preload of fontData.preloads ?? []) {\n fontHTML += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n`;\n }\n\n if (fontData.styles && fontData.styles.length > 0) {\n fontHTML += `<style data-vinext-fonts${nonceAttr}>${fontData.styles.join(\"\\n\")}</style>\\n`;\n }\n\n return fontHTML;\n}\n\n/**\n * Extract the bootstrap module URL from the `import(\"...\")` string that\n * `import.meta.viteRsc.loadBootstrapScriptContent(\"index\")` returns.\n *\n * The plugin-rsc helper returns the bootstrap as an inline call so we can\n * inject it via `bootstrapScriptContent`. We instead pass the URL to\n * React's `bootstrapModules` option so a real\n * `<script type=\"module\" src=\"…\">` tag ends up in the streamed HTML —\n * this exposes the URL to anything that reads `script.attribs.src` (e.g.\n * the Next.js asset-prefix fixture test). The same URL also feeds the\n * `<link rel=\"modulepreload\">` we emit ahead of the bootstrap.\n *\n * Returns `undefined` when the helper produced no URL (older plugin-rsc\n * versions, or a custom client entry that disables bootstrap content).\n */\nfunction extractBootstrapModuleUrl(bootstrapScriptContent?: string): string | undefined {\n if (!bootstrapScriptContent) return undefined;\n // Accept either quote style — plugin-rsc currently emits double quotes\n // (`import(\"…\")`) but a future version could switch to single quotes,\n // and there's no public contract documenting which is used.\n const match = bootstrapScriptContent.match(/import\\([\"']([^\"']+)[\"']\\)/);\n return match?.[1] ?? undefined;\n}\n\nfunction buildModulePreloadHtml(bootstrapModuleUrl?: string, nonce?: string): string {\n if (!bootstrapModuleUrl) return \"\";\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(bootstrapModuleUrl)}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapModuleUrl: string | undefined,\n formState: ReactFormState | null,\n insertedHTML: string,\n fontHTML: string,\n scriptNonce?: string,\n): string {\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const rscMetadataScript = createInlineScriptTag(\n createNavigationRuntimeRscMetadataScript(navContext?.params ?? {}, navPayload),\n scriptNonce,\n );\n const formStateScript =\n formState === null\n ? \"\"\n : createInlineScriptTag(\n \"self[\" + safeJsonStringify(RSC_FORM_STATE_GLOBAL) + \"]=\" + safeJsonStringify(formState),\n scriptNonce,\n );\n\n return (\n rscMetadataScript +\n formStateScript +\n buildModulePreloadHtml(bootstrapModuleUrl, scriptNonce) +\n insertedHTML +\n fontHTML\n );\n}\n\nexport async function handleSsr(\n rscStream: ReadableStream<Uint8Array>,\n navContext: NavigationContext | null,\n fontData?: FontData,\n options?: {\n scriptNonce?: string;\n /** Pre-split side stream for embed+capture fusion. When provided,\n * rscStream is fed directly to createFromReadableStream (no internal tee).\n * The embed transform accumulates raw bytes. */\n sideStream?: ReadableStream<Uint8Array>;\n /** Out-parameter: filled with accumulated raw RSC bytes when sideStream is consumed. */\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n formState?: ReactFormState | null;\n basePath?: string;\n rootParams?: RootParams;\n /** When true, wait for the full React tree (including Suspense boundaries)\n * to resolve before returning the HTML stream. Used for static prerender\n * and ISR cache writes to avoid caching fallback content. */\n waitForAllReady?: boolean;\n },\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await clientReferencePreloader.preload();\n\n if (navContext) {\n setNavigationContext(navContext);\n }\n\n clearServerInsertedHTML();\n\n const cleanup = (): void => {\n setNavigationContext(null);\n clearServerInsertedHTML();\n };\n\n const rootParams = options?.rootParams ?? {};\n return runWithRootParamsScope(rootParams, async () => {\n try {\n // Fused tee path (#981): caller pre-split the stream. No internal tee needed.\n // sideStream carries both the embed transform and raw byte accumulation.\n // rscStream is used directly for createFromReadableStream (SSR).\n let ssrStream: ReadableStream<Uint8Array>;\n let rscEmbed;\n\n if (options?.sideStream) {\n ssrStream = rscStream;\n rscEmbed = createRscEmbedTransform(options.sideStream, options?.scriptNonce);\n if (options.capturedRscDataRef) {\n options.capturedRscDataRef.value = rscEmbed.getRawBuffer();\n }\n } else {\n const [s1, s2] = rscStream.tee();\n ssrStream = s1;\n rscEmbed = createRscEmbedTransform(s2, options?.scriptNonce);\n }\n\n let flightRoot: PromiseLike<AppWireElements> | null = null;\n\n function VinextFlightRoot(): ReactNode {\n if (!flightRoot) {\n flightRoot = createFromReadableStream<AppWireElements>(ssrStream);\n }\n const wireElements = use(flightRoot);\n const elements = AppElementsWire.decode(wireElements);\n const metadata = AppElementsWire.readMetadata(elements);\n return createReactElement(\n ElementsContext.Provider,\n { value: elements },\n createReactElement(Slot, { id: metadata.routeId }),\n );\n }\n\n const flightRootElement = createReactElement(VinextFlightRoot);\n const root = AppRouterContext\n ? createReactElement(\n AppRouterContext.Provider,\n { value: appRouterInstance },\n flightRootElement,\n )\n : flightRootElement;\n const ssrTree = ServerInsertedHTMLContext\n ? createReactElement(\n ServerInsertedHTMLContext.Provider,\n { value: useServerInsertedHTML },\n root,\n )\n : root;\n const ssrRoot = withScriptNonce(ssrTree, options?.scriptNonce);\n\n // plugin-rsc returns the bootstrap as `import(\"<url>\")` so callers can\n // inject it via `bootstrapScriptContent`. We hand the URL to React's\n // `bootstrapModules` option instead so the streamed HTML contains a\n // real `<script type=\"module\" src=\"<url>\">` tag — exposing the URL\n // to anything that inspects `script.attribs.src` (e.g. the Next.js\n // asset-prefix fixture test \"bundles should return 200 on served\n // assetPrefix\"). Mirrors Next.js's app-render path which passes\n // `bootstrapScripts: [{ src }]` for the same reason; we use\n // `bootstrapModules` because vinext's chunks are native ES modules\n // (Vite output) so a `type=\"module\"` tag is the correct loader.\n //\n // In dev, `<url>` is a Vite dev URL like\n // `/@id/__x00__virtual:vinext-app-browser-entry`; the browser fetches\n // it as a module from the dev server. In prod it's the hashed bundle\n // URL (e.g. `/_next/static/index-abc123.js`, optionally prefixed by\n // `assetPrefix`). Both are valid `<script type=\"module\" src=…>` targets.\n const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\n \"index\",\n );\n const bootstrapModuleUrl = extractBootstrapModuleUrl(bootstrapScriptContent);\n const errorMetaRenderer = createSsrErrorMetaRenderer({\n basePath: options?.basePath,\n });\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n // `bootstrapScriptContent` was previously how vinext injected the\n // dynamic-import call. `bootstrapModules` performs the same work\n // natively (and exposes the URL in the DOM), so passing both would\n // load the bootstrap module twice.\n //\n // CSP implications of using `bootstrapModules` instead of inline\n // `bootstrapScriptContent`:\n // - Apps no longer need `script-src 'unsafe-inline'` to load the\n // bootstrap (improvement — inline imports required `'unsafe-inline'`).\n // - Apps that restrict script sources need `'self'` for the\n // common case, or the CDN origin when `assetPrefix` is an\n // absolute URL like `https://cdn.example.com`.\n // - React still applies `nonce` to the emitted\n // `<script type=\"module\" src=…>` tag, so nonce-based CSP\n // (`script-src 'nonce-…' 'strict-dynamic'`) keeps working.\n bootstrapModules: bootstrapModuleUrl ? [bootstrapModuleUrl] : undefined,\n formState: options?.formState ?? null,\n nonce: options?.scriptNonce,\n onError(error) {\n errorMetaRenderer.capture(error);\n\n if (error && typeof error === \"object\" && \"digest\" in error) {\n return String(error.digest);\n }\n\n if (process.env.NODE_ENV === \"production\" && error) {\n const message = getErrorMessage(error);\n const stack = error instanceof Error ? (error.stack ?? \"\") : \"\";\n return ssrErrorDigest(message + stack);\n }\n\n return undefined;\n },\n });\n\n // When producing static output (prerender / ISR cache writes), wait for\n // the full React tree to resolve before emitting bytes. This prevents\n // Suspense fallback content from being serialized to the cache.\n // Matches Next.js waitForAllReady forkpoint in renderToNodeFizzStream.\n if (options?.waitForAllReady === true) {\n await htmlStream.allReady;\n }\n\n const fontHTML = renderFontHtml(fontData, options?.scriptNonce);\n let didInjectHeadHTML = false;\n const getInsertedHTML = (): string => {\n const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());\n const errorMetaHTML = errorMetaRenderer.flush();\n if (didInjectHeadHTML) return insertedHTML + errorMetaHTML;\n\n didInjectHeadHTML = true;\n return buildHeadInjectionHtml(\n navContext,\n bootstrapModuleUrl,\n options?.formState ?? null,\n insertedHTML + errorMetaHTML,\n fontHTML,\n options?.scriptNonce,\n );\n };\n\n return deferUntilStreamConsumed(\n htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, getInsertedHTML)),\n cleanup,\n );\n } catch (error) {\n cleanup();\n throw error;\n }\n });\n }) as Promise<ReadableStream<Uint8Array>>;\n}\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n // Block protocol-relative URL open redirects (including percent-encoded\n // variants like /%5Cevil.com/). See request-pipeline.ts for details.\n if (isOpenRedirectShaped(url.pathname)) {\n return notFoundResponse();\n }\n\n const rscModule = await import.meta.viteRsc.loadModule<{\n default(request: Request): Promise<Response | string | null | undefined>;\n }>(\"rsc\", \"index\");\n const result = await rscModule.default(request);\n\n if (result instanceof Response) {\n return result;\n }\n\n if (result == null) {\n return notFoundResponse();\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport \"./server-globals.js\";\nimport type { ReactNode } from \"react\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { Fragment, createElement as createReactElement, use } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"vinext/shims/navigation\";\nimport {\n ServerInsertedHTMLContext,\n appRouterInstance,\n clearServerInsertedHTML,\n renderServerInsertedHTML,\n setNavigationContext,\n useServerInsertedHTML,\n} from \"vinext/shims/navigation\";\nimport { runWithNavigationContext } from \"vinext/shims/navigation-state\";\nimport { runWithRootParamsScope, type RootParams } from \"vinext/shims/root-params\";\nimport { isOpenRedirectShaped } from \"./request-pipeline.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { withScriptNonce } from \"vinext/shims/script-nonce-context\";\nimport {\n BeforeInteractiveContext,\n type BeforeInteractiveInlineScript,\n} from \"vinext/shims/before-interactive-context\";\nimport {\n createInlineScriptTag,\n createNonceAttribute,\n escapeHtmlAttr,\n safeJsonStringify,\n} from \"./html.js\";\nimport {\n createNavigationRuntimeRscMetadataScript,\n createRscEmbedTransform,\n createTickBufferedTransform,\n} from \"./app-ssr-stream.js\";\nimport { deferUntilStreamConsumed } from \"./app-page-stream.js\";\nimport { createSsrErrorMetaRenderer } from \"./app-ssr-error-meta.js\";\nimport { getClientTraceMetadataHTML } from \"./client-trace-metadata.js\";\nimport { AppElementsWire, type AppWireElements } from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"vinext/shims/slot\";\nimport { AppRouterContext } from \"vinext/shims/internal/app-router-context\";\nimport { createClientReferencePreloader } from \"./app-client-reference-preloader.js\";\nimport { RSC_FORM_STATE_GLOBAL } from \"./app-browser-hydration.js\";\n\nexport type FontPreload = {\n href: string;\n type: string;\n};\n\nexport type FontData = {\n links?: string[];\n styles?: string[];\n preloads?: FontPreload[];\n};\n\nconst clientReferencePreloader = createClientReferencePreloader({\n getReferences() {\n return clientReferences;\n },\n getClientRequire() {\n return globalThis.__vite_rsc_client_require__;\n },\n onPreloadError(id, error) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n },\n});\n\nfunction ssrErrorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return Object.prototype.toString.call(error);\n}\n\nfunction renderInsertedHtml(insertedElements: readonly unknown[]): string {\n let insertedHTML = \"\";\n\n for (const element of insertedElements) {\n try {\n insertedHTML += renderToStaticMarkup(\n createReactElement(Fragment, null, element as ReactNode),\n );\n } catch {\n // Ignore individual callback failures so the rest of the page can render.\n }\n }\n\n return insertedHTML;\n}\n\n/**\n * Render captured `<Script strategy=\"beforeInteractive\">` inline scripts to\n * HTML, ready to splice immediately after `<head ...>` opens. Each entry has\n * already had its inline content escaped via `escapeInlineContent(..., \"script\")`\n * inside the Script shim, so this function only quotes the attributes that\n * actually go on the tag (id, nonce, plus the residual passthroughs).\n *\n * Keeping this function colocated with the rest of the head-injection\n * helpers makes it obvious where the boundary is: anything passed through\n * here is being concatenated directly into HTML; treat the inputs\n * accordingly.\n */\n// Conservative subset of the HTML attribute-name grammar. Must start with a\n// letter and contain only letters, digits, underscores, hyphens, or dots —\n// enough to round-trip data-* and standard attributes (`async`, `defer`,\n// `type`, `crossorigin`, etc.) without ever splicing a `\"`/`>`/whitespace\n// into the unquoted *name* position where escaping wouldn't help.\nconst VALID_ATTR_NAME = /^[a-zA-Z][\\w.-]*$/;\n\nfunction renderBeforeInteractiveInlineScripts(\n scripts: readonly BeforeInteractiveInlineScript[],\n): string {\n if (scripts.length === 0) return \"\";\n let html = \"\";\n for (const script of scripts) {\n let attrs = \"\";\n if (script.id) {\n attrs += ` id=\"${escapeHtmlAttr(script.id)}\"`;\n }\n attrs += createNonceAttribute(script.nonce);\n if (script.attributes) {\n for (const [key, value] of Object.entries(script.attributes)) {\n // Attribute *values* go through escapeHtmlAttr below. The *name*\n // can't be escaped — a malformed key would break the tag — so we\n // gate at the boundary instead of trying to neutralise it.\n if (!VALID_ATTR_NAME.test(key)) continue;\n if (value === true) {\n attrs += ` ${key}`;\n } else if (typeof value === \"string\") {\n attrs += ` ${key}=\"${escapeHtmlAttr(value)}\"`;\n }\n }\n }\n html += `<script${attrs}>${script.innerHTML}</script>`;\n }\n return html;\n}\n\nfunction renderFontHtml(\n fontData?: FontData,\n nonce?: string,\n options: { includeStyles?: boolean } = {},\n): string {\n if (!fontData) return \"\";\n\n let fontHTML = \"\";\n const nonceAttr = createNonceAttribute(nonce);\n const includeStyles = options.includeStyles ?? true;\n\n for (const url of fontData.links ?? []) {\n fontHTML += `<link rel=\"stylesheet\"${nonceAttr} href=\"${escapeHtmlAttr(url)}\" />\\n`;\n }\n\n for (const preload of fontData.preloads ?? []) {\n fontHTML += `<link rel=\"preload\"${nonceAttr} href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n`;\n }\n\n if (includeStyles && fontData.styles && fontData.styles.length > 0) {\n fontHTML += `<style data-vinext-fonts${nonceAttr}>${fontData.styles.join(\"\\n\")}</style>\\n`;\n }\n\n return fontHTML;\n}\n\nfunction hasInlineCssManifest(manifest: Record<string, string> | undefined): boolean {\n return manifest !== undefined && Object.keys(manifest).length > 0;\n}\n\n/**\n * Extract the bootstrap module URL from the `import(\"...\")` string that\n * `import.meta.viteRsc.loadBootstrapScriptContent(\"index\")` returns.\n *\n * The plugin-rsc helper returns the bootstrap as an inline call so we can\n * inject it via `bootstrapScriptContent`. We instead pass the URL to\n * React's `bootstrapModules` option so a real\n * `<script type=\"module\" src=\"…\">` tag ends up in the streamed HTML —\n * this exposes the URL to anything that reads `script.attribs.src` (e.g.\n * the Next.js asset-prefix fixture test). The same URL also feeds the\n * `<link rel=\"modulepreload\">` we emit ahead of the bootstrap.\n *\n * Returns `undefined` when the helper produced no URL (older plugin-rsc\n * versions, or a custom client entry that disables bootstrap content).\n */\nfunction extractBootstrapModuleUrl(bootstrapScriptContent?: string): string | undefined {\n if (!bootstrapScriptContent) return undefined;\n // Accept either quote style — plugin-rsc currently emits double quotes\n // (`import(\"…\")`) but a future version could switch to single quotes,\n // and there's no public contract documenting which is used.\n const match = bootstrapScriptContent.match(/import\\([\"']([^\"']+)[\"']\\)/);\n return match?.[1] ?? undefined;\n}\n\nfunction buildModulePreloadHtml(bootstrapModuleUrl?: string, nonce?: string): string {\n if (!bootstrapModuleUrl) return \"\";\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(bootstrapModuleUrl)}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapModuleUrl: string | undefined,\n formState: ReactFormState | null,\n insertedHTML: string,\n fontHTML: string,\n scriptNonce?: string,\n): string {\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const rscMetadataScript = createInlineScriptTag(\n createNavigationRuntimeRscMetadataScript(navContext?.params ?? {}, navPayload),\n scriptNonce,\n );\n const formStateScript =\n formState === null\n ? \"\"\n : createInlineScriptTag(\n \"self[\" + safeJsonStringify(RSC_FORM_STATE_GLOBAL) + \"]=\" + safeJsonStringify(formState),\n scriptNonce,\n );\n\n return (\n rscMetadataScript +\n formStateScript +\n buildModulePreloadHtml(bootstrapModuleUrl, scriptNonce) +\n insertedHTML +\n fontHTML\n );\n}\n\nexport async function handleSsr(\n rscStream: ReadableStream<Uint8Array>,\n navContext: NavigationContext | null,\n fontData?: FontData,\n options?: {\n scriptNonce?: string;\n /** Pre-split side stream for embed+capture fusion. When provided,\n * rscStream is fed directly to createFromReadableStream (no internal tee).\n * The embed transform accumulates raw bytes. */\n sideStream?: ReadableStream<Uint8Array>;\n /** Out-parameter: filled with accumulated raw RSC bytes when sideStream is consumed. */\n capturedRscDataRef?: { value: Promise<ArrayBuffer> | null };\n formState?: ReactFormState | null;\n basePath?: string;\n /**\n * Allow-list of OpenTelemetry propagation keys (from\n * `experimental.clientTraceMetadata`) to render as `<meta>` tags in the\n * SSR head. Undefined or empty disables emission entirely.\n */\n clientTraceMetadata?: readonly string[];\n rootParams?: RootParams;\n /** When true, wait for the full React tree (including Suspense boundaries)\n * to resolve before returning the HTML stream. Used for static prerender\n * and ISR cache writes to avoid caching fallback content. */\n waitForAllReady?: boolean;\n },\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await clientReferencePreloader.preload();\n\n if (navContext) {\n setNavigationContext(navContext);\n }\n\n clearServerInsertedHTML();\n\n const cleanup = (): void => {\n setNavigationContext(null);\n clearServerInsertedHTML();\n };\n\n const rootParams = options?.rootParams ?? {};\n return runWithRootParamsScope(rootParams, async () => {\n try {\n // Fused tee path (#981): caller pre-split the stream. No internal tee needed.\n // sideStream carries both the embed transform and raw byte accumulation.\n // rscStream is used directly for createFromReadableStream (SSR).\n let ssrStream: ReadableStream<Uint8Array>;\n let rscEmbed;\n\n if (options?.sideStream) {\n ssrStream = rscStream;\n rscEmbed = createRscEmbedTransform(options.sideStream, options?.scriptNonce);\n if (options.capturedRscDataRef) {\n options.capturedRscDataRef.value = rscEmbed.getRawBuffer();\n }\n } else {\n const [s1, s2] = rscStream.tee();\n ssrStream = s1;\n rscEmbed = createRscEmbedTransform(s2, options?.scriptNonce);\n }\n\n let flightRoot: PromiseLike<AppWireElements> | null = null;\n\n function VinextFlightRoot(): ReactNode {\n if (!flightRoot) {\n flightRoot = createFromReadableStream<AppWireElements>(ssrStream);\n }\n const wireElements = use(flightRoot);\n const elements = AppElementsWire.decode(wireElements);\n const metadata = AppElementsWire.readMetadata(elements);\n return createReactElement(\n ElementsContext.Provider,\n { value: elements },\n createReactElement(Slot, { id: metadata.routeId }),\n );\n }\n\n const flightRootElement = createReactElement(VinextFlightRoot);\n const root = AppRouterContext\n ? createReactElement(\n AppRouterContext.Provider,\n { value: appRouterInstance },\n flightRootElement,\n )\n : flightRootElement;\n const ssrTree = ServerInsertedHTMLContext\n ? createReactElement(\n ServerInsertedHTMLContext.Provider,\n { value: useServerInsertedHTML },\n root,\n )\n : root;\n\n // Capture inline `<Script strategy=\"beforeInteractive\">` content so the\n // SSR stream transform can emit it immediately after `<head ...>`\n // opens — ahead of every React-emitted resource hint. The Script shim\n // pushes here when it sees an inline beforeInteractive Script and\n // returns `null` from its render so React does not also serialize the\n // tag where the user wrote it (where Fizz would push it *after* the\n // hoisted stylesheets/modulepreloads). See\n // packages/vinext/src/shims/script.tsx for the capture side.\n const beforeInteractiveInlineScripts: BeforeInteractiveInlineScript[] = [];\n const registerBeforeInteractiveInlineScript = (\n script: BeforeInteractiveInlineScript,\n ): void => {\n beforeInteractiveInlineScripts.push(script);\n };\n const treeWithBeforeInteractive = createReactElement(\n BeforeInteractiveContext.Provider,\n { value: registerBeforeInteractiveInlineScript },\n ssrTree,\n );\n const ssrRoot = withScriptNonce(treeWithBeforeInteractive, options?.scriptNonce);\n\n // plugin-rsc returns the bootstrap as `import(\"<url>\")` so callers can\n // inject it via `bootstrapScriptContent`. We hand the URL to React's\n // `bootstrapModules` option instead so the streamed HTML contains a\n // real `<script type=\"module\" src=\"<url>\">` tag — exposing the URL\n // to anything that inspects `script.attribs.src` (e.g. the Next.js\n // asset-prefix fixture test \"bundles should return 200 on served\n // assetPrefix\"). Mirrors Next.js's app-render path which passes\n // `bootstrapScripts: [{ src }]` for the same reason; we use\n // `bootstrapModules` because vinext's chunks are native ES modules\n // (Vite output) so a `type=\"module\"` tag is the correct loader.\n //\n // In dev, `<url>` is a Vite dev URL like\n // `/@id/__x00__virtual:vinext-app-browser-entry`; the browser fetches\n // it as a module from the dev server. In prod it's the hashed bundle\n // URL (e.g. `/_next/static/index-abc123.js`, optionally prefixed by\n // `assetPrefix`). Both are valid `<script type=\"module\" src=…>` targets.\n const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\n \"index\",\n );\n const bootstrapModuleUrl = extractBootstrapModuleUrl(bootstrapScriptContent);\n const errorMetaRenderer = createSsrErrorMetaRenderer({\n basePath: options?.basePath,\n });\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n // `bootstrapScriptContent` was previously how vinext injected the\n // dynamic-import call. `bootstrapModules` performs the same work\n // natively (and exposes the URL in the DOM), so passing both would\n // load the bootstrap module twice.\n //\n // CSP implications of using `bootstrapModules` instead of inline\n // `bootstrapScriptContent`:\n // - Apps no longer need `script-src 'unsafe-inline'` to load the\n // bootstrap (improvement — inline imports required `'unsafe-inline'`).\n // - Apps that restrict script sources need `'self'` for the\n // common case, or the CDN origin when `assetPrefix` is an\n // absolute URL like `https://cdn.example.com`.\n // - React still applies `nonce` to the emitted\n // `<script type=\"module\" src=…>` tag, so nonce-based CSP\n // (`script-src 'nonce-…' 'strict-dynamic'`) keeps working.\n bootstrapModules: bootstrapModuleUrl ? [bootstrapModuleUrl] : undefined,\n formState: options?.formState ?? null,\n nonce: options?.scriptNonce,\n onError(error) {\n errorMetaRenderer.capture(error);\n\n if (error && typeof error === \"object\" && \"digest\" in error) {\n return String(error.digest);\n }\n\n if (process.env.NODE_ENV === \"production\" && error) {\n const message = getErrorMessage(error);\n const stack = error instanceof Error ? (error.stack ?? \"\") : \"\";\n return ssrErrorDigest(message + stack);\n }\n\n return undefined;\n },\n });\n\n // When producing static output (prerender / ISR cache writes), wait for\n // the full React tree to resolve before emitting bytes. This prevents\n // Suspense fallback content from being serialized to the cache.\n // Matches Next.js waitForAllReady forkpoint in renderToNodeFizzStream.\n if (options?.waitForAllReady === true) {\n await htmlStream.allReady;\n }\n\n // Populated before any SSR request runs: at prod-server startup\n // (prod-server.ts) or via build-time bundle injection (index.ts). Left\n // undefined in dev, which naturally disables inline CSS there.\n const inlineCssManifest = globalThis.__VINEXT_INLINE_CSS__;\n const fontStyles = fontData?.styles ?? [];\n const mergeFontStylesIntoInlineCss =\n fontStyles.length > 0 && hasInlineCssManifest(inlineCssManifest);\n const inlineCssFontStyles = mergeFontStylesIntoInlineCss ? fontStyles.join(\"\\n\") : \"\";\n const inlineCssFontStyleFallbackHTML = mergeFontStylesIntoInlineCss\n ? renderFontHtml({ styles: fontStyles }, options?.scriptNonce)\n : \"\";\n const fontHTML = renderFontHtml(fontData, options?.scriptNonce, {\n includeStyles: !mergeFontStylesIntoInlineCss,\n });\n // Trace meta tags only need to land in the document head once.\n // Read the active OTel context lazily so the value reflects the\n // span that was active when the SSR shell rendered. When\n // clientTraceMetadata is unset (the common case) this is empty.\n let traceMetaHTML: string | null = null;\n const getTraceMetaHTML = (): string => {\n if (traceMetaHTML === null) {\n traceMetaHTML = getClientTraceMetadataHTML(options?.clientTraceMetadata);\n }\n return traceMetaHTML;\n };\n let didInjectHeadHTML = false;\n const getInsertedHTML = (): string => {\n const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());\n const errorMetaHTML = errorMetaRenderer.flush();\n if (didInjectHeadHTML) return insertedHTML + errorMetaHTML;\n\n didInjectHeadHTML = true;\n return buildHeadInjectionHtml(\n navContext,\n bootstrapModuleUrl,\n options?.formState ?? null,\n insertedHTML + errorMetaHTML + getTraceMetaHTML(),\n fontHTML,\n options?.scriptNonce,\n );\n };\n\n // The transform calls this once when it splices after `<head ...>`.\n // By that point React Fizz has rendered the layout's `<head>` children\n // (which is where the Script shim registers), so the captured array is\n // populated. We deliberately return a snapshot — `flushBuffered` will\n // not re-invoke us, and any beforeInteractive Script that renders\n // later (inside a Suspense boundary further down the tree) falls back\n // to its inline location, matching the documented guarantee that\n // ordering applies to scripts rendered in the initial shell.\n const getBeforeInteractiveHeadHTML = (): string =>\n renderBeforeInteractiveInlineScripts(beforeInteractiveInlineScripts);\n\n return deferUntilStreamConsumed(\n htmlStream.pipeThrough(\n createTickBufferedTransform(\n rscEmbed,\n getInsertedHTML,\n getBeforeInteractiveHeadHTML,\n inlineCssManifest,\n inlineCssFontStyles,\n inlineCssFontStyleFallbackHTML,\n options?.scriptNonce,\n ),\n ),\n cleanup,\n );\n } catch (error) {\n cleanup();\n throw error;\n }\n });\n }) as Promise<ReadableStream<Uint8Array>>;\n}\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n // Block protocol-relative URL open redirects (including percent-encoded\n // variants like /%5Cevil.com/). See request-pipeline.ts for details.\n if (isOpenRedirectShaped(url.pathname)) {\n return notFoundResponse();\n }\n\n const rscModule = await import.meta.viteRsc.loadModule<{\n default(request: Request): Promise<Response | string | null | undefined>;\n }>(\"rsc\", \"index\");\n const result = await rscModule.default(request);\n\n if (result instanceof Response) {\n return result;\n }\n\n if (result == null) {\n return notFoundResponse();\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
|
|
@@ -14,15 +14,15 @@ function renderSsrErrorMetaTag(error, options) {
|
|
|
14
14
|
const digest = getNextErrorDigest(error);
|
|
15
15
|
if (!digest) return "";
|
|
16
16
|
if (parseNextHttpErrorDigest(digest)) {
|
|
17
|
-
let html = "<meta name=\"robots\" content=\"noindex\"
|
|
18
|
-
if ((options.nodeEnv ?? process.env.NODE_ENV) === "development") html += "<meta name=\"next-error\" content=\"not-found\"
|
|
17
|
+
let html = "<meta name=\"robots\" content=\"noindex\"/>";
|
|
18
|
+
if ((options.nodeEnv ?? process.env.NODE_ENV) === "development") html += "<meta name=\"next-error\" content=\"not-found\"/>";
|
|
19
19
|
return html;
|
|
20
20
|
}
|
|
21
21
|
const redirect = parseNextRedirectDigest(digest);
|
|
22
22
|
if (!redirect) return "";
|
|
23
23
|
const delay = redirect.status === PERMANENT_REDIRECT_STATUS ? 0 : 1;
|
|
24
24
|
const location = prefixRedirectLocation(redirect.url, options.basePath);
|
|
25
|
-
return "<meta id=\"__next-page-redirect\" http-equiv=\"refresh\" content=\"" + delay + ";url=" + escapeHtmlAttr(location) + "\"
|
|
25
|
+
return "<meta id=\"__next-page-redirect\" http-equiv=\"refresh\" content=\"" + delay + ";url=" + escapeHtmlAttr(location) + "\"/>";
|
|
26
26
|
}
|
|
27
27
|
function renderSsrErrorMetaTags(errors, options = {}) {
|
|
28
28
|
let html = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-ssr-error-meta.js","names":[],"sources":["../../src/server/app-ssr-error-meta.ts"],"sourcesContent":["import { addBasePathToPathname } from \"../utils/base-path.js\";\nimport { escapeHtmlAttr } from \"./html.js\";\nimport {\n getNextErrorDigest,\n parseNextHttpErrorDigest,\n parseNextRedirectDigest,\n} from \"./next-error-digest.js\";\n\ntype SsrErrorMetaRenderOptions = {\n basePath?: string;\n nodeEnv?: string;\n};\n\ntype SsrErrorMetaRenderer = {\n capture: (error: unknown) => void;\n flush: () => string;\n};\n\nconst PERMANENT_REDIRECT_STATUS = 308;\n\nfunction prefixRedirectLocation(location: string, basePath?: string): string {\n if (!basePath || !location.startsWith(\"/\")) {\n return location;\n }\n\n const hashIndex = location.indexOf(\"#\");\n const queryIndex = location.indexOf(\"?\");\n const pathnameEnd =\n queryIndex === -1\n ? hashIndex === -1\n ? location.length\n : hashIndex\n : hashIndex === -1\n ? queryIndex\n : Math.min(queryIndex, hashIndex);\n const pathname = location.slice(0, pathnameEnd);\n\n return addBasePathToPathname(pathname, basePath) + location.slice(pathnameEnd);\n}\n\nfunction renderSsrErrorMetaTag(error: unknown, options: SsrErrorMetaRenderOptions): string {\n const digest = getNextErrorDigest(error);\n if (!digest) return \"\";\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (httpError) {\n let html = '<meta name=\"robots\" content=\"noindex\"
|
|
1
|
+
{"version":3,"file":"app-ssr-error-meta.js","names":[],"sources":["../../src/server/app-ssr-error-meta.ts"],"sourcesContent":["import { addBasePathToPathname } from \"../utils/base-path.js\";\nimport { escapeHtmlAttr } from \"./html.js\";\nimport {\n getNextErrorDigest,\n parseNextHttpErrorDigest,\n parseNextRedirectDigest,\n} from \"./next-error-digest.js\";\n\ntype SsrErrorMetaRenderOptions = {\n basePath?: string;\n nodeEnv?: string;\n};\n\ntype SsrErrorMetaRenderer = {\n capture: (error: unknown) => void;\n flush: () => string;\n};\n\nconst PERMANENT_REDIRECT_STATUS = 308;\n\nfunction prefixRedirectLocation(location: string, basePath?: string): string {\n if (!basePath || !location.startsWith(\"/\")) {\n return location;\n }\n\n const hashIndex = location.indexOf(\"#\");\n const queryIndex = location.indexOf(\"?\");\n const pathnameEnd =\n queryIndex === -1\n ? hashIndex === -1\n ? location.length\n : hashIndex\n : hashIndex === -1\n ? queryIndex\n : Math.min(queryIndex, hashIndex);\n const pathname = location.slice(0, pathnameEnd);\n\n return addBasePathToPathname(pathname, basePath) + location.slice(pathnameEnd);\n}\n\nfunction renderSsrErrorMetaTag(error: unknown, options: SsrErrorMetaRenderOptions): string {\n const digest = getNextErrorDigest(error);\n if (!digest) return \"\";\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (httpError) {\n // Output format matches Next.js's `make-get-server-inserted-html.tsx`,\n // which serializes these meta tags via React's HTML renderer. React's\n // void-element output uses no space before `/>`, and Next.js tests assert\n // on that exact substring (e.g. `'<meta name=\"robots\" content=\"noindex\"/>'`).\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/make-get-server-inserted-html.tsx\n let html = '<meta name=\"robots\" content=\"noindex\"/>';\n if ((options.nodeEnv ?? process.env.NODE_ENV) === \"development\") {\n html += '<meta name=\"next-error\" content=\"not-found\"/>';\n }\n return html;\n }\n\n const redirect = parseNextRedirectDigest(digest);\n if (!redirect) return \"\";\n\n const delay = redirect.status === PERMANENT_REDIRECT_STATUS ? 0 : 1;\n const location = prefixRedirectLocation(redirect.url, options.basePath);\n return (\n '<meta id=\"__next-page-redirect\" http-equiv=\"refresh\" content=\"' +\n delay +\n \";url=\" +\n escapeHtmlAttr(location) +\n '\"/>'\n );\n}\n\nexport function renderSsrErrorMetaTags(\n errors: readonly unknown[],\n options: SsrErrorMetaRenderOptions = {},\n): string {\n let html = \"\";\n\n for (const error of errors) {\n html += renderSsrErrorMetaTag(error, options);\n }\n\n return html;\n}\n\nexport function createSsrErrorMetaRenderer(\n options: SsrErrorMetaRenderOptions = {},\n): SsrErrorMetaRenderer {\n const capturedErrors: unknown[] = [];\n let flushedUntil = 0;\n\n return {\n capture(error) {\n capturedErrors.push(error);\n },\n flush() {\n if (flushedUntil >= capturedErrors.length) return \"\";\n\n const html = renderSsrErrorMetaTags(capturedErrors.slice(flushedUntil), options);\n flushedUntil = capturedErrors.length;\n return html;\n },\n };\n}\n"],"mappings":";;;;AAkBA,MAAM,4BAA4B;AAElC,SAAS,uBAAuB,UAAkB,UAA2B;CAC3E,IAAI,CAAC,YAAY,CAAC,SAAS,WAAW,IAAI,EACxC,OAAO;CAGT,MAAM,YAAY,SAAS,QAAQ,IAAI;CACvC,MAAM,aAAa,SAAS,QAAQ,IAAI;CACxC,MAAM,cACJ,eAAe,KACX,cAAc,KACZ,SAAS,SACT,YACF,cAAc,KACZ,aACA,KAAK,IAAI,YAAY,UAAU;CAGvC,OAAO,sBAFU,SAAS,MAAM,GAAG,YAEE,EAAE,SAAS,GAAG,SAAS,MAAM,YAAY;;AAGhF,SAAS,sBAAsB,OAAgB,SAA4C;CACzF,MAAM,SAAS,mBAAmB,MAAM;CACxC,IAAI,CAAC,QAAQ,OAAO;CAGpB,IADkB,yBAAyB,OAC9B,EAAE;EAMb,IAAI,OAAO;EACX,KAAK,QAAQ,WAAW,QAAQ,IAAI,cAAc,eAChD,QAAQ;EAEV,OAAO;;CAGT,MAAM,WAAW,wBAAwB,OAAO;CAChD,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,QAAQ,SAAS,WAAW,4BAA4B,IAAI;CAClE,MAAM,WAAW,uBAAuB,SAAS,KAAK,QAAQ,SAAS;CACvE,OACE,wEACA,QACA,UACA,eAAe,SAAS,GACxB;;AAIJ,SAAgB,uBACd,QACA,UAAqC,EAAE,EAC/B;CACR,IAAI,OAAO;CAEX,KAAK,MAAM,SAAS,QAClB,QAAQ,sBAAsB,OAAO,QAAQ;CAG/C,OAAO;;AAGT,SAAgB,2BACd,UAAqC,EAAE,EACjB;CACtB,MAAM,iBAA4B,EAAE;CACpC,IAAI,eAAe;CAEnB,OAAO;EACL,QAAQ,OAAO;GACb,eAAe,KAAK,MAAM;;EAE5B,QAAQ;GACN,IAAI,gBAAgB,eAAe,QAAQ,OAAO;GAElD,MAAM,OAAO,uBAAuB,eAAe,MAAM,aAAa,EAAE,QAAQ;GAChF,eAAe,eAAe;GAC9B,OAAO;;EAEV"}
|
|
@@ -5,6 +5,7 @@ type RscEmbedTransform = {
|
|
|
5
5
|
getRawBuffer(): Promise<ArrayBuffer>;
|
|
6
6
|
};
|
|
7
7
|
type HtmlInsertion = string | (() => string);
|
|
8
|
+
type InlineCssManifest = Record<string, string>;
|
|
8
9
|
declare function navigationRuntimeRscBootstrapExpression(): string;
|
|
9
10
|
declare function createNavigationRuntimeRscMetadataScript(params: Record<string, string | string[]>, nav: {
|
|
10
11
|
pathname: string;
|
|
@@ -30,8 +31,31 @@ declare function fixPreloadAs(html: string): string;
|
|
|
30
31
|
/**
|
|
31
32
|
* Create the tick-buffered HTML transform that injects RSC scripts between
|
|
32
33
|
* React Fizz flush cycles without corrupting split HTML chunks.
|
|
34
|
+
*
|
|
35
|
+
* Two insertion points are supported in tandem:
|
|
36
|
+
*
|
|
37
|
+
* - `injectHTML` is emitted immediately before `</head>`. This is where the
|
|
38
|
+
* bulk of vinext's head additions live (RSC navigation runtime metadata,
|
|
39
|
+
* bootstrap modulepreload, server-inserted HTML, font preloads, etc.).
|
|
40
|
+
* - `injectAfterHeadOpenHTML` is emitted immediately after the `<head ...>`
|
|
41
|
+
* opening tag so the content runs before any React-emitted resource
|
|
42
|
+
* hints. This is where inline `<Script strategy="beforeInteractive">`
|
|
43
|
+
* captures land so the no-flash dark-mode pattern works.
|
|
44
|
+
*
|
|
45
|
+
* Fallback behaviour differs by insertion point:
|
|
46
|
+
*
|
|
47
|
+
* - `injectHTML` is emitted at end-of-stream by the `flush` handler when no
|
|
48
|
+
* chunk ever contained `</head>` — callers still see the payload on
|
|
49
|
+
* highly fragmented streams (just at the end of the body rather than in
|
|
50
|
+
* the head).
|
|
51
|
+
* - `injectAfterHeadOpenHTML` is silently dropped when `<head ...>` is not
|
|
52
|
+
* found in a discoverable chunk. Emitting it at end-of-stream would put
|
|
53
|
+
* it after the document body, defeating the point — the splice has to
|
|
54
|
+
* happen before resource hints to be useful, so the safer behaviour is
|
|
55
|
+
* to no-op and let the user-rendered Script (in its source-order
|
|
56
|
+
* position) ship as-is.
|
|
33
57
|
*/
|
|
34
|
-
declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?: HtmlInsertion): TransformStream<Uint8Array, Uint8Array>;
|
|
58
|
+
declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?: HtmlInsertion, injectAfterHeadOpenHTML?: HtmlInsertion, inlineCssManifest?: InlineCssManifest, inlineCssPrependCss?: string, inlineCssPrependFallbackHTML?: string, inlineCssScriptNonce?: string): TransformStream<Uint8Array, Uint8Array>;
|
|
35
59
|
//#endregion
|
|
36
60
|
export { createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs, navigationRuntimeRscBootstrapExpression };
|
|
37
61
|
//# sourceMappingURL=app-ssr-stream.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION } from "../client/navigation-runtime.js";
|
|
2
|
-
import { createInlineScriptTag, safeJsonStringify } from "./html.js";
|
|
2
|
+
import { createInlineScriptTag, escapeHtmlAttr, htmlTokenListContains, safeJsonStringify } from "./html.js";
|
|
3
3
|
import { bytesToBase64, concatUint8Arrays } from "./app-rsc-embedded-chunks.js";
|
|
4
4
|
//#region src/server/app-ssr-stream.ts
|
|
5
5
|
const NAVIGATION_RUNTIME_REFERENCE = `self[Symbol.for(${safeJsonStringify(NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION)})]`;
|
|
@@ -86,43 +86,259 @@ function createRscEmbedTransform(embedStream, scriptNonce) {
|
|
|
86
86
|
function fixPreloadAs(html) {
|
|
87
87
|
return html.replace(/<link(?=[^>]*\srel="preload")[^>]*>/g, (tag) => tag.replace(" as=\"stylesheet\"", " as=\"style\""));
|
|
88
88
|
}
|
|
89
|
+
const LINK_TAG_RE = /<link\b[^>]*>/gi;
|
|
90
|
+
const HTML_REWRITE_EXCLUDED_REGION_RE = /<!--[\s\S]*?-->|<(script|style|textarea|title)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
|
|
91
|
+
const HTML_REWRITE_EXCLUDED_REGION_START_RE = /<!--|<(script|style|textarea|title)\b[^>]*>/gi;
|
|
92
|
+
function getHtmlAttribute(tag, name) {
|
|
93
|
+
const attrRe = /\s([^\s"'=<>`]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
94
|
+
let match;
|
|
95
|
+
while ((match = attrRe.exec(tag)) !== null) {
|
|
96
|
+
if (match[1]?.toLowerCase() !== name.toLowerCase()) continue;
|
|
97
|
+
return match[2] ?? match[3] ?? match[4] ?? "";
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function htmlAttributeHasToken(tag, name, token) {
|
|
102
|
+
return htmlTokenListContains(getHtmlAttribute(tag, name), token);
|
|
103
|
+
}
|
|
104
|
+
function getInlineCss(manifest, href) {
|
|
105
|
+
if (Object.prototype.hasOwnProperty.call(manifest, href)) return manifest[href] ?? "";
|
|
106
|
+
try {
|
|
107
|
+
const pathname = new URL(href).pathname;
|
|
108
|
+
if (Object.prototype.hasOwnProperty.call(manifest, pathname)) return manifest[pathname] ?? "";
|
|
109
|
+
} catch {}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const TRAILING_LINK_OPEN_RE = /<link/gi;
|
|
113
|
+
function splitTrailingIncompleteLinkTag(html) {
|
|
114
|
+
TRAILING_LINK_OPEN_RE.lastIndex = 0;
|
|
115
|
+
let lastIndex = -1;
|
|
116
|
+
let match;
|
|
117
|
+
while ((match = TRAILING_LINK_OPEN_RE.exec(html)) !== null) lastIndex = match.index;
|
|
118
|
+
if (lastIndex === -1) return {
|
|
119
|
+
complete: html,
|
|
120
|
+
trailing: ""
|
|
121
|
+
};
|
|
122
|
+
if (html.indexOf(">", lastIndex) !== -1) return {
|
|
123
|
+
complete: html,
|
|
124
|
+
trailing: ""
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
complete: html.slice(0, lastIndex),
|
|
128
|
+
trailing: html.slice(lastIndex)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function findTrailingOpenHtmlRewriteExcludedRegionStart(html) {
|
|
132
|
+
let match;
|
|
133
|
+
HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex = 0;
|
|
134
|
+
while ((match = HTML_REWRITE_EXCLUDED_REGION_START_RE.exec(html)) !== null) {
|
|
135
|
+
const start = match.index;
|
|
136
|
+
if (match[0] === "<!--") {
|
|
137
|
+
const close = html.indexOf("-->", HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex);
|
|
138
|
+
if (close === -1) return start;
|
|
139
|
+
HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex = close + 3;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const tagName = match[1]?.toLowerCase();
|
|
143
|
+
if (!tagName) continue;
|
|
144
|
+
const close = new RegExp(`</${tagName}\\s*>`, "i").exec(html.slice(HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex));
|
|
145
|
+
if (!close) return start;
|
|
146
|
+
HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex += close.index + close[0].length;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
function splitTrailingInlineCssRewriteBoundary(html) {
|
|
151
|
+
const linkSplit = splitTrailingIncompleteLinkTag(html);
|
|
152
|
+
const incompleteLinkStart = linkSplit.trailing ? linkSplit.complete.length : null;
|
|
153
|
+
const openRegionStart = findTrailingOpenHtmlRewriteExcludedRegionStart(html);
|
|
154
|
+
const trailingStart = incompleteLinkStart === null ? openRegionStart : openRegionStart === null ? incompleteLinkStart : Math.min(incompleteLinkStart, openRegionStart);
|
|
155
|
+
if (trailingStart === null) return {
|
|
156
|
+
complete: html,
|
|
157
|
+
trailing: ""
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
complete: html.slice(0, trailingStart),
|
|
161
|
+
trailing: html.slice(trailingStart)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function escapeStyleText(css) {
|
|
165
|
+
return css.replace(/<\/style/gi, "<\\/style");
|
|
166
|
+
}
|
|
167
|
+
const CSS_PREPEND_UNSAFE_PREAMBLE_RE = /^\uFEFF?(?:\s|\/\*[\s\S]*?\*\/)*@(charset|import|layer|namespace)\b/i;
|
|
168
|
+
function canPrependCss(css) {
|
|
169
|
+
return !CSS_PREPEND_UNSAFE_PREAMBLE_RE.test(css);
|
|
170
|
+
}
|
|
171
|
+
function replaceLinkTags(html, replaceLinkTag) {
|
|
172
|
+
LINK_TAG_RE.lastIndex = 0;
|
|
173
|
+
return html.replace(LINK_TAG_RE, replaceLinkTag);
|
|
174
|
+
}
|
|
175
|
+
function replaceLinkTagsOutsideRawText(html, replaceLinkTag) {
|
|
176
|
+
let rewritten = "";
|
|
177
|
+
let cursor = 0;
|
|
178
|
+
let match;
|
|
179
|
+
HTML_REWRITE_EXCLUDED_REGION_RE.lastIndex = 0;
|
|
180
|
+
while ((match = HTML_REWRITE_EXCLUDED_REGION_RE.exec(html)) !== null) {
|
|
181
|
+
rewritten += replaceLinkTags(html.slice(cursor, match.index), replaceLinkTag);
|
|
182
|
+
rewritten += match[0];
|
|
183
|
+
cursor = match.index + match[0].length;
|
|
184
|
+
}
|
|
185
|
+
const tail = html.slice(cursor);
|
|
186
|
+
const openRegionStart = findTrailingOpenHtmlRewriteExcludedRegionStart(tail);
|
|
187
|
+
if (openRegionStart === null) return rewritten + replaceLinkTags(tail, replaceLinkTag);
|
|
188
|
+
return rewritten + replaceLinkTags(tail.slice(0, openRegionStart), replaceLinkTag) + tail.slice(openRegionStart);
|
|
189
|
+
}
|
|
190
|
+
function rewriteInlineCssStylesheetLinks(html, inlineCssManifest, prependCss, ssrScriptNonce) {
|
|
191
|
+
if (!inlineCssManifest || Object.keys(inlineCssManifest).length === 0) return {
|
|
192
|
+
html,
|
|
193
|
+
consumedPrependCss: false
|
|
194
|
+
};
|
|
195
|
+
let consumedPrependCss = false;
|
|
196
|
+
return {
|
|
197
|
+
html: replaceLinkTagsOutsideRawText(html, (tag) => {
|
|
198
|
+
if (!htmlAttributeHasToken(tag, "rel", "stylesheet")) return tag;
|
|
199
|
+
const href = getHtmlAttribute(tag, "href");
|
|
200
|
+
const precedence = getHtmlAttribute(tag, "data-precedence") ?? getHtmlAttribute(tag, "precedence");
|
|
201
|
+
if (!href || !precedence) return tag;
|
|
202
|
+
const css = getInlineCss(inlineCssManifest, href);
|
|
203
|
+
if (css === null) return tag;
|
|
204
|
+
const effectiveNonce = getHtmlAttribute(tag, "nonce") ?? ssrScriptNonce;
|
|
205
|
+
const nonceAttr = effectiveNonce ? ` nonce="${escapeHtmlAttr(effectiveNonce)}"` : "";
|
|
206
|
+
const cssPrefix = !consumedPrependCss && prependCss.length > 0 && canPrependCss(css) ? `${prependCss}\n` : "";
|
|
207
|
+
consumedPrependCss ||= cssPrefix.length > 0;
|
|
208
|
+
return `<style data-vinext-inline-css${nonceAttr} data-precedence="${escapeHtmlAttr(precedence)}" data-href="${escapeHtmlAttr(href)}">${escapeStyleText(cssPrefix + css)}</style>`;
|
|
209
|
+
}),
|
|
210
|
+
consumedPrependCss
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Match the `<head ...>` opening tag in a chunk. Matches both bare `<head>`
|
|
215
|
+
* and `<head class="foo">` shapes. Used to splice HTML immediately after the
|
|
216
|
+
* opening tag so injected content runs before any React-emitted resource
|
|
217
|
+
* hints (stylesheets, modulepreloads) that React Float hoists into `<head>`.
|
|
218
|
+
*/
|
|
219
|
+
const HEAD_OPEN_RE = /<head\b[^>]*>/;
|
|
89
220
|
/**
|
|
90
221
|
* Create the tick-buffered HTML transform that injects RSC scripts between
|
|
91
222
|
* React Fizz flush cycles without corrupting split HTML chunks.
|
|
223
|
+
*
|
|
224
|
+
* Two insertion points are supported in tandem:
|
|
225
|
+
*
|
|
226
|
+
* - `injectHTML` is emitted immediately before `</head>`. This is where the
|
|
227
|
+
* bulk of vinext's head additions live (RSC navigation runtime metadata,
|
|
228
|
+
* bootstrap modulepreload, server-inserted HTML, font preloads, etc.).
|
|
229
|
+
* - `injectAfterHeadOpenHTML` is emitted immediately after the `<head ...>`
|
|
230
|
+
* opening tag so the content runs before any React-emitted resource
|
|
231
|
+
* hints. This is where inline `<Script strategy="beforeInteractive">`
|
|
232
|
+
* captures land so the no-flash dark-mode pattern works.
|
|
233
|
+
*
|
|
234
|
+
* Fallback behaviour differs by insertion point:
|
|
235
|
+
*
|
|
236
|
+
* - `injectHTML` is emitted at end-of-stream by the `flush` handler when no
|
|
237
|
+
* chunk ever contained `</head>` — callers still see the payload on
|
|
238
|
+
* highly fragmented streams (just at the end of the body rather than in
|
|
239
|
+
* the head).
|
|
240
|
+
* - `injectAfterHeadOpenHTML` is silently dropped when `<head ...>` is not
|
|
241
|
+
* found in a discoverable chunk. Emitting it at end-of-stream would put
|
|
242
|
+
* it after the document body, defeating the point — the splice has to
|
|
243
|
+
* happen before resource hints to be useful, so the safer behaviour is
|
|
244
|
+
* to no-op and let the user-rendered Script (in its source-order
|
|
245
|
+
* position) ship as-is.
|
|
92
246
|
*/
|
|
93
|
-
function createTickBufferedTransform(rscEmbed, injectHTML = "") {
|
|
247
|
+
function createTickBufferedTransform(rscEmbed, injectHTML = "", injectAfterHeadOpenHTML = "", inlineCssManifest, inlineCssPrependCss = "", inlineCssPrependFallbackHTML = "", inlineCssScriptNonce) {
|
|
94
248
|
const decoder = new TextDecoder();
|
|
95
249
|
const encoder = new TextEncoder();
|
|
96
250
|
const insertsPerFlush = typeof injectHTML === "function";
|
|
97
251
|
let injected = false;
|
|
252
|
+
let preHeadInjected = false;
|
|
98
253
|
let buffered = [];
|
|
254
|
+
let pendingHtml = "";
|
|
99
255
|
let timeoutId = null;
|
|
256
|
+
const hasInlineCssManifest = inlineCssManifest !== void 0 && Object.keys(inlineCssManifest).length > 0;
|
|
100
257
|
const readInsertion = () => typeof injectHTML === "function" ? injectHTML() : injectHTML;
|
|
258
|
+
const readPreHeadInsertion = () => typeof injectAfterHeadOpenHTML === "function" ? injectAfterHeadOpenHTML() : injectAfterHeadOpenHTML;
|
|
259
|
+
const readInlineCssPrependFallback = () => {
|
|
260
|
+
if (!inlineCssPrependCss || !inlineCssPrependFallbackHTML) return "";
|
|
261
|
+
inlineCssPrependCss = "";
|
|
262
|
+
return inlineCssPrependFallbackHTML;
|
|
263
|
+
};
|
|
101
264
|
const emitInsertion = (controller) => {
|
|
102
|
-
const insertion = readInsertion();
|
|
265
|
+
const insertion = readInlineCssPrependFallback() + readInsertion();
|
|
103
266
|
if (insertion) controller.enqueue(encoder.encode(insertion));
|
|
104
267
|
};
|
|
105
|
-
|
|
106
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Splice the pre-head insertion (typically captured beforeInteractive inline
|
|
270
|
+
* scripts) immediately after the `<head ...>` opening tag. Returns the
|
|
271
|
+
* rewritten chunk and a flag indicating whether the splice happened, so the
|
|
272
|
+
* caller can mark `preHeadInjected` and stop scanning further chunks.
|
|
273
|
+
*
|
|
274
|
+
* NOTE: This is called only when `<head ...>` lies fully inside the current
|
|
275
|
+
* tick-buffered batch. We deliberately avoid retaining arbitrary output until
|
|
276
|
+
* a future chunk completes `<head ...>`, which would delay TTFB and complicate
|
|
277
|
+
* the existing `</head>` injection path. In practice React Fizz emits the
|
|
278
|
+
* opening shell as a single batch.
|
|
279
|
+
*/
|
|
280
|
+
const spliceAfterHeadOpen = (chunk) => {
|
|
281
|
+
if (preHeadInjected) return {
|
|
282
|
+
chunk,
|
|
283
|
+
spliced: false
|
|
284
|
+
};
|
|
285
|
+
const insertion = readPreHeadInsertion();
|
|
286
|
+
if (!insertion) return {
|
|
287
|
+
chunk,
|
|
288
|
+
spliced: false
|
|
289
|
+
};
|
|
290
|
+
const match = HEAD_OPEN_RE.exec(chunk);
|
|
291
|
+
if (!match) return {
|
|
292
|
+
chunk,
|
|
293
|
+
spliced: false
|
|
294
|
+
};
|
|
295
|
+
const insertAt = match.index + match[0].length;
|
|
296
|
+
return {
|
|
297
|
+
chunk: chunk.slice(0, insertAt) + insertion + chunk.slice(insertAt),
|
|
298
|
+
spliced: true
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
const flushBuffered = (controller, final = false) => {
|
|
302
|
+
if (buffered.length === 0 && !pendingHtml) return;
|
|
303
|
+
const rawHtml = pendingHtml + buffered.join("");
|
|
304
|
+
buffered = [];
|
|
305
|
+
pendingHtml = "";
|
|
306
|
+
const split = final || !hasInlineCssManifest ? {
|
|
307
|
+
complete: rawHtml,
|
|
308
|
+
trailing: ""
|
|
309
|
+
} : splitTrailingInlineCssRewriteBoundary(rawHtml);
|
|
310
|
+
if (split.trailing) pendingHtml = split.trailing;
|
|
311
|
+
if (!split.complete) return;
|
|
107
312
|
if (injected && insertsPerFlush) emitInsertion(controller);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
313
|
+
const preparedHtml = fixPreloadAs(split.complete);
|
|
314
|
+
const inlineCssResult = hasInlineCssManifest ? rewriteInlineCssStylesheetLinks(preparedHtml, inlineCssManifest, inlineCssPrependCss, inlineCssScriptNonce) : {
|
|
315
|
+
html: preparedHtml,
|
|
316
|
+
consumedPrependCss: false
|
|
317
|
+
};
|
|
318
|
+
if (inlineCssResult.consumedPrependCss) inlineCssPrependCss = "";
|
|
319
|
+
let working = inlineCssResult.html;
|
|
320
|
+
if (!preHeadInjected) {
|
|
321
|
+
const result = spliceAfterHeadOpen(working);
|
|
322
|
+
if (result.spliced) {
|
|
323
|
+
working = result.chunk;
|
|
324
|
+
preHeadInjected = true;
|
|
118
325
|
}
|
|
119
|
-
controller.enqueue(encoder.encode(chunk));
|
|
120
326
|
}
|
|
121
|
-
|
|
327
|
+
if (!injected) {
|
|
328
|
+
const headEnd = working.indexOf("</head>");
|
|
329
|
+
if (headEnd !== -1) {
|
|
330
|
+
const before = working.slice(0, headEnd);
|
|
331
|
+
const after = working.slice(headEnd);
|
|
332
|
+
controller.enqueue(encoder.encode(before + readInlineCssPrependFallback() + readInsertion() + after));
|
|
333
|
+
injected = true;
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
controller.enqueue(encoder.encode(working));
|
|
122
338
|
};
|
|
123
339
|
return new TransformStream({
|
|
124
340
|
transform(chunk, controller) {
|
|
125
|
-
buffered.push(
|
|
341
|
+
buffered.push(decoder.decode(chunk, { stream: true }));
|
|
126
342
|
if (timeoutId !== null) return;
|
|
127
343
|
timeoutId = setTimeout(() => {
|
|
128
344
|
try {
|
|
@@ -138,7 +354,9 @@ function createTickBufferedTransform(rscEmbed, injectHTML = "") {
|
|
|
138
354
|
clearTimeout(timeoutId);
|
|
139
355
|
timeoutId = null;
|
|
140
356
|
}
|
|
141
|
-
|
|
357
|
+
const remainder = decoder.decode();
|
|
358
|
+
if (remainder) buffered.push(remainder);
|
|
359
|
+
flushBuffered(controller, true);
|
|
142
360
|
if (!injected) {
|
|
143
361
|
emitInsertion(controller);
|
|
144
362
|
injected = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-ssr-stream.js","names":[],"sources":["../../src/server/app-ssr-stream.ts"],"sourcesContent":["import { createInlineScriptTag, safeJsonStringify } from \"./html.js\";\nimport {\n bytesToBase64,\n concatUint8Arrays,\n RSC_EMBEDDED_BINARY_CHUNK,\n type RscEmbeddedChunk,\n} from \"./app-rsc-embedded-chunks.js\";\nimport { NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION } from \"../client/navigation-runtime.js\";\n\ntype RscEmbedTransform = {\n flush(): string;\n finalize(): Promise<string>;\n /** Resolves when all raw bytes from the embed stream have been read. */\n getRawBuffer(): Promise<ArrayBuffer>;\n};\n\ntype HtmlInsertion = string | (() => string);\n\nconst NAVIGATION_RUNTIME_REFERENCE = `self[Symbol.for(${safeJsonStringify(\n NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION,\n)})]`;\n\nexport function navigationRuntimeRscBootstrapExpression(): string {\n return `((${NAVIGATION_RUNTIME_REFERENCE}??={bootstrap:{routeManifest:null},functions:{}}).bootstrap.rsc??={rsc:[]})`;\n}\n\nexport function createNavigationRuntimeRscMetadataScript(\n params: Record<string, string | string[]>,\n nav: { pathname: string; searchParams: [string, string][] },\n): string {\n return (\n \"Object.assign(\" +\n navigationRuntimeRscBootstrapExpression() +\n \",{params:\" +\n safeJsonStringify(params) +\n \",nav:\" +\n safeJsonStringify(nav) +\n \"})\"\n );\n}\n\nfunction createNavigationRuntimeRscChunkScript(chunk: RscEmbeddedChunk): string {\n return navigationRuntimeRscBootstrapExpression() + \".rsc.push(\" + safeJsonStringify(chunk) + \")\";\n}\n\nfunction createNavigationRuntimeRscDoneScript(): string {\n return navigationRuntimeRscBootstrapExpression() + \".done=true\";\n}\n\n/**\n * Fix invalid preload \"as\" values in RSC Flight hint lines before they reach\n * the client. React Flight emits HL hints with as=\"stylesheet\" for CSS, but\n * the HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixFlightHints(text: string): string {\n return text.replace(/(\\d*:HL\\[.*?),\"stylesheet\"(\\]|,)/g, '$1,\"style\"$2');\n}\n\n/**\n * Create a helper that progressively embeds RSC chunks as inline <script> tags.\n * The browser entry turns the embedded chunks back into Uint8Array data.\n */\nexport function createRscEmbedTransform(\n embedStream: ReadableStream<Uint8Array>,\n scriptNonce?: string,\n): RscEmbedTransform {\n const reader = embedStream.getReader();\n let pendingChunks: RscEmbeddedChunk[] = [];\n const rawChunks: Uint8Array[] = [];\n let reading = false;\n\n async function pumpReader(): Promise<void> {\n if (reading) return;\n reading = true;\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n // Accumulate raw bytes BEFORE fixFlightHints so the cache stores\n // unmodified RSC data. The embed script path below applies fixes.\n rawChunks.push(result.value);\n try {\n const decoder = new TextDecoder(\"utf-8\", { fatal: true });\n const text = decoder.decode(result.value);\n // The RSC entry already fixes HL hints at the source. Keep this second\n // pass as defense in depth for any embed stream that bypasses that\n // wrapper; the rewrite is idempotent, so double-application is safe.\n pendingChunks.push(fixFlightHints(text));\n } catch {\n pendingChunks.push([RSC_EMBEDDED_BINARY_CHUNK, bytesToBase64(result.value)]);\n }\n }\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] RSC embed stream read error:\", error);\n }\n throw error;\n } finally {\n reading = false;\n }\n }\n\n const pumpPromise = pumpReader();\n\n return {\n flush(): string {\n if (pendingChunks.length === 0) return \"\";\n\n const chunks = pendingChunks;\n pendingChunks = [];\n\n let scripts = \"\";\n for (const chunk of chunks) {\n scripts += createInlineScriptTag(createNavigationRuntimeRscChunkScript(chunk), scriptNonce);\n }\n return scripts;\n },\n\n async finalize(): Promise<string> {\n await pumpPromise;\n let scripts = this.flush();\n scripts += createInlineScriptTag(createNavigationRuntimeRscDoneScript(), scriptNonce);\n return scripts;\n },\n\n async getRawBuffer(): Promise<ArrayBuffer> {\n await pumpPromise;\n const buffer = concatUint8Arrays(rawChunks);\n rawChunks.length = 0;\n return buffer.buffer;\n },\n };\n}\n\n/**\n * Fix invalid preload \"as\" values in server-rendered HTML.\n * React Fizz emits <link rel=\"preload\" as=\"stylesheet\"> for CSS, but the\n * HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixPreloadAs(html: string): string {\n return html.replace(/<link(?=[^>]*\\srel=\"preload\")[^>]*>/g, (tag) =>\n tag.replace(' as=\"stylesheet\"', ' as=\"style\"'),\n );\n}\n\n/**\n * Create the tick-buffered HTML transform that injects RSC scripts between\n * React Fizz flush cycles without corrupting split HTML chunks.\n */\nexport function createTickBufferedTransform(\n rscEmbed: RscEmbedTransform,\n injectHTML: HtmlInsertion = \"\",\n): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n const insertsPerFlush = typeof injectHTML === \"function\";\n let injected = false;\n let buffered: string[] = [];\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n const readInsertion = (): string =>\n typeof injectHTML === \"function\" ? injectHTML() : injectHTML;\n const emitInsertion = (controller: TransformStreamDefaultController<Uint8Array>): void => {\n const insertion = readInsertion();\n if (insertion) {\n controller.enqueue(encoder.encode(insertion));\n }\n };\n\n const flushBuffered = (controller: TransformStreamDefaultController<Uint8Array>): void => {\n if (buffered.length === 0) return;\n\n if (injected && insertsPerFlush) {\n // Emit newly collected server-inserted HTML before the next Fizz HTML\n // batch so CSS-in-JS styles precede the elements they style.\n emitInsertion(controller);\n }\n\n for (const chunk of buffered) {\n if (!injected) {\n const headEnd = chunk.indexOf(\"</head>\");\n if (headEnd !== -1) {\n const before = chunk.slice(0, headEnd);\n const after = chunk.slice(headEnd);\n controller.enqueue(encoder.encode(before + readInsertion() + after));\n injected = true;\n continue;\n }\n }\n controller.enqueue(encoder.encode(chunk));\n }\n buffered = [];\n };\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buffered.push(fixPreloadAs(decoder.decode(chunk, { stream: true })));\n\n if (timeoutId !== null) return;\n\n timeoutId = setTimeout(() => {\n try {\n flushBuffered(controller);\n\n const rscScripts = rscEmbed.flush();\n if (rscScripts) {\n controller.enqueue(encoder.encode(rscScripts));\n }\n } catch {\n // Stream was cancelled between when the timeout was registered and\n // when it fired (e.g. client disconnected, health-check cancelled\n // the response body). Ignore — the stream is already closed.\n }\n\n timeoutId = null;\n }, 0);\n },\n\n async flush(controller) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n flushBuffered(controller);\n\n if (!injected) {\n emitInsertion(controller);\n injected = true;\n } else if (insertsPerFlush) {\n emitInsertion(controller);\n }\n\n const finalScripts = await rscEmbed.finalize();\n if (finalScripts) {\n controller.enqueue(encoder.encode(finalScripts));\n }\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-ssr-stream.js","names":[],"sources":["../../src/server/app-ssr-stream.ts"],"sourcesContent":["import {\n createInlineScriptTag,\n escapeHtmlAttr,\n htmlTokenListContains,\n safeJsonStringify,\n} from \"./html.js\";\nimport {\n bytesToBase64,\n concatUint8Arrays,\n RSC_EMBEDDED_BINARY_CHUNK,\n type RscEmbeddedChunk,\n} from \"./app-rsc-embedded-chunks.js\";\nimport { NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION } from \"../client/navigation-runtime.js\";\n\ntype RscEmbedTransform = {\n flush(): string;\n finalize(): Promise<string>;\n /** Resolves when all raw bytes from the embed stream have been read. */\n getRawBuffer(): Promise<ArrayBuffer>;\n};\n\ntype HtmlInsertion = string | (() => string);\ntype InlineCssManifest = Record<string, string>;\ntype InlineCssRewriteResult = {\n html: string;\n consumedPrependCss: boolean;\n};\n\nconst NAVIGATION_RUNTIME_REFERENCE = `self[Symbol.for(${safeJsonStringify(\n NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION,\n)})]`;\n\nexport function navigationRuntimeRscBootstrapExpression(): string {\n return `((${NAVIGATION_RUNTIME_REFERENCE}??={bootstrap:{routeManifest:null},functions:{}}).bootstrap.rsc??={rsc:[]})`;\n}\n\nexport function createNavigationRuntimeRscMetadataScript(\n params: Record<string, string | string[]>,\n nav: { pathname: string; searchParams: [string, string][] },\n): string {\n return (\n \"Object.assign(\" +\n navigationRuntimeRscBootstrapExpression() +\n \",{params:\" +\n safeJsonStringify(params) +\n \",nav:\" +\n safeJsonStringify(nav) +\n \"})\"\n );\n}\n\nfunction createNavigationRuntimeRscChunkScript(chunk: RscEmbeddedChunk): string {\n return navigationRuntimeRscBootstrapExpression() + \".rsc.push(\" + safeJsonStringify(chunk) + \")\";\n}\n\nfunction createNavigationRuntimeRscDoneScript(): string {\n return navigationRuntimeRscBootstrapExpression() + \".done=true\";\n}\n\n/**\n * Fix invalid preload \"as\" values in RSC Flight hint lines before they reach\n * the client. React Flight emits HL hints with as=\"stylesheet\" for CSS, but\n * the HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixFlightHints(text: string): string {\n return text.replace(/(\\d*:HL\\[.*?),\"stylesheet\"(\\]|,)/g, '$1,\"style\"$2');\n}\n\n/**\n * Create a helper that progressively embeds RSC chunks as inline <script> tags.\n * The browser entry turns the embedded chunks back into Uint8Array data.\n */\nexport function createRscEmbedTransform(\n embedStream: ReadableStream<Uint8Array>,\n scriptNonce?: string,\n): RscEmbedTransform {\n const reader = embedStream.getReader();\n let pendingChunks: RscEmbeddedChunk[] = [];\n const rawChunks: Uint8Array[] = [];\n let reading = false;\n\n async function pumpReader(): Promise<void> {\n if (reading) return;\n reading = true;\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n // Accumulate raw bytes BEFORE fixFlightHints so the cache stores\n // unmodified RSC data. The embed script path below applies fixes.\n rawChunks.push(result.value);\n try {\n const decoder = new TextDecoder(\"utf-8\", { fatal: true });\n const text = decoder.decode(result.value);\n // The RSC entry already fixes HL hints at the source. Keep this second\n // pass as defense in depth for any embed stream that bypasses that\n // wrapper; the rewrite is idempotent, so double-application is safe.\n pendingChunks.push(fixFlightHints(text));\n } catch {\n pendingChunks.push([RSC_EMBEDDED_BINARY_CHUNK, bytesToBase64(result.value)]);\n }\n }\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] RSC embed stream read error:\", error);\n }\n throw error;\n } finally {\n reading = false;\n }\n }\n\n const pumpPromise = pumpReader();\n\n return {\n flush(): string {\n if (pendingChunks.length === 0) return \"\";\n\n const chunks = pendingChunks;\n pendingChunks = [];\n\n let scripts = \"\";\n for (const chunk of chunks) {\n scripts += createInlineScriptTag(createNavigationRuntimeRscChunkScript(chunk), scriptNonce);\n }\n return scripts;\n },\n\n async finalize(): Promise<string> {\n await pumpPromise;\n let scripts = this.flush();\n scripts += createInlineScriptTag(createNavigationRuntimeRscDoneScript(), scriptNonce);\n return scripts;\n },\n\n async getRawBuffer(): Promise<ArrayBuffer> {\n await pumpPromise;\n const buffer = concatUint8Arrays(rawChunks);\n rawChunks.length = 0;\n return buffer.buffer;\n },\n };\n}\n\n/**\n * Fix invalid preload \"as\" values in server-rendered HTML.\n * React Fizz emits <link rel=\"preload\" as=\"stylesheet\"> for CSS, but the\n * HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixPreloadAs(html: string): string {\n return html.replace(/<link(?=[^>]*\\srel=\"preload\")[^>]*>/g, (tag) =>\n tag.replace(' as=\"stylesheet\"', ' as=\"style\"'),\n );\n}\n\n// These `g`-flag regexes carry mutable `lastIndex` state. Every consumer below\n// resets `lastIndex` before use, which is safe only because they run to\n// completion synchronously within a single call. They must not be shared across\n// concurrent/interleaved call paths.\nconst LINK_TAG_RE = /<link\\b[^>]*>/gi;\nconst HTML_REWRITE_EXCLUDED_REGION_RE =\n /<!--[\\s\\S]*?-->|<(script|style|textarea|title)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi;\nconst HTML_REWRITE_EXCLUDED_REGION_START_RE = /<!--|<(script|style|textarea|title)\\b[^>]*>/gi;\n\nfunction getHtmlAttribute(tag: string, name: string): string | null {\n const attrRe = /\\s([^\\s\"'=<>`]+)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRe.exec(tag)) !== null) {\n if (match[1]?.toLowerCase() !== name.toLowerCase()) continue;\n return match[2] ?? match[3] ?? match[4] ?? \"\";\n }\n\n return null;\n}\n\nfunction htmlAttributeHasToken(tag: string, name: string, token: string): boolean {\n return htmlTokenListContains(getHtmlAttribute(tag, name), token);\n}\n\nfunction getInlineCss(manifest: InlineCssManifest, href: string): string | null {\n if (Object.prototype.hasOwnProperty.call(manifest, href)) {\n return manifest[href] ?? \"\";\n }\n\n try {\n const pathname = new URL(href).pathname;\n if (Object.prototype.hasOwnProperty.call(manifest, pathname)) {\n return manifest[pathname] ?? \"\";\n }\n } catch {\n // Relative asset URLs are looked up by their emitted href.\n }\n\n return null;\n}\n\n// Module-level regex; consumers reset `lastIndex` before each scan. Same\n// shared-state constraint as the other `g`-flag regexes above.\nconst TRAILING_LINK_OPEN_RE = /<link/gi;\n\nfunction splitTrailingIncompleteLinkTag(html: string): { complete: string; trailing: string } {\n // Scan forward to find the last `<link` opening without allocating a\n // lowercased copy of `html` — this runs on every flush of the streaming\n // hot path, and `html` can be tens of KB.\n TRAILING_LINK_OPEN_RE.lastIndex = 0;\n let lastIndex = -1;\n let match: RegExpExecArray | null;\n while ((match = TRAILING_LINK_OPEN_RE.exec(html)) !== null) {\n lastIndex = match.index;\n }\n if (lastIndex === -1) return { complete: html, trailing: \"\" };\n const close = html.indexOf(\">\", lastIndex);\n if (close !== -1) return { complete: html, trailing: \"\" };\n return {\n complete: html.slice(0, lastIndex),\n trailing: html.slice(lastIndex),\n };\n}\n\nfunction findTrailingOpenHtmlRewriteExcludedRegionStart(html: string): number | null {\n let match: RegExpExecArray | null;\n\n HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex = 0;\n while ((match = HTML_REWRITE_EXCLUDED_REGION_START_RE.exec(html)) !== null) {\n const start = match.index;\n if (match[0] === \"<!--\") {\n const close = html.indexOf(\"-->\", HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex);\n if (close === -1) return start;\n HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex = close + 3;\n continue;\n }\n\n const tagName = match[1]?.toLowerCase();\n if (!tagName) continue;\n\n const closeTagRe = new RegExp(`</${tagName}\\\\s*>`, \"i\");\n const close = closeTagRe.exec(html.slice(HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex));\n if (!close) return start;\n HTML_REWRITE_EXCLUDED_REGION_START_RE.lastIndex += close.index + close[0].length;\n }\n\n return null;\n}\n\nfunction splitTrailingInlineCssRewriteBoundary(html: string): {\n complete: string;\n trailing: string;\n} {\n const linkSplit = splitTrailingIncompleteLinkTag(html);\n const incompleteLinkStart = linkSplit.trailing ? linkSplit.complete.length : null;\n const openRegionStart = findTrailingOpenHtmlRewriteExcludedRegionStart(html);\n const trailingStart =\n incompleteLinkStart === null\n ? openRegionStart\n : openRegionStart === null\n ? incompleteLinkStart\n : Math.min(incompleteLinkStart, openRegionStart);\n\n if (trailingStart === null) return { complete: html, trailing: \"\" };\n\n return {\n complete: html.slice(0, trailingStart),\n trailing: html.slice(trailingStart),\n };\n}\n\nfunction escapeStyleText(css: string): string {\n return css.replace(/<\\/style/gi, \"<\\\\/style\");\n}\n\nconst CSS_PREPEND_UNSAFE_PREAMBLE_RE =\n /^\\uFEFF?(?:\\s|\\/\\*[\\s\\S]*?\\*\\/)*@(charset|import|layer|namespace)\\b/i;\n\nfunction canPrependCss(css: string): boolean {\n return !CSS_PREPEND_UNSAFE_PREAMBLE_RE.test(css);\n}\n\nfunction replaceLinkTags(html: string, replaceLinkTag: (tag: string) => string): string {\n LINK_TAG_RE.lastIndex = 0;\n return html.replace(LINK_TAG_RE, replaceLinkTag);\n}\n\nfunction replaceLinkTagsOutsideRawText(\n html: string,\n replaceLinkTag: (tag: string) => string,\n): string {\n let rewritten = \"\";\n let cursor = 0;\n let match: RegExpExecArray | null;\n\n HTML_REWRITE_EXCLUDED_REGION_RE.lastIndex = 0;\n while ((match = HTML_REWRITE_EXCLUDED_REGION_RE.exec(html)) !== null) {\n rewritten += replaceLinkTags(html.slice(cursor, match.index), replaceLinkTag);\n rewritten += match[0];\n cursor = match.index + match[0].length;\n }\n\n const tail = html.slice(cursor);\n const openRegionStart = findTrailingOpenHtmlRewriteExcludedRegionStart(tail);\n if (openRegionStart === null) {\n return rewritten + replaceLinkTags(tail, replaceLinkTag);\n }\n\n return (\n rewritten +\n replaceLinkTags(tail.slice(0, openRegionStart), replaceLinkTag) +\n tail.slice(openRegionStart)\n );\n}\n\nfunction rewriteInlineCssStylesheetLinks(\n html: string,\n inlineCssManifest: InlineCssManifest | undefined,\n prependCss: string,\n ssrScriptNonce: string | undefined,\n): InlineCssRewriteResult {\n if (!inlineCssManifest || Object.keys(inlineCssManifest).length === 0) {\n return { html, consumedPrependCss: false };\n }\n let consumedPrependCss = false;\n\n const rewritten = replaceLinkTagsOutsideRawText(html, (tag) => {\n if (!htmlAttributeHasToken(tag, \"rel\", \"stylesheet\")) return tag;\n\n const href = getHtmlAttribute(tag, \"href\");\n const precedence =\n getHtmlAttribute(tag, \"data-precedence\") ?? getHtmlAttribute(tag, \"precedence\");\n if (!href || !precedence) return tag;\n\n const css = getInlineCss(inlineCssManifest, href);\n if (css === null) return tag;\n\n // Prefer the link's own nonce if Fizz emitted one; otherwise fall back to\n // the SSR-time script/style nonce so sites with CSP `style-src 'nonce-…'`\n // policies don't block the inlined `<style>` block. The `<link>` tag this\n // replaces wasn't subject to inline-style CSP, but the new `<style>` is.\n const linkNonce = getHtmlAttribute(tag, \"nonce\");\n const effectiveNonce = linkNonce ?? ssrScriptNonce;\n const nonceAttr = effectiveNonce ? ` nonce=\"${escapeHtmlAttr(effectiveNonce)}\"` : \"\";\n const shouldPrependCss = !consumedPrependCss && prependCss.length > 0 && canPrependCss(css);\n const cssPrefix = shouldPrependCss ? `${prependCss}\\n` : \"\";\n consumedPrependCss ||= cssPrefix.length > 0;\n\n return (\n `<style data-vinext-inline-css${nonceAttr}` +\n ` data-precedence=\"${escapeHtmlAttr(precedence)}\"` +\n ` data-href=\"${escapeHtmlAttr(href)}\">` +\n `${escapeStyleText(cssPrefix + css)}</style>`\n );\n });\n\n return { html: rewritten, consumedPrependCss };\n}\n\n/**\n * Match the `<head ...>` opening tag in a chunk. Matches both bare `<head>`\n * and `<head class=\"foo\">` shapes. Used to splice HTML immediately after the\n * opening tag so injected content runs before any React-emitted resource\n * hints (stylesheets, modulepreloads) that React Float hoists into `<head>`.\n */\nconst HEAD_OPEN_RE = /<head\\b[^>]*>/;\n\n/**\n * Create the tick-buffered HTML transform that injects RSC scripts between\n * React Fizz flush cycles without corrupting split HTML chunks.\n *\n * Two insertion points are supported in tandem:\n *\n * - `injectHTML` is emitted immediately before `</head>`. This is where the\n * bulk of vinext's head additions live (RSC navigation runtime metadata,\n * bootstrap modulepreload, server-inserted HTML, font preloads, etc.).\n * - `injectAfterHeadOpenHTML` is emitted immediately after the `<head ...>`\n * opening tag so the content runs before any React-emitted resource\n * hints. This is where inline `<Script strategy=\"beforeInteractive\">`\n * captures land so the no-flash dark-mode pattern works.\n *\n * Fallback behaviour differs by insertion point:\n *\n * - `injectHTML` is emitted at end-of-stream by the `flush` handler when no\n * chunk ever contained `</head>` — callers still see the payload on\n * highly fragmented streams (just at the end of the body rather than in\n * the head).\n * - `injectAfterHeadOpenHTML` is silently dropped when `<head ...>` is not\n * found in a discoverable chunk. Emitting it at end-of-stream would put\n * it after the document body, defeating the point — the splice has to\n * happen before resource hints to be useful, so the safer behaviour is\n * to no-op and let the user-rendered Script (in its source-order\n * position) ship as-is.\n */\nexport function createTickBufferedTransform(\n rscEmbed: RscEmbedTransform,\n injectHTML: HtmlInsertion = \"\",\n injectAfterHeadOpenHTML: HtmlInsertion = \"\",\n inlineCssManifest?: InlineCssManifest,\n inlineCssPrependCss = \"\",\n inlineCssPrependFallbackHTML = \"\",\n inlineCssScriptNonce?: string,\n): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n const insertsPerFlush = typeof injectHTML === \"function\";\n let injected = false;\n let preHeadInjected = false;\n let buffered: string[] = [];\n let pendingHtml = \"\";\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n // Computed once at transform creation: every flush is a hot path, so we\n // avoid re-running Object.keys() on the manifest per chunk. Gates both the\n // split-link boundary buffering and the inline-css link rewrite below.\n const hasInlineCssManifest =\n inlineCssManifest !== undefined && Object.keys(inlineCssManifest).length > 0;\n const readInsertion = (): string =>\n typeof injectHTML === \"function\" ? injectHTML() : injectHTML;\n const readPreHeadInsertion = (): string =>\n typeof injectAfterHeadOpenHTML === \"function\"\n ? injectAfterHeadOpenHTML()\n : injectAfterHeadOpenHTML;\n const readInlineCssPrependFallback = (): string => {\n if (!inlineCssPrependCss || !inlineCssPrependFallbackHTML) return \"\";\n inlineCssPrependCss = \"\";\n return inlineCssPrependFallbackHTML;\n };\n const emitInsertion = (controller: TransformStreamDefaultController<Uint8Array>): void => {\n const insertion = readInlineCssPrependFallback() + readInsertion();\n if (insertion) {\n controller.enqueue(encoder.encode(insertion));\n }\n };\n\n /**\n * Splice the pre-head insertion (typically captured beforeInteractive inline\n * scripts) immediately after the `<head ...>` opening tag. Returns the\n * rewritten chunk and a flag indicating whether the splice happened, so the\n * caller can mark `preHeadInjected` and stop scanning further chunks.\n *\n * NOTE: This is called only when `<head ...>` lies fully inside the current\n * tick-buffered batch. We deliberately avoid retaining arbitrary output until\n * a future chunk completes `<head ...>`, which would delay TTFB and complicate\n * the existing `</head>` injection path. In practice React Fizz emits the\n * opening shell as a single batch.\n */\n const spliceAfterHeadOpen = (chunk: string): { chunk: string; spliced: boolean } => {\n if (preHeadInjected) return { chunk, spliced: false };\n const insertion = readPreHeadInsertion();\n if (!insertion) return { chunk, spliced: false };\n const match = HEAD_OPEN_RE.exec(chunk);\n if (!match) return { chunk, spliced: false };\n const insertAt = match.index + match[0].length;\n return {\n chunk: chunk.slice(0, insertAt) + insertion + chunk.slice(insertAt),\n spliced: true,\n };\n };\n\n const flushBuffered = (\n controller: TransformStreamDefaultController<Uint8Array>,\n final = false,\n ): void => {\n if (buffered.length === 0 && !pendingHtml) return;\n const rawHtml = pendingHtml + buffered.join(\"\");\n buffered = [];\n pendingHtml = \"\";\n\n const split =\n final || !hasInlineCssManifest\n ? { complete: rawHtml, trailing: \"\" }\n : splitTrailingInlineCssRewriteBoundary(rawHtml);\n if (split.trailing) {\n pendingHtml = split.trailing;\n }\n if (!split.complete) return;\n\n if (injected && insertsPerFlush) {\n // Emit newly collected server-inserted HTML before the next Fizz HTML\n // batch so CSS-in-JS styles precede the elements they style.\n emitInsertion(controller);\n }\n\n const preparedHtml = fixPreloadAs(split.complete);\n const inlineCssResult = hasInlineCssManifest\n ? rewriteInlineCssStylesheetLinks(\n preparedHtml,\n inlineCssManifest,\n inlineCssPrependCss,\n inlineCssScriptNonce,\n )\n : { html: preparedHtml, consumedPrependCss: false };\n if (inlineCssResult.consumedPrependCss) {\n inlineCssPrependCss = \"\";\n }\n\n let working = inlineCssResult.html;\n if (!preHeadInjected) {\n const result = spliceAfterHeadOpen(working);\n if (result.spliced) {\n working = result.chunk;\n preHeadInjected = true;\n }\n }\n if (!injected) {\n const headEnd = working.indexOf(\"</head>\");\n if (headEnd !== -1) {\n const before = working.slice(0, headEnd);\n const after = working.slice(headEnd);\n controller.enqueue(\n encoder.encode(before + readInlineCssPrependFallback() + readInsertion() + after),\n );\n injected = true;\n return;\n }\n }\n controller.enqueue(encoder.encode(working));\n };\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buffered.push(decoder.decode(chunk, { stream: true }));\n\n if (timeoutId !== null) return;\n\n timeoutId = setTimeout(() => {\n try {\n flushBuffered(controller);\n\n const rscScripts = rscEmbed.flush();\n if (rscScripts) {\n controller.enqueue(encoder.encode(rscScripts));\n }\n } catch {\n // Stream was cancelled between when the timeout was registered and\n // when it fired (e.g. client disconnected, health-check cancelled\n // the response body). Ignore — the stream is already closed.\n }\n\n timeoutId = null;\n }, 0);\n },\n\n async flush(controller) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n const remainder = decoder.decode();\n if (remainder) {\n buffered.push(remainder);\n }\n\n flushBuffered(controller, true);\n\n if (!injected) {\n emitInsertion(controller);\n injected = true;\n } else if (insertsPerFlush) {\n emitInsertion(controller);\n }\n\n const finalScripts = await rscEmbed.finalize();\n if (finalScripts) {\n controller.enqueue(encoder.encode(finalScripts));\n }\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { HeadersContext } from "../shims/headers.js";
|
|
|
3
3
|
//#region src/server/app-static-generation.d.ts
|
|
4
4
|
type AppStaticGenerationRouteKind = "page" | "route";
|
|
5
5
|
type CreateStaticGenerationHeadersContextOptions = {
|
|
6
|
+
draftModeSecret?: string;
|
|
6
7
|
dynamicConfig?: string;
|
|
7
8
|
routeKind: AppStaticGenerationRouteKind;
|
|
8
9
|
routePattern?: string;
|
|
@@ -8,7 +8,8 @@ function getAppRouteStaticGenerationErrorMessage(routePattern, expression) {
|
|
|
8
8
|
function createStaticGenerationHeadersContext(options) {
|
|
9
9
|
const context = {
|
|
10
10
|
headers: new Headers(),
|
|
11
|
-
cookies: /* @__PURE__ */ new Map()
|
|
11
|
+
cookies: /* @__PURE__ */ new Map(),
|
|
12
|
+
draftModeSecret: options.draftModeSecret
|
|
12
13
|
};
|
|
13
14
|
if (options.dynamicConfig === "force-static") context.forceStatic = true;
|
|
14
15
|
if (options.dynamicConfig === "error") context.accessError = new Error(options.routeKind === "route" ? getAppRouteStaticGenerationErrorMessage(options.routePattern) : getAppPageStaticGenerationErrorMessage());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-static-generation.js","names":[],"sources":["../../src/server/app-static-generation.ts"],"sourcesContent":["import type { HeadersContext } from \"vinext/shims/headers\";\n\ntype AppStaticGenerationRouteKind = \"page\" | \"route\";\n\ntype CreateStaticGenerationHeadersContextOptions = {\n dynamicConfig?: string;\n routeKind: AppStaticGenerationRouteKind;\n routePattern?: string;\n};\n\nexport function getAppPageStaticGenerationErrorMessage(): string {\n return (\n 'Page with `dynamic = \"error\"` used a dynamic API. ' +\n \"This page was expected to be fully static, but headers(), cookies(), \" +\n \"or searchParams was accessed. Remove the dynamic API usage or change \" +\n 'the dynamic config to \"auto\" or \"force-dynamic\".'\n );\n}\n\nexport function getAppRouteStaticGenerationErrorMessage(\n routePattern?: string,\n expression?: string,\n): string {\n const route = routePattern ?? \"unknown route\";\n const dynamicExpression = expression ?? \"a dynamic request API\";\n return (\n `Route ${route} with \\`dynamic = \"error\"\\` couldn't be rendered statically ` +\n `because it used ${dynamicExpression}. ` +\n \"See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering\"\n );\n}\n\nexport function createStaticGenerationHeadersContext(\n options: CreateStaticGenerationHeadersContextOptions,\n): HeadersContext {\n const context: HeadersContext = {\n headers: new Headers(),\n cookies: new Map(),\n };\n\n if (options.dynamicConfig === \"force-static\") {\n context.forceStatic = true;\n }\n\n if (options.dynamicConfig === \"error\") {\n context.accessError = new Error(\n options.routeKind === \"route\"\n ? getAppRouteStaticGenerationErrorMessage(options.routePattern)\n : getAppPageStaticGenerationErrorMessage(),\n );\n }\n\n return context;\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"app-static-generation.js","names":[],"sources":["../../src/server/app-static-generation.ts"],"sourcesContent":["import type { HeadersContext } from \"vinext/shims/headers\";\n\ntype AppStaticGenerationRouteKind = \"page\" | \"route\";\n\ntype CreateStaticGenerationHeadersContextOptions = {\n draftModeSecret?: string;\n dynamicConfig?: string;\n routeKind: AppStaticGenerationRouteKind;\n routePattern?: string;\n};\n\nexport function getAppPageStaticGenerationErrorMessage(): string {\n return (\n 'Page with `dynamic = \"error\"` used a dynamic API. ' +\n \"This page was expected to be fully static, but headers(), cookies(), \" +\n \"or searchParams was accessed. Remove the dynamic API usage or change \" +\n 'the dynamic config to \"auto\" or \"force-dynamic\".'\n );\n}\n\nexport function getAppRouteStaticGenerationErrorMessage(\n routePattern?: string,\n expression?: string,\n): string {\n const route = routePattern ?? \"unknown route\";\n const dynamicExpression = expression ?? \"a dynamic request API\";\n return (\n `Route ${route} with \\`dynamic = \"error\"\\` couldn't be rendered statically ` +\n `because it used ${dynamicExpression}. ` +\n \"See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering\"\n );\n}\n\nexport function createStaticGenerationHeadersContext(\n options: CreateStaticGenerationHeadersContextOptions,\n): HeadersContext {\n const context: HeadersContext = {\n headers: new Headers(),\n cookies: new Map(),\n draftModeSecret: options.draftModeSecret,\n };\n\n if (options.dynamicConfig === \"force-static\") {\n context.forceStatic = true;\n }\n\n if (options.dynamicConfig === \"error\") {\n context.accessError = new Error(\n options.routeKind === \"route\"\n ? getAppRouteStaticGenerationErrorMessage(options.routePattern)\n : getAppPageStaticGenerationErrorMessage(),\n );\n }\n\n return context;\n}\n"],"mappings":";AAWA,SAAgB,yCAAiD;CAC/D,OACE;;AAOJ,SAAgB,wCACd,cACA,YACQ;CAGR,OACE,SAHY,gBAAgB,gBAGb,8EAFS,cAAc,wBAGD;;AAKzC,SAAgB,qCACd,SACgB;CAChB,MAAM,UAA0B;EAC9B,SAAS,IAAI,SAAS;EACtB,yBAAS,IAAI,KAAK;EAClB,iBAAiB,QAAQ;EAC1B;CAED,IAAI,QAAQ,kBAAkB,gBAC5B,QAAQ,cAAc;CAGxB,IAAI,QAAQ,kBAAkB,SAC5B,QAAQ,cAAc,IAAI,MACxB,QAAQ,cAAc,UAClB,wCAAwC,QAAQ,aAAa,GAC7D,wCAAwC,CAC7C;CAGH,OAAO"}
|