vinext 0.0.51 → 0.0.52
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/dist/build/precompress.d.ts +7 -7
- package/dist/build/precompress.js +18 -17
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +3 -14
- package/dist/build/prerender.js +40 -40
- package/dist/build/prerender.js.map +1 -1
- package/dist/check.js +4 -0
- package/dist/check.js.map +1 -1
- package/dist/cli-args.d.ts +1 -0
- package/dist/cli-args.js +5 -0
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +47 -0
- package/dist/client/navigation-runtime.js +156 -0
- package/dist/client/navigation-runtime.js.map +1 -0
- package/dist/client/pages-router-link-navigation.d.ts +26 -0
- package/dist/client/pages-router-link-navigation.js +14 -0
- package/dist/client/pages-router-link-navigation.js.map +1 -0
- package/dist/client/vinext-next-data.d.ts +12 -2
- package/dist/client/vinext-next-data.js +50 -1
- package/dist/client/vinext-next-data.js.map +1 -0
- package/dist/cloudflare/kv-cache-handler.js +2 -1
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/config/config-matchers.d.ts +63 -16
- package/dist/config/config-matchers.js +143 -8
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +20 -2
- package/dist/config/next-config.js +11 -1
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +101 -39
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.js +9 -3
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +53 -13
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +1 -0
- package/dist/entries/app-rsc-manifest.js +53 -6
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/app-ssr-entry.d.ts +3 -3
- package/dist/entries/app-ssr-entry.js +4 -4
- package/dist/entries/app-ssr-entry.js.map +1 -1
- package/dist/entries/pages-client-entry.js +18 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +58 -8
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +2 -1
- package/dist/entries/runtime-entry-module.js +9 -3
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +132 -40
- package/dist/index.js.map +1 -1
- package/dist/plugins/css-data-url.d.ts +7 -0
- package/dist/plugins/css-data-url.js +81 -0
- package/dist/plugins/css-data-url.js.map +1 -0
- package/dist/plugins/fonts.js +5 -3
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/middleware-server-only.d.ts +54 -0
- package/dist/plugins/middleware-server-only.js +91 -0
- package/dist/plugins/middleware-server-only.js.map +1 -0
- package/dist/plugins/optimize-imports.js +4 -4
- package/dist/plugins/optimize-imports.js.map +1 -1
- package/dist/plugins/strip-server-exports.js +5 -8
- package/dist/plugins/strip-server-exports.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +20 -1
- package/dist/routing/app-route-graph.js +58 -6
- 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/utils.d.ts +2 -1
- package/dist/routing/utils.js +4 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +139 -37
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-entry.js +293 -149
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-interception-context.d.ts +24 -0
- package/dist/server/app-browser-interception-context.js +32 -0
- package/dist/server/app-browser-interception-context.js.map +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +3 -1
- package/dist/server/app-browser-navigation-controller.js +5 -1
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-rsc-redirect.d.ts +2 -1
- package/dist/server/app-browser-rsc-redirect.js +2 -2
- package/dist/server/app-browser-rsc-redirect.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +18 -1
- package/dist/server/app-browser-state.js +19 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +5 -14
- package/dist/server/app-browser-stream.js +13 -7
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +2 -1
- package/dist/server/app-browser-visible-commit.js +1 -0
- package/dist/server/app-browser-visible-commit.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +10 -5
- package/dist/server/app-elements-wire.js +84 -2
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +3 -2
- package/dist/server/app-elements.js +3 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.js +5 -3
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-middleware.d.ts +13 -0
- package/dist/server/app-middleware.js +3 -1
- package/dist/server/app-middleware.js.map +1 -1
- package/dist/server/app-optimistic-routing.d.ts +54 -0
- package/dist/server/app-optimistic-routing.js +200 -0
- package/dist/server/app-optimistic-routing.js.map +1 -0
- package/dist/server/app-page-cache.d.ts +13 -1
- package/dist/server/app-page-cache.js +61 -6
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +2 -0
- package/dist/server/app-page-dispatch.js +28 -1
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.js +2 -1
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +28 -1
- package/dist/server/app-page-execution.js +89 -4
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.js +21 -2
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-probe.js +1 -1
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +2 -1
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.js +17 -10
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +3 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-static-params.d.ts +2 -1
- package/dist/server/app-prerender-static-params.js +44 -8
- package/dist/server/app-prerender-static-params.js.map +1 -1
- package/dist/server/app-route-handler-cache.d.ts +2 -2
- package/dist/server/app-route-handler-cache.js +3 -2
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +6 -1
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +17 -2
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +5 -4
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-router-entry.js +6 -2
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +9 -1
- package/dist/server/app-rsc-handler.js +32 -14
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-render-mode.d.ts +4 -3
- package/dist/server/app-rsc-render-mode.js +7 -1
- package/dist/server/app-rsc-render-mode.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +4 -1
- package/dist/server/app-rsc-request-normalization.js +4 -1
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
- package/dist/server/app-rsc-response-finalizer.js +10 -3
- package/dist/server/app-rsc-response-finalizer.js.map +1 -1
- package/dist/server/app-rsc-route-matching.js +2 -2
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +56 -55
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +17 -3
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +1 -1
- package/dist/server/artifact-compatibility.js.map +1 -1
- package/dist/server/cache-headers.d.ts +7 -0
- package/dist/server/cache-headers.js +19 -0
- package/dist/server/cache-headers.js.map +1 -0
- package/dist/server/cache-proof.d.ts +49 -3
- package/dist/server/cache-proof.js +78 -22
- package/dist/server/cache-proof.js.map +1 -1
- package/dist/server/client-reuse-manifest.d.ts +99 -0
- package/dist/server/client-reuse-manifest.js +212 -0
- package/dist/server/client-reuse-manifest.js.map +1 -0
- package/dist/server/default-global-error-module.d.ts +20 -0
- package/dist/server/default-global-error-module.js +20 -0
- package/dist/server/default-global-error-module.js.map +1 -0
- package/dist/server/dev-server.d.ts +9 -1
- package/dist/server/dev-server.js +76 -29
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/edge-api-runtime.d.ts +5 -0
- package/dist/server/edge-api-runtime.js +8 -0
- package/dist/server/edge-api-runtime.js.map +1 -0
- package/dist/server/headers.d.ts +18 -1
- package/dist/server/headers.js +18 -1
- package/dist/server/headers.js.map +1 -1
- package/dist/server/http-error-responses.d.ts +16 -1
- package/dist/server/http-error-responses.js +21 -1
- package/dist/server/http-error-responses.js.map +1 -1
- package/dist/server/isr-cache.d.ts +6 -2
- package/dist/server/isr-cache.js +20 -4
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +15 -0
- package/dist/server/middleware-runtime.js +59 -7
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js +4 -2
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/navigation-planner.d.ts +9 -3
- package/dist/server/navigation-planner.js +98 -25
- package/dist/server/navigation-planner.js.map +1 -1
- package/dist/server/navigation-trace.d.ts +2 -1
- package/dist/server/navigation-trace.js +1 -0
- package/dist/server/navigation-trace.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +27 -1
- package/dist/server/pages-api-route.js +24 -3
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-data-route.d.ts +77 -0
- package/dist/server/pages-data-route.js +97 -0
- package/dist/server/pages-data-route.js.map +1 -0
- package/dist/server/pages-i18n.d.ts +51 -1
- package/dist/server/pages-i18n.js +61 -1
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +29 -2
- package/dist/server/pages-page-data.js +31 -17
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +11 -1
- package/dist/server/pages-page-response.js +5 -3
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +13 -15
- package/dist/server/prod-server.js +109 -56
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +11 -2
- package/dist/server/request-pipeline.js +28 -11
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/seed-cache.d.ts +12 -31
- package/dist/server/seed-cache.js +22 -35
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.js +8 -3
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/skip-cache-proof.d.ts +41 -0
- package/dist/server/skip-cache-proof.js +101 -0
- package/dist/server/skip-cache-proof.js.map +1 -0
- package/dist/server/static-file-cache.d.ts +1 -1
- package/dist/server/static-file-cache.js +7 -6
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/client-locale.d.ts +15 -0
- package/dist/shims/client-locale.js +13 -0
- package/dist/shims/client-locale.js.map +1 -0
- package/dist/shims/default-global-error.d.ts +32 -0
- package/dist/shims/default-global-error.js +181 -0
- package/dist/shims/default-global-error.js.map +1 -0
- package/dist/shims/document.d.ts +59 -3
- package/dist/shims/document.js +36 -5
- package/dist/shims/document.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +2 -2
- package/dist/shims/form.js +13 -6
- package/dist/shims/form.js.map +1 -1
- package/dist/shims/link.d.ts +21 -3
- package/dist/shims/link.js +131 -22
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.js +4 -4
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +36 -15
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/og.d.ts +18 -2
- package/dist/shims/og.js +49 -1
- package/dist/shims/og.js.map +1 -0
- package/dist/shims/request-state-types.d.ts +1 -1
- package/dist/shims/root-params.d.ts +3 -1
- package/dist/shims/root-params.js +11 -3
- package/dist/shims/root-params.js.map +1 -1
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +12 -5
- package/dist/shims/router.js +172 -22
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +21 -4
- package/dist/shims/server.js +29 -9
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.js +5 -1
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/url-safety.d.ts +23 -1
- package/dist/shims/url-safety.js +29 -2
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/typegen.d.ts +10 -0
- package/dist/typegen.js +242 -0
- package/dist/typegen.js.map +1 -0
- package/dist/utils/asset-prefix.d.ts +33 -5
- package/dist/utils/asset-prefix.js +39 -6
- package/dist/utils/asset-prefix.js.map +1 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +1 -3
- package/dist/utils/cache-control-metadata.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +2 -1
- package/dist/utils/domain-locale.js +9 -1
- package/dist/utils/domain-locale.js.map +1 -1
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/dist/utils/prerender-output-paths.d.ts +15 -0
- package/dist/utils/prerender-output-paths.js +24 -0
- package/dist/utils/prerender-output-paths.js.map +1 -0
- package/dist/utils/query.d.ts +17 -1
- package/dist/utils/query.js +36 -1
- package/dist/utils/query.js.map +1 -1
- package/dist/utils/record.d.ts +5 -0
- package/dist/utils/record.js +8 -0
- package/dist/utils/record.js.map +1 -0
- package/package.json +11 -3
|
@@ -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 { 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 { createRscEmbedTransform, createTickBufferedTransform } 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 paramsScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_PARAMS__=\" + safeJsonStringify(navContext?.params ?? {}),\n scriptNonce,\n );\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const navScript = createInlineScriptTag(\n \"self.__VINEXT_RSC_NAV__=\" + safeJsonStringify(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 paramsScript +\n navScript +\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 /** 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 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(\"index\");\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 }) 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":";;;;;;;;;;;;;;;;;;;;;AAgDA,MAAM,2BAA2B,+BAA+B;CAC9D,gBAAgB;EACd,OAAO;;CAET,mBAAmB;EACjB,OAAO,WAAW;;CAEpB,eAAe,IAAI,OAAO;EACxB,IAAI,QAAQ,IAAI,aAAa,cAC3B,QAAQ,KAAK,0CAA0C,IAAI,MAAM;;CAGtE,CAAC;AAEF,SAAS,eAAe,OAAuB;CAC7C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KACrC,OAAQ,OAAO,KAAM,MAAM,WAAW,EAAE;CAE1C,QAAQ,SAAS,GAAG,UAAU;;AAGhC,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,iBAAiB,OAAO,OAAO,MAAM;CACzC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAO,OAAO,UAAU,SAAS,KAAK,MAAM;;AAG9C,SAAS,mBAAmB,kBAA8C;CACxE,IAAI,eAAe;CAEnB,KAAK,MAAM,WAAW,kBACpB,IAAI;EACF,gBAAgB,qBACdA,cAAmB,UAAU,MAAM,QAAqB,CACzD;SACK;CAKV,OAAO;;AAGT,SAAS,eAAe,UAAqB,OAAwB;CACnE,IAAI,CAAC,UAAU,OAAO;CAEtB,IAAI,WAAW;CACf,MAAM,YAAY,qBAAqB,MAAM;CAE7C,KAAK,MAAM,OAAO,SAAS,SAAS,EAAE,EACpC,YAAY,yBAAyB,UAAU,SAAS,eAAe,IAAI,CAAC;CAG9E,KAAK,MAAM,WAAW,SAAS,YAAY,EAAE,EAC3C,YAAY,sBAAsB,UAAU,SAAS,eAAe,QAAQ,KAAK,CAAC,oBAAoB,eAAe,QAAQ,KAAK,CAAC;CAGrI,IAAI,SAAS,UAAU,SAAS,OAAO,SAAS,GAC9C,YAAY,2BAA2B,UAAU,GAAG,SAAS,OAAO,KAAK,KAAK,CAAC;CAGjF,OAAO;;;;;;;;;;;;;;;;;AAkBT,SAAS,0BAA0B,wBAAqD;CACtF,IAAI,CAAC,wBAAwB,OAAO,KAAA;CAKpC,OADc,uBAAuB,MAAM,6BAC/B,GAAG,MAAM,KAAA;;AAGvB,SAAS,uBAAuB,oBAA6B,OAAwB;CACnF,IAAI,CAAC,oBAAoB,OAAO;CAChC,OAAO,4BAA4B,qBAAqB,MAAM,CAAC,SAAS,eAAe,mBAAmB,CAAC;;AAG7G,SAAS,uBACP,YACA,oBACA,WACA,cACA,UACA,aACQ;CACR,MAAM,eAAe,sBACnB,gCAAgC,kBAAkB,YAAY,UAAU,EAAE,CAAC,EAC3E,YACD;CAKD,MAAM,YAAY,sBAChB,6BAA6B,kBAAkB;EAJ/C,UAAU,YAAY,YAAY;EAClC,cAAc,YAAY,eAAe,CAAC,GAAG,WAAW,aAAa,SAAS,CAAC,GAAG,EAAE;EAG3B,CAAC,EAC1D,YACD;CACD,MAAM,kBACJ,cAAc,OACV,KACA,sBACE,UAAU,kBAAkB,sBAAsB,GAAG,OAAO,kBAAkB,UAAU,EACxF,YACD;CAEP,OACE,eACA,YACA,kBACA,uBAAuB,oBAAoB,YAAY,GACvD,eACA;;AAIJ,eAAsB,UACpB,WACA,YACA,UACA,SAeqC;CACrC,OAAO,yBAAyB,YAAY;EAC1C,MAAM,yBAAyB,SAAS;EAExC,IAAI,YACF,qBAAqB,WAAW;EAGlC,yBAAyB;EAEzB,MAAM,gBAAsB;GAC1B,qBAAqB,KAAK;GAC1B,yBAAyB;;EAG3B,IAAI;GAIF,IAAI;GACJ,IAAI;GAEJ,IAAI,SAAS,YAAY;IACvB,YAAY;IACZ,WAAW,wBAAwB,QAAQ,YAAY,SAAS,YAAY;IAC5E,IAAI,QAAQ,oBACV,QAAQ,mBAAmB,QAAQ,SAAS,cAAc;UAEvD;IACL,MAAM,CAAC,IAAI,MAAM,UAAU,KAAK;IAChC,YAAY;IACZ,WAAW,wBAAwB,IAAI,SAAS,YAAY;;GAG9D,IAAI,aAAkD;GAEtD,SAAS,mBAA8B;IACrC,IAAI,CAAC,YACH,aAAa,yBAA0C,UAAU;IAEnE,MAAM,eAAe,IAAI,WAAW;IACpC,MAAM,WAAW,gBAAgB,OAAO,aAAa;IACrD,MAAM,WAAW,gBAAgB,aAAa,SAAS;IACvD,OAAOA,cACL,gBAAgB,UAChB,EAAE,OAAO,UAAU,EACnBA,cAAmB,MAAM,EAAE,IAAI,SAAS,SAAS,CAAC,CACnD;;GAGH,MAAM,oBAAoBA,cAAmB,iBAAiB;GAC9D,MAAM,OAAO,mBACTA,cACE,iBAAiB,UACjB,EAAE,OAAO,mBAAmB,EAC5B,kBACD,GACD;GAQJ,MAAM,UAAU,gBAPA,4BACZA,cACE,0BAA0B,UAC1B,EAAE,OAAO,uBAAuB,EAChC,KACD,GACD,MACqC,SAAS,YAAY;GAmB9D,MAAM,qBAAqB,0BAA0B,MADhB,OAAO,KAAK,QAAQ,2BAA2B,QAAQ,CAChB;GAC5E,MAAM,oBAAoB,2BAA2B,EACnD,UAAU,SAAS,UACpB,CAAC;GAEF,MAAM,aAAa,MAAM,uBAAuB,SAAS;IAgBvD,kBAAkB,qBAAqB,CAAC,mBAAmB,GAAG,KAAA;IAC9D,WAAW,SAAS,aAAa;IACjC,OAAO,SAAS;IAChB,QAAQ,OAAO;KACb,kBAAkB,QAAQ,MAAM;KAEhC,IAAI,SAAS,OAAO,UAAU,YAAY,YAAY,OACpD,OAAO,OAAO,MAAM,OAAO;KAG7B,IAAI,QAAQ,IAAI,aAAa,gBAAgB,OAG3C,OAAO,eAFS,gBAAgB,MAEH,IADf,iBAAiB,QAAS,MAAM,SAAS,KAAM,IACvB;;IAK3C,CAAC;GAMF,IAAI,SAAS,oBAAoB,MAC/B,MAAM,WAAW;GAGnB,MAAM,WAAW,eAAe,UAAU,SAAS,YAAY;GAC/D,IAAI,oBAAoB;GACxB,MAAM,wBAAgC;IACpC,MAAM,eAAe,mBAAmB,0BAA0B,CAAC;IACnE,MAAM,gBAAgB,kBAAkB,OAAO;IAC/C,IAAI,mBAAmB,OAAO,eAAe;IAE7C,oBAAoB;IACpB,OAAO,uBACL,YACA,oBACA,SAAS,aAAa,MACtB,eAAe,eACf,UACA,SAAS,YACV;;GAGH,OAAO,yBACL,WAAW,YAAY,4BAA4B,UAAU,gBAAgB,CAAC,EAC9E,QACD;WACM,OAAO;GACd,SAAS;GACT,MAAM;;GAER;;AAGJ,IAAA,wBAAe,EACb,MAAM,MAAM,SAAqC;CAI/C,IAAI,qBAAqB,IAHT,IAAI,QAAQ,IAGA,CAAC,SAAS,EACpC,OAAO,kBAAkB;CAM3B,MAAM,SAAS,OAAM,MAHG,OAAO,KAAK,QAAQ,WAEzC,OAAO,QAAQ,EACa,QAAQ,QAAQ;CAE/C,IAAI,kBAAkB,UACpB,OAAO;CAGT,IAAI,UAAU,MACZ,OAAO,kBAAkB;CAG3B,OAAO,IAAI,SAAS,OAAO,OAAO,EAAE,EAAE,QAAQ,KAAK,CAAC;GAEvD"}
|
|
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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"}
|
|
@@ -5,6 +5,11 @@ type RscEmbedTransform = {
|
|
|
5
5
|
getRawBuffer(): Promise<ArrayBuffer>;
|
|
6
6
|
};
|
|
7
7
|
type HtmlInsertion = string | (() => string);
|
|
8
|
+
declare function navigationRuntimeRscBootstrapExpression(): string;
|
|
9
|
+
declare function createNavigationRuntimeRscMetadataScript(params: Record<string, string | string[]>, nav: {
|
|
10
|
+
pathname: string;
|
|
11
|
+
searchParams: [string, string][];
|
|
12
|
+
}): string;
|
|
8
13
|
/**
|
|
9
14
|
* Fix invalid preload "as" values in RSC Flight hint lines before they reach
|
|
10
15
|
* the client. React Flight emits HL hints with as="stylesheet" for CSS, but
|
|
@@ -28,5 +33,5 @@ declare function fixPreloadAs(html: string): string;
|
|
|
28
33
|
*/
|
|
29
34
|
declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?: HtmlInsertion): TransformStream<Uint8Array, Uint8Array>;
|
|
30
35
|
//#endregion
|
|
31
|
-
export { createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs };
|
|
36
|
+
export { createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs, navigationRuntimeRscBootstrapExpression };
|
|
32
37
|
//# sourceMappingURL=app-ssr-stream.d.ts.map
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import { NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION } from "../client/navigation-runtime.js";
|
|
1
2
|
import { createInlineScriptTag, safeJsonStringify } from "./html.js";
|
|
2
3
|
import { bytesToBase64, concatUint8Arrays } from "./app-rsc-embedded-chunks.js";
|
|
3
4
|
//#region src/server/app-ssr-stream.ts
|
|
5
|
+
const NAVIGATION_RUNTIME_REFERENCE = `self[Symbol.for(${safeJsonStringify(NAVIGATION_RUNTIME_SYMBOL_DESCRIPTION)})]`;
|
|
6
|
+
function navigationRuntimeRscBootstrapExpression() {
|
|
7
|
+
return `((${NAVIGATION_RUNTIME_REFERENCE}??={bootstrap:{routeManifest:null},functions:{}}).bootstrap.rsc??={rsc:[]})`;
|
|
8
|
+
}
|
|
9
|
+
function createNavigationRuntimeRscMetadataScript(params, nav) {
|
|
10
|
+
return "Object.assign(" + navigationRuntimeRscBootstrapExpression() + ",{params:" + safeJsonStringify(params) + ",nav:" + safeJsonStringify(nav) + "})";
|
|
11
|
+
}
|
|
12
|
+
function createNavigationRuntimeRscChunkScript(chunk) {
|
|
13
|
+
return navigationRuntimeRscBootstrapExpression() + ".rsc.push(" + safeJsonStringify(chunk) + ")";
|
|
14
|
+
}
|
|
15
|
+
function createNavigationRuntimeRscDoneScript() {
|
|
16
|
+
return navigationRuntimeRscBootstrapExpression() + ".done=true";
|
|
17
|
+
}
|
|
4
18
|
/**
|
|
5
19
|
* Fix invalid preload "as" values in RSC Flight hint lines before they reach
|
|
6
20
|
* the client. React Flight emits HL hints with as="stylesheet" for CSS, but
|
|
@@ -47,13 +61,13 @@ function createRscEmbedTransform(embedStream, scriptNonce) {
|
|
|
47
61
|
const chunks = pendingChunks;
|
|
48
62
|
pendingChunks = [];
|
|
49
63
|
let scripts = "";
|
|
50
|
-
for (const chunk of chunks) scripts += createInlineScriptTag(
|
|
64
|
+
for (const chunk of chunks) scripts += createInlineScriptTag(createNavigationRuntimeRscChunkScript(chunk), scriptNonce);
|
|
51
65
|
return scripts;
|
|
52
66
|
},
|
|
53
67
|
async finalize() {
|
|
54
68
|
await pumpPromise;
|
|
55
69
|
let scripts = this.flush();
|
|
56
|
-
scripts += createInlineScriptTag(
|
|
70
|
+
scripts += createInlineScriptTag(createNavigationRuntimeRscDoneScript(), scriptNonce);
|
|
57
71
|
return scripts;
|
|
58
72
|
},
|
|
59
73
|
async getRawBuffer() {
|
|
@@ -135,6 +149,6 @@ function createTickBufferedTransform(rscEmbed, injectHTML = "") {
|
|
|
135
149
|
});
|
|
136
150
|
}
|
|
137
151
|
//#endregion
|
|
138
|
-
export { createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs };
|
|
152
|
+
export { createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs, navigationRuntimeRscBootstrapExpression };
|
|
139
153
|
|
|
140
154
|
//# sourceMappingURL=app-ssr-stream.js.map
|
|
@@ -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\";\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\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(\n \"self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push(\" +\n safeJsonStringify(chunk) +\n \")\",\n scriptNonce,\n );\n }\n return scripts;\n },\n\n async finalize(): Promise<string> {\n await pumpPromise;\n let scripts = this.flush();\n scripts += createInlineScriptTag(\"self.__VINEXT_RSC_DONE__=true\", 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":";;;;;;;;AAsBA,SAAgB,eAAe,MAAsB;CACnD,OAAO,KAAK,QAAQ,qCAAqC,iBAAe;;;;;;AAO1E,SAAgB,wBACd,aACA,aACmB;CACnB,MAAM,SAAS,YAAY,WAAW;CACtC,IAAI,gBAAoC,EAAE;CAC1C,MAAM,YAA0B,EAAE;CAClC,IAAI,UAAU;CAEd,eAAe,aAA4B;EACzC,IAAI,SAAS;EACb,UAAU;EACV,IAAI;GACF,OAAO,MAAM;IACX,MAAM,SAAS,MAAM,OAAO,MAAM;IAClC,IAAI,OAAO,MAAM;IAGjB,UAAU,KAAK,OAAO,MAAM;IAC5B,IAAI;KAEF,MAAM,OAAO,IADO,YAAY,SAAS,EAAE,OAAO,MAAM,CACpC,CAAC,OAAO,OAAO,MAAM;KAIzC,cAAc,KAAK,eAAe,KAAK,CAAC;YAClC;KACN,cAAc,KAAK,CAAA,GAA4B,cAAc,OAAO,MAAM,CAAC,CAAC;;;WAGzE,OAAO;GACd,IAAI,QAAQ,IAAI,aAAa,cAC3B,QAAQ,KAAK,yCAAyC,MAAM;GAE9D,MAAM;YACE;GACR,UAAU;;;CAId,MAAM,cAAc,YAAY;CAEhC,OAAO;EACL,QAAgB;GACd,IAAI,cAAc,WAAW,GAAG,OAAO;GAEvC,MAAM,SAAS;GACf,gBAAgB,EAAE;GAElB,IAAI,UAAU;GACd,KAAK,MAAM,SAAS,QAClB,WAAW,sBACT,+FACE,kBAAkB,MAAM,GACxB,KACF,YACD;GAEH,OAAO;;EAGT,MAAM,WAA4B;GAChC,MAAM;GACN,IAAI,UAAU,KAAK,OAAO;GAC1B,WAAW,sBAAsB,iCAAiC,YAAY;GAC9E,OAAO;;EAGT,MAAM,eAAqC;GACzC,MAAM;GACN,MAAM,SAAS,kBAAkB,UAAU;GAC3C,UAAU,SAAS;GACnB,OAAO,OAAO;;EAEjB;;;;;;;AAQH,SAAgB,aAAa,MAAsB;CACjD,OAAO,KAAK,QAAQ,yCAAyC,QAC3D,IAAI,QAAQ,sBAAoB,gBAAc,CAC/C;;;;;;AAOH,SAAgB,4BACd,UACA,aAA4B,IACa;CACzC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,kBAAkB,OAAO,eAAe;CAC9C,IAAI,WAAW;CACf,IAAI,WAAqB,EAAE;CAC3B,IAAI,YAAkD;CACtD,MAAM,sBACJ,OAAO,eAAe,aAAa,YAAY,GAAG;CACpD,MAAM,iBAAiB,eAAmE;EACxF,MAAM,YAAY,eAAe;EACjC,IAAI,WACF,WAAW,QAAQ,QAAQ,OAAO,UAAU,CAAC;;CAIjD,MAAM,iBAAiB,eAAmE;EACxF,IAAI,SAAS,WAAW,GAAG;EAE3B,IAAI,YAAY,iBAGd,cAAc,WAAW;EAG3B,KAAK,MAAM,SAAS,UAAU;GAC5B,IAAI,CAAC,UAAU;IACb,MAAM,UAAU,MAAM,QAAQ,UAAU;IACxC,IAAI,YAAY,IAAI;KAClB,MAAM,SAAS,MAAM,MAAM,GAAG,QAAQ;KACtC,MAAM,QAAQ,MAAM,MAAM,QAAQ;KAClC,WAAW,QAAQ,QAAQ,OAAO,SAAS,eAAe,GAAG,MAAM,CAAC;KACpE,WAAW;KACX;;;GAGJ,WAAW,QAAQ,QAAQ,OAAO,MAAM,CAAC;;EAE3C,WAAW,EAAE;;CAGf,OAAO,IAAI,gBAAwC;EACjD,UAAU,OAAO,YAAY;GAC3B,SAAS,KAAK,aAAa,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC,CAAC;GAEpE,IAAI,cAAc,MAAM;GAExB,YAAY,iBAAiB;IAC3B,IAAI;KACF,cAAc,WAAW;KAEzB,MAAM,aAAa,SAAS,OAAO;KACnC,IAAI,YACF,WAAW,QAAQ,QAAQ,OAAO,WAAW,CAAC;YAE1C;IAMR,YAAY;MACX,EAAE;;EAGP,MAAM,MAAM,YAAY;GACtB,IAAI,cAAc,MAAM;IACtB,aAAa,UAAU;IACvB,YAAY;;GAGd,cAAc,WAAW;GAEzB,IAAI,CAAC,UAAU;IACb,cAAc,WAAW;IACzB,WAAW;UACN,IAAI,iBACT,cAAc,WAAW;GAG3B,MAAM,eAAe,MAAM,SAAS,UAAU;GAC9C,IAAI,cACF,WAAW,QAAQ,QAAQ,OAAO,aAAa,CAAC;;EAGrD,CAAC"}
|
|
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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"}
|
|
@@ -50,5 +50,5 @@ declare function createArtifactCompatibilityGraphVersion(input: ArtifactCompatib
|
|
|
50
50
|
declare function parseArtifactCompatibilityEnvelope(value: unknown): ArtifactCompatibilityEnvelope | null;
|
|
51
51
|
declare function evaluateArtifactCompatibility(current: ArtifactCompatibilityEnvelope, candidate: ArtifactCompatibilityEnvelope, options?: ArtifactCompatibilityEvaluationOptions): ArtifactCompatibilityDecision;
|
|
52
52
|
//#endregion
|
|
53
|
-
export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, ArtifactCompatibilityEnvelope, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
|
|
53
|
+
export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, ArtifactCompatibilityEnvelope, ArtifactCompatibilityEvaluationOptions, ArtifactCompatibilityMap, ArtifactCompatibilitySet, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
|
|
54
54
|
//# sourceMappingURL=artifact-compatibility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-compatibility.js","names":[],"sources":["../../src/server/artifact-compatibility.ts"],"sourcesContent":["import { fnv1a64 } from \"../utils/hash.js\";\n\nexport const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;\n\n// These versions describe separate protocol layers. For example, a future\n// rolling deploy can bump the flat AppElements row shape while keeping the\n// envelope object and serialized RSC transport version stable.\nexport const APP_ELEMENTS_SCHEMA_VERSION = 1;\nexport const RSC_PAYLOAD_SCHEMA_VERSION = 1;\n\nexport type ArtifactCompatibilityEnvelope = Readonly<{\n schemaVersion: typeof ARTIFACT_COMPATIBILITY_SCHEMA_VERSION;\n graphVersion: string | null;\n deploymentVersion: string | null;\n appElementsSchemaVersion: typeof APP_ELEMENTS_SCHEMA_VERSION;\n rscPayloadSchemaVersion: typeof RSC_PAYLOAD_SCHEMA_VERSION;\n rootBoundaryId: string | null;\n renderEpoch: string | null;\n}>;\n\ntype ArtifactCompatibilityEnvelopeInput = Readonly<{\n graphVersion?: string | null;\n deploymentVersion?: string | null;\n rootBoundaryId?: string | null;\n renderEpoch?: string | null;\n}>;\n\ntype ArtifactCompatibilitySet = readonly [string, string, ...string[]];\n\ntype ArtifactCompatibilityMap = Readonly<{\n graphVersions?: readonly ArtifactCompatibilitySet[];\n deploymentVersions?: readonly ArtifactCompatibilitySet[];\n rootBoundaryIds?: readonly ArtifactCompatibilitySet[];\n renderEpochs?: readonly ArtifactCompatibilitySet[];\n}>;\n\ntype ArtifactCompatibilityEvaluationOptions = Readonly<{\n compatibilityMap?: ArtifactCompatibilityMap;\n}>;\n\ntype ArtifactCompatibilityFallback = \"renderFresh\";\n\ntype ArtifactCompatibilityUnknownReason =\n | \"graphVersionUnknown\"\n | \"deploymentVersionUnknown\"\n | \"rootBoundaryIdUnknown\"\n | \"renderEpochUnknown\";\n\ntype ArtifactCompatibilityIncompatibleReason =\n | \"appElementsSchemaVersionMismatch\"\n | \"deploymentVersionNotDeclaredCompatible\"\n | \"deploymentVersionMismatch\"\n | \"graphVersionNotDeclaredCompatible\"\n | \"graphVersionMismatch\"\n | \"renderEpochNotDeclaredCompatible\"\n | \"renderEpochMismatch\"\n | \"rootBoundaryIdNotDeclaredCompatible\"\n | \"rootBoundaryIdMismatch\"\n | \"rscPayloadSchemaVersionMismatch\"\n | \"schemaVersionMismatch\";\n\ntype ArtifactCompatibilityDecision = Readonly<\n | { kind: \"compatible\" }\n | {\n kind: \"unknown\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityUnknownReason;\n }\n | {\n kind: \"incompatible\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityIncompatibleReason;\n }\n>;\n\ntype ArtifactCompatibilityGraphVersionInput = Readonly<{\n routePattern: string;\n rootBoundaryId: string | null;\n}>;\n\nexport function createArtifactCompatibilityEnvelope(\n input: ArtifactCompatibilityEnvelopeInput = {},\n): ArtifactCompatibilityEnvelope {\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: input.graphVersion ?? null,\n deploymentVersion: input.deploymentVersion ?? null,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: input.rootBoundaryId ?? null,\n renderEpoch: input.renderEpoch ?? null,\n };\n}\n\nexport function createArtifactCompatibilityGraphVersion(\n input: ArtifactCompatibilityGraphVersionInput,\n): string {\n const fingerprint = fnv1a64(JSON.stringify([input.routePattern, input.rootBoundaryId]));\n return `app-route-graph:${fingerprint}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStringOrNull(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction hasCurrentSchemaVersions(record: Readonly<Record<string, unknown>>): boolean {\n return (\n record.schemaVersion === ARTIFACT_COMPATIBILITY_SCHEMA_VERSION &&\n record.appElementsSchemaVersion === APP_ELEMENTS_SCHEMA_VERSION &&\n record.rscPayloadSchemaVersion === RSC_PAYLOAD_SCHEMA_VERSION\n );\n}\n\nexport function parseArtifactCompatibilityEnvelope(\n value: unknown,\n): ArtifactCompatibilityEnvelope | null {\n if (!isRecord(value)) return null;\n // The Wave01 skeleton intentionally collapses version mismatch and malformed\n // metadata into \"not current\". Cache/skip callers must split those cases\n // before treating unknown compatibility as anything other than a miss/reject.\n if (!hasCurrentSchemaVersions(value)) return null;\n if (!isStringOrNull(value.graphVersion)) return null;\n if (!isStringOrNull(value.deploymentVersion)) return null;\n if (!isStringOrNull(value.rootBoundaryId)) return null;\n if (!isStringOrNull(value.renderEpoch)) return null;\n\n // This parser intentionally returns a normalized current-version proof. A\n // future-compatible reader should introduce a separate parsed type instead of\n // widening this Wave01 envelope after the current-version checks above.\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: value.graphVersion,\n deploymentVersion: value.deploymentVersion,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: value.rootBoundaryId,\n renderEpoch: value.renderEpoch,\n };\n}\n\nfunction incompatible(\n reason: ArtifactCompatibilityIncompatibleReason,\n): ArtifactCompatibilityDecision {\n return { kind: \"incompatible\", fallback: \"renderFresh\", reason };\n}\n\nfunction unknown(reason: ArtifactCompatibilityUnknownReason): ArtifactCompatibilityDecision {\n return { kind: \"unknown\", fallback: \"renderFresh\", reason };\n}\n\nfunction compareKnownField(\n currentValue: string | null,\n candidateValue: string | null,\n unknownReason: ArtifactCompatibilityUnknownReason,\n mismatchReason: ArtifactCompatibilityIncompatibleReason,\n notDeclaredCompatibleReason: ArtifactCompatibilityIncompatibleReason,\n compatibilitySets: readonly ArtifactCompatibilitySet[] | undefined,\n): ArtifactCompatibilityDecision | null {\n if (currentValue === null || candidateValue === null) {\n return unknown(unknownReason);\n }\n if (currentValue === candidateValue) {\n return null;\n }\n if (compatibilitySets === undefined) {\n return incompatible(mismatchReason);\n }\n return isDeclaredCompatible(currentValue, candidateValue, compatibilitySets)\n ? null\n : incompatible(notDeclaredCompatibleReason);\n}\n\nfunction isDeclaredCompatible(\n currentValue: string,\n candidateValue: string,\n compatibilitySets: readonly ArtifactCompatibilitySet[],\n): boolean {\n // Compatibility is intentionally scoped to one declared set. Overlapping\n // pair sets like [a,b] and [b,c] must not silently make a compatible with c.\n return compatibilitySets.some(\n (compatibilitySet) =>\n compatibilitySet.includes(currentValue) && compatibilitySet.includes(candidateValue),\n );\n}\n\nexport function evaluateArtifactCompatibility(\n current: ArtifactCompatibilityEnvelope,\n candidate: ArtifactCompatibilityEnvelope,\n options: ArtifactCompatibilityEvaluationOptions = {},\n): ArtifactCompatibilityDecision {\n // This remains a proof evaluator: mismatched fields are compatible only when\n // the current build's compatibility map explicitly declares that relationship.\n if (current.schemaVersion !== candidate.schemaVersion) {\n return incompatible(\"schemaVersionMismatch\");\n }\n if (current.appElementsSchemaVersion !== candidate.appElementsSchemaVersion) {\n return incompatible(\"appElementsSchemaVersionMismatch\");\n }\n if (current.rscPayloadSchemaVersion !== candidate.rscPayloadSchemaVersion) {\n return incompatible(\"rscPayloadSchemaVersionMismatch\");\n }\n\n const graphDecision = compareKnownField(\n current.graphVersion,\n candidate.graphVersion,\n \"graphVersionUnknown\",\n \"graphVersionMismatch\",\n \"graphVersionNotDeclaredCompatible\",\n options.compatibilityMap?.graphVersions,\n );\n if (graphDecision) return graphDecision;\n\n const deploymentDecision = compareKnownField(\n current.deploymentVersion,\n candidate.deploymentVersion,\n \"deploymentVersionUnknown\",\n \"deploymentVersionMismatch\",\n \"deploymentVersionNotDeclaredCompatible\",\n options.compatibilityMap?.deploymentVersions,\n );\n if (deploymentDecision) return deploymentDecision;\n\n const rootBoundaryDecision = compareKnownField(\n current.rootBoundaryId,\n candidate.rootBoundaryId,\n \"rootBoundaryIdUnknown\",\n \"rootBoundaryIdMismatch\",\n \"rootBoundaryIdNotDeclaredCompatible\",\n options.compatibilityMap?.rootBoundaryIds,\n );\n if (rootBoundaryDecision) return rootBoundaryDecision;\n\n const renderEpochDecision = compareKnownField(\n current.renderEpoch,\n candidate.renderEpoch,\n \"renderEpochUnknown\",\n \"renderEpochMismatch\",\n \"renderEpochNotDeclaredCompatible\",\n options.compatibilityMap?.renderEpochs,\n );\n if (renderEpochDecision) return renderEpochDecision;\n\n return { kind: \"compatible\" };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"artifact-compatibility.js","names":[],"sources":["../../src/server/artifact-compatibility.ts"],"sourcesContent":["import { fnv1a64 } from \"../utils/hash.js\";\n\nexport const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;\n\n// These versions describe separate protocol layers. For example, a future\n// rolling deploy can bump the flat AppElements row shape while keeping the\n// envelope object and serialized RSC transport version stable.\nexport const APP_ELEMENTS_SCHEMA_VERSION = 1;\nexport const RSC_PAYLOAD_SCHEMA_VERSION = 1;\n\nexport type ArtifactCompatibilityEnvelope = Readonly<{\n schemaVersion: typeof ARTIFACT_COMPATIBILITY_SCHEMA_VERSION;\n graphVersion: string | null;\n deploymentVersion: string | null;\n appElementsSchemaVersion: typeof APP_ELEMENTS_SCHEMA_VERSION;\n rscPayloadSchemaVersion: typeof RSC_PAYLOAD_SCHEMA_VERSION;\n rootBoundaryId: string | null;\n renderEpoch: string | null;\n}>;\n\ntype ArtifactCompatibilityEnvelopeInput = Readonly<{\n graphVersion?: string | null;\n deploymentVersion?: string | null;\n rootBoundaryId?: string | null;\n renderEpoch?: string | null;\n}>;\n\nexport type ArtifactCompatibilitySet = readonly [string, string, ...string[]];\n\nexport type ArtifactCompatibilityMap = Readonly<{\n graphVersions?: readonly ArtifactCompatibilitySet[];\n deploymentVersions?: readonly ArtifactCompatibilitySet[];\n rootBoundaryIds?: readonly ArtifactCompatibilitySet[];\n renderEpochs?: readonly ArtifactCompatibilitySet[];\n}>;\n\nexport type ArtifactCompatibilityEvaluationOptions = Readonly<{\n compatibilityMap?: ArtifactCompatibilityMap;\n}>;\n\ntype ArtifactCompatibilityFallback = \"renderFresh\";\n\ntype ArtifactCompatibilityUnknownReason =\n | \"graphVersionUnknown\"\n | \"deploymentVersionUnknown\"\n | \"rootBoundaryIdUnknown\"\n | \"renderEpochUnknown\";\n\ntype ArtifactCompatibilityIncompatibleReason =\n | \"appElementsSchemaVersionMismatch\"\n | \"deploymentVersionNotDeclaredCompatible\"\n | \"deploymentVersionMismatch\"\n | \"graphVersionNotDeclaredCompatible\"\n | \"graphVersionMismatch\"\n | \"renderEpochNotDeclaredCompatible\"\n | \"renderEpochMismatch\"\n | \"rootBoundaryIdNotDeclaredCompatible\"\n | \"rootBoundaryIdMismatch\"\n | \"rscPayloadSchemaVersionMismatch\"\n | \"schemaVersionMismatch\";\n\ntype ArtifactCompatibilityDecision = Readonly<\n | { kind: \"compatible\" }\n | {\n kind: \"unknown\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityUnknownReason;\n }\n | {\n kind: \"incompatible\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityIncompatibleReason;\n }\n>;\n\ntype ArtifactCompatibilityGraphVersionInput = Readonly<{\n routePattern: string;\n rootBoundaryId: string | null;\n}>;\n\nexport function createArtifactCompatibilityEnvelope(\n input: ArtifactCompatibilityEnvelopeInput = {},\n): ArtifactCompatibilityEnvelope {\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: input.graphVersion ?? null,\n deploymentVersion: input.deploymentVersion ?? null,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: input.rootBoundaryId ?? null,\n renderEpoch: input.renderEpoch ?? null,\n };\n}\n\nexport function createArtifactCompatibilityGraphVersion(\n input: ArtifactCompatibilityGraphVersionInput,\n): string {\n const fingerprint = fnv1a64(JSON.stringify([input.routePattern, input.rootBoundaryId]));\n return `app-route-graph:${fingerprint}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStringOrNull(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction hasCurrentSchemaVersions(record: Readonly<Record<string, unknown>>): boolean {\n return (\n record.schemaVersion === ARTIFACT_COMPATIBILITY_SCHEMA_VERSION &&\n record.appElementsSchemaVersion === APP_ELEMENTS_SCHEMA_VERSION &&\n record.rscPayloadSchemaVersion === RSC_PAYLOAD_SCHEMA_VERSION\n );\n}\n\nexport function parseArtifactCompatibilityEnvelope(\n value: unknown,\n): ArtifactCompatibilityEnvelope | null {\n if (!isRecord(value)) return null;\n // The Wave01 skeleton intentionally collapses version mismatch and malformed\n // metadata into \"not current\". Cache/skip callers must split those cases\n // before treating unknown compatibility as anything other than a miss/reject.\n if (!hasCurrentSchemaVersions(value)) return null;\n if (!isStringOrNull(value.graphVersion)) return null;\n if (!isStringOrNull(value.deploymentVersion)) return null;\n if (!isStringOrNull(value.rootBoundaryId)) return null;\n if (!isStringOrNull(value.renderEpoch)) return null;\n\n // This parser intentionally returns a normalized current-version proof. A\n // future-compatible reader should introduce a separate parsed type instead of\n // widening this Wave01 envelope after the current-version checks above.\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: value.graphVersion,\n deploymentVersion: value.deploymentVersion,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: value.rootBoundaryId,\n renderEpoch: value.renderEpoch,\n };\n}\n\nfunction incompatible(\n reason: ArtifactCompatibilityIncompatibleReason,\n): ArtifactCompatibilityDecision {\n return { kind: \"incompatible\", fallback: \"renderFresh\", reason };\n}\n\nfunction unknown(reason: ArtifactCompatibilityUnknownReason): ArtifactCompatibilityDecision {\n return { kind: \"unknown\", fallback: \"renderFresh\", reason };\n}\n\nfunction compareKnownField(\n currentValue: string | null,\n candidateValue: string | null,\n unknownReason: ArtifactCompatibilityUnknownReason,\n mismatchReason: ArtifactCompatibilityIncompatibleReason,\n notDeclaredCompatibleReason: ArtifactCompatibilityIncompatibleReason,\n compatibilitySets: readonly ArtifactCompatibilitySet[] | undefined,\n): ArtifactCompatibilityDecision | null {\n if (currentValue === null || candidateValue === null) {\n return unknown(unknownReason);\n }\n if (currentValue === candidateValue) {\n return null;\n }\n if (compatibilitySets === undefined) {\n return incompatible(mismatchReason);\n }\n return isDeclaredCompatible(currentValue, candidateValue, compatibilitySets)\n ? null\n : incompatible(notDeclaredCompatibleReason);\n}\n\nfunction isDeclaredCompatible(\n currentValue: string,\n candidateValue: string,\n compatibilitySets: readonly ArtifactCompatibilitySet[],\n): boolean {\n // Compatibility is intentionally scoped to one declared set. Overlapping\n // pair sets like [a,b] and [b,c] must not silently make a compatible with c.\n return compatibilitySets.some(\n (compatibilitySet) =>\n compatibilitySet.includes(currentValue) && compatibilitySet.includes(candidateValue),\n );\n}\n\nexport function evaluateArtifactCompatibility(\n current: ArtifactCompatibilityEnvelope,\n candidate: ArtifactCompatibilityEnvelope,\n options: ArtifactCompatibilityEvaluationOptions = {},\n): ArtifactCompatibilityDecision {\n // This remains a proof evaluator: mismatched fields are compatible only when\n // the current build's compatibility map explicitly declares that relationship.\n if (current.schemaVersion !== candidate.schemaVersion) {\n return incompatible(\"schemaVersionMismatch\");\n }\n if (current.appElementsSchemaVersion !== candidate.appElementsSchemaVersion) {\n return incompatible(\"appElementsSchemaVersionMismatch\");\n }\n if (current.rscPayloadSchemaVersion !== candidate.rscPayloadSchemaVersion) {\n return incompatible(\"rscPayloadSchemaVersionMismatch\");\n }\n\n const graphDecision = compareKnownField(\n current.graphVersion,\n candidate.graphVersion,\n \"graphVersionUnknown\",\n \"graphVersionMismatch\",\n \"graphVersionNotDeclaredCompatible\",\n options.compatibilityMap?.graphVersions,\n );\n if (graphDecision) return graphDecision;\n\n const deploymentDecision = compareKnownField(\n current.deploymentVersion,\n candidate.deploymentVersion,\n \"deploymentVersionUnknown\",\n \"deploymentVersionMismatch\",\n \"deploymentVersionNotDeclaredCompatible\",\n options.compatibilityMap?.deploymentVersions,\n );\n if (deploymentDecision) return deploymentDecision;\n\n const rootBoundaryDecision = compareKnownField(\n current.rootBoundaryId,\n candidate.rootBoundaryId,\n \"rootBoundaryIdUnknown\",\n \"rootBoundaryIdMismatch\",\n \"rootBoundaryIdNotDeclaredCompatible\",\n options.compatibilityMap?.rootBoundaryIds,\n );\n if (rootBoundaryDecision) return rootBoundaryDecision;\n\n const renderEpochDecision = compareKnownField(\n current.renderEpoch,\n candidate.renderEpoch,\n \"renderEpochUnknown\",\n \"renderEpochMismatch\",\n \"renderEpochNotDeclaredCompatible\",\n options.compatibilityMap?.renderEpochs,\n );\n if (renderEpochDecision) return renderEpochDecision;\n\n return { kind: \"compatible\" };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/server/cache-headers.d.ts
|
|
2
|
+
type VinextCacheState = "HIT" | "MISS" | "STALE" | "STATIC";
|
|
3
|
+
declare function setCacheStateHeaders(headers: Headers, cacheState: VinextCacheState): void;
|
|
4
|
+
declare function buildCacheStateHeaders(cacheState: VinextCacheState): Record<string, string>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { buildCacheStateHeaders, setCacheStateHeaders };
|
|
7
|
+
//# sourceMappingURL=cache-headers.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NEXTJS_CACHE_HEADER, VINEXT_CACHE_HEADER } from "./headers.js";
|
|
2
|
+
//#region src/server/cache-headers.ts
|
|
3
|
+
function toNextJsCacheState(cacheState) {
|
|
4
|
+
return cacheState === "STATIC" ? "HIT" : cacheState;
|
|
5
|
+
}
|
|
6
|
+
function setCacheStateHeaders(headers, cacheState) {
|
|
7
|
+
headers.set(VINEXT_CACHE_HEADER, cacheState);
|
|
8
|
+
headers.set(NEXTJS_CACHE_HEADER, toNextJsCacheState(cacheState));
|
|
9
|
+
}
|
|
10
|
+
function buildCacheStateHeaders(cacheState) {
|
|
11
|
+
return {
|
|
12
|
+
[VINEXT_CACHE_HEADER]: cacheState,
|
|
13
|
+
[NEXTJS_CACHE_HEADER]: toNextJsCacheState(cacheState)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { buildCacheStateHeaders, setCacheStateHeaders };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=cache-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-headers.js","names":[],"sources":["../../src/server/cache-headers.ts"],"sourcesContent":["import { NEXTJS_CACHE_HEADER, VINEXT_CACHE_HEADER } from \"./headers.js\";\n\ntype VinextCacheState = \"HIT\" | \"MISS\" | \"STALE\" | \"STATIC\";\ntype NextJsCacheState = \"HIT\" | \"MISS\" | \"STALE\";\n\nfunction toNextJsCacheState(cacheState: VinextCacheState): NextJsCacheState {\n return cacheState === \"STATIC\" ? \"HIT\" : cacheState;\n}\n\nexport function setCacheStateHeaders(headers: Headers, cacheState: VinextCacheState): void {\n headers.set(VINEXT_CACHE_HEADER, cacheState);\n headers.set(NEXTJS_CACHE_HEADER, toNextJsCacheState(cacheState));\n}\n\nexport function buildCacheStateHeaders(cacheState: VinextCacheState): Record<string, string> {\n return {\n [VINEXT_CACHE_HEADER]: cacheState,\n [NEXTJS_CACHE_HEADER]: toNextJsCacheState(cacheState),\n };\n}\n"],"mappings":";;AAKA,SAAS,mBAAmB,YAAgD;CAC1E,OAAO,eAAe,WAAW,QAAQ;;AAG3C,SAAgB,qBAAqB,SAAkB,YAAoC;CACzF,QAAQ,IAAI,qBAAqB,WAAW;CAC5C,QAAQ,IAAI,qBAAqB,mBAAmB,WAAW,CAAC;;AAGlE,SAAgB,uBAAuB,YAAsD;CAC3F,OAAO;GACJ,sBAAsB;GACtB,sBAAsB,mBAAmB,WAAW;EACtD"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AppRouteSemanticIds } from "../routing/app-route-graph.js";
|
|
2
|
+
import { ArtifactCompatibilityEnvelope, ArtifactCompatibilityEvaluationOptions } from "./artifact-compatibility.js";
|
|
2
3
|
|
|
3
4
|
//#region src/server/cache-proof.d.ts
|
|
4
5
|
declare const CACHE_PROOF_MODEL_SCHEMA_VERSION = 1;
|
|
5
6
|
type CacheProofModelSchemaVersion = 1;
|
|
6
|
-
type CacheProofRejectionCode = "CP_MODEL_DISABLED" | "CP_DIMENSION_COUNT_EXCEEDED" | "CP_DIMENSION_NAME_MISSING" | "CP_DIMENSION_NAME_TOO_LONG" | "CP_DIMENSION_VALUE_COUNT_EXCEEDED" | "CP_DIMENSION_VALUE_TOO_LONG" | "CP_DIMENSION_VALUES_MISSING" | "CP_ENCODED_VARIANT_TOO_LONG" | "CP_INVALID_VARIANT_BUDGET" | "CP_ROUTE_VARIANT_BUDGET_ROUTE_MISMATCH" | "CP_ROUTE_VARIANT_CEILING_EXCEEDED" | "CP_UNSAFE_PUBLIC_DIMENSION" | "CP_BOUNDARY_OUTCOME_MISMATCH" | "CP_BOUNDARY_OUTCOME_UNKNOWN" | "CP_PRIVATE_DYNAMIC_DOWNGRADE" | "CP_STATIC_LAYOUT_CANDIDATE_OUTPUT_KIND" | "CP_STATIC_LAYOUT_CURRENT_OUTPUT_KIND" | "CP_STATIC_LAYOUT_ID_MISMATCH" | "CP_STATIC_LAYOUT_OBSERVATION_OUTPUT_KIND" | "CP_STATIC_LAYOUT_OBSERVATION_OUTPUT_MISMATCH" | "CP_STATIC_LAYOUT_PRIVATE_DYNAMIC_DOWNGRADE" | "
|
|
7
|
+
type CacheProofRejectionCode = "CP_CACHE_ENTRY_PROOF_MISSING" | "CP_MODEL_DISABLED" | "CP_ARTIFACT_COMPATIBILITY_INCOMPATIBLE" | "CP_ARTIFACT_COMPATIBILITY_UNKNOWN" | "CP_DIMENSION_COUNT_EXCEEDED" | "CP_DIMENSION_NAME_MISSING" | "CP_DIMENSION_NAME_TOO_LONG" | "CP_DIMENSION_VALUE_COUNT_EXCEEDED" | "CP_DIMENSION_VALUE_TOO_LONG" | "CP_DIMENSION_VALUES_MISSING" | "CP_ENCODED_VARIANT_TOO_LONG" | "CP_INVALID_VARIANT_BUDGET" | "CP_ROUTE_VARIANT_BUDGET_ROUTE_MISMATCH" | "CP_ROUTE_VARIANT_CEILING_EXCEEDED" | "CP_UNSAFE_PUBLIC_DIMENSION" | "CP_BOUNDARY_OUTCOME_MISMATCH" | "CP_BOUNDARY_OUTCOME_UNKNOWN" | "CP_PRIVATE_DYNAMIC_DOWNGRADE" | "CP_STATIC_LAYOUT_CANDIDATE_OUTPUT_KIND" | "CP_STATIC_LAYOUT_CURRENT_OUTPUT_KIND" | "CP_STATIC_LAYOUT_ID_MISMATCH" | "CP_STATIC_LAYOUT_OBSERVATION_OUTPUT_KIND" | "CP_STATIC_LAYOUT_OBSERVATION_OUTPUT_MISMATCH" | "CP_STATIC_LAYOUT_PRIVATE_DYNAMIC_DOWNGRADE" | "CP_STATIC_LAYOUT_REQUEST_API_OBSERVED" | "CP_STATIC_LAYOUT_REQUEST_API_UNKNOWN" | "CP_STATIC_LAYOUT_ROOT_BOUNDARY_MISMATCH" | "CP_STATIC_LAYOUT_ROOT_BOUNDARY_UNKNOWN" | "CP_STATIC_LAYOUT_VARIANT_DIMENSION_UNPROVEN";
|
|
7
8
|
type CacheProofAcceptanceCode = "CP_STATIC_LAYOUT_REUSE_PROVEN";
|
|
8
9
|
type CacheProofTraceCode = CacheProofAcceptanceCode | CacheProofRejectionCode;
|
|
9
10
|
type CacheProofTraceFieldValue = string | number | boolean | null | readonly string[];
|
|
@@ -247,7 +248,7 @@ type RenderObservation = Readonly<{
|
|
|
247
248
|
schemaVersion: CacheProofModelSchemaVersion;
|
|
248
249
|
}>;
|
|
249
250
|
type StaticLayoutReuseProof = Readonly<{
|
|
250
|
-
authorizesRuntimeReuse:
|
|
251
|
+
authorizesRuntimeReuse: true;
|
|
251
252
|
candidateOutput: StaticLayoutCacheProofOutputScope;
|
|
252
253
|
code: "CP_STATIC_LAYOUT_REUSE_PROVEN";
|
|
253
254
|
currentOutput: StaticLayoutCacheProofOutputScope;
|
|
@@ -257,6 +258,9 @@ type StaticLayoutReuseProof = Readonly<{
|
|
|
257
258
|
reuseClass: "static-layout";
|
|
258
259
|
variant: CacheVariant;
|
|
259
260
|
}>;
|
|
261
|
+
type StaticLayoutArtifactReuseProof = StaticLayoutReuseProof & Readonly<{
|
|
262
|
+
candidateArtifactCompatibility: ArtifactCompatibilityEnvelope;
|
|
263
|
+
}>;
|
|
260
264
|
type BuildStaticLayoutReuseProofInput = Readonly<{
|
|
261
265
|
candidateObservation: RenderObservation;
|
|
262
266
|
candidateVariant: CacheVariant;
|
|
@@ -269,6 +273,46 @@ type BuildStaticLayoutReuseProofResult = Readonly<{
|
|
|
269
273
|
kind: "rejected";
|
|
270
274
|
fallback: CacheProofBreakerFallback;
|
|
271
275
|
}>;
|
|
276
|
+
type CacheProofHotPathMetric = Readonly<{
|
|
277
|
+
code: CacheProofTraceCode;
|
|
278
|
+
fields: CacheProofTraceFields;
|
|
279
|
+
name: "vinext.cache.static_layout_artifact_reuse";
|
|
280
|
+
outcome: "fallback" | "reuse";
|
|
281
|
+
}>;
|
|
282
|
+
type StaticLayoutArtifactReuseDecision = Readonly<{
|
|
283
|
+
canReuse: true;
|
|
284
|
+
kind: "reuse";
|
|
285
|
+
metric: CacheProofHotPathMetric;
|
|
286
|
+
proof: StaticLayoutArtifactReuseProof;
|
|
287
|
+
}> | Readonly<{
|
|
288
|
+
canReuse: false;
|
|
289
|
+
fallback: CacheProofBreakerFallback;
|
|
290
|
+
kind: "fallback";
|
|
291
|
+
metric: CacheProofHotPathMetric;
|
|
292
|
+
}>;
|
|
293
|
+
type CacheEntryReuseDecision = Readonly<{
|
|
294
|
+
canReuse: true;
|
|
295
|
+
code: CacheProofAcceptanceCode;
|
|
296
|
+
kind: "reuse";
|
|
297
|
+
reuseClass: StaticLayoutReuseProof["reuseClass"];
|
|
298
|
+
}> | Readonly<{
|
|
299
|
+
canReuse: false;
|
|
300
|
+
code: CacheProofRejectionCode;
|
|
301
|
+
kind: "reject";
|
|
302
|
+
mode: CacheProofBreakerFallbackMode;
|
|
303
|
+
scope: CacheProofFallbackScope;
|
|
304
|
+
}>;
|
|
305
|
+
type CacheEntryReuseProof = Readonly<{
|
|
306
|
+
decision: CacheEntryReuseDecision | null;
|
|
307
|
+
kind: "runtime-cache-entry";
|
|
308
|
+
}>;
|
|
309
|
+
type CreateStaticLayoutArtifactReuseDecisionInput = Readonly<{
|
|
310
|
+
candidateArtifactCompatibility: ArtifactCompatibilityEnvelope;
|
|
311
|
+
candidateObservation: RenderObservation;
|
|
312
|
+
candidateVariant: BuildCacheVariantWithRouteBudgetResult;
|
|
313
|
+
currentArtifactCompatibility: ArtifactCompatibilityEnvelope;
|
|
314
|
+
currentOutput: CacheProofOutputScope;
|
|
315
|
+
}> & ArtifactCompatibilityEvaluationOptions;
|
|
272
316
|
type BuildRenderObservationInput = Readonly<{
|
|
273
317
|
boundaryOutcome: BoundaryOutcome;
|
|
274
318
|
cacheTags: readonly string[];
|
|
@@ -313,7 +357,9 @@ declare function buildRenderRequestApiObservations(input: BuildRenderRequestApiO
|
|
|
313
357
|
declare function buildRenderObservation(input: BuildRenderObservationInput): RenderObservation;
|
|
314
358
|
declare function hasCompleteNegativeRequestApiProof(observation: RenderObservation, requiredApis: readonly RenderRequestApiKind[]): boolean;
|
|
315
359
|
declare function buildStaticLayoutReuseProof(input: BuildStaticLayoutReuseProofInput): BuildStaticLayoutReuseProofResult;
|
|
360
|
+
declare function createStaticLayoutArtifactReuseDecision(input: CreateStaticLayoutArtifactReuseDecisionInput): StaticLayoutArtifactReuseDecision;
|
|
361
|
+
declare function createCacheEntryReuseProof(decision: StaticLayoutArtifactReuseDecision | null): CacheEntryReuseProof;
|
|
316
362
|
declare function createDisabledCacheProofDecision(input: CreateDisabledCacheProofDecisionInput): DisabledCacheProofDecision;
|
|
317
363
|
//#endregion
|
|
318
|
-
export { ALL_RENDER_REQUEST_API_KINDS, AppRouteCacheProofGraphScope, AppRouteCacheProofGraphScopeInput, BoundaryOutcome, BoundaryOutcomeCompatibility, BuildCacheVariantInput, BuildCacheVariantResult, BuildCacheVariantWithRouteBudgetInput, BuildCacheVariantWithRouteBudgetResult, BuildRenderObservationInput, BuildRenderRequestApiObservationsInput, BuildStaticLayoutReuseProofInput, BuildStaticLayoutReuseProofResult, CACHE_PROOF_MODEL_SCHEMA_VERSION, CacheProofAcceptanceCode, CacheProofBreakerFallback, CacheProofBreakerFallbackMode, CacheProofDowngradeClassification, CacheProofDowngradeReason, CacheProofDowngradeTarget, CacheProofFallbackScope, CacheProofModelSchemaVersion, CacheProofOutputScope, CacheProofRejectionCode, CacheProofTraceCode, CacheProofTraceFieldValue, CacheProofTraceFields, CacheVariant, CacheVariantBudget, CacheVariantDimension, CacheVariantDimensionInput, CacheVariantDimensionPrivacy, CacheVariantDimensionSource, CacheVariantRouteBudget, CacheVariantRouteBudgetAdmission, ClassifyCacheVariantDimensionDowngradeInput, ClassifyRenderObservationDowngradeInput, CreateDisabledCacheProofDecisionInput, DEFAULT_CACHE_VARIANT_BUDGET, DisabledCacheProofDecision, RenderCacheability, RenderObservation, RenderObservationCompleteness, RenderRequestApiKind, RenderRequestApiObservation, RenderRequestApiStatus, StaticLayoutCacheProofOutputScope, StaticLayoutReuseProof, buildBoundaryOutcomeCompatibility, buildCacheVariant, buildCacheVariantWithRouteBudget, buildRenderObservation, buildRenderRequestApiObservations, buildStaticLayoutReuseProof, classifyCacheVariantDimensionDowngrade, classifyRenderObservationDowngrade, createAppRouteCacheProofGraphScope, createDisabledCacheProofDecision, enforceCacheVariantRouteBudget, hasCompleteNegativeRequestApiProof };
|
|
364
|
+
export { ALL_RENDER_REQUEST_API_KINDS, AppRouteCacheProofGraphScope, AppRouteCacheProofGraphScopeInput, BoundaryOutcome, BoundaryOutcomeCompatibility, BuildCacheVariantInput, BuildCacheVariantResult, BuildCacheVariantWithRouteBudgetInput, BuildCacheVariantWithRouteBudgetResult, BuildRenderObservationInput, BuildRenderRequestApiObservationsInput, BuildStaticLayoutReuseProofInput, BuildStaticLayoutReuseProofResult, CACHE_PROOF_MODEL_SCHEMA_VERSION, CacheEntryReuseDecision, CacheEntryReuseProof, CacheProofAcceptanceCode, CacheProofBreakerFallback, CacheProofBreakerFallbackMode, CacheProofDowngradeClassification, CacheProofDowngradeReason, CacheProofDowngradeTarget, CacheProofFallbackScope, CacheProofHotPathMetric, CacheProofModelSchemaVersion, CacheProofOutputScope, CacheProofRejectionCode, CacheProofTraceCode, CacheProofTraceFieldValue, CacheProofTraceFields, CacheVariant, CacheVariantBudget, CacheVariantDimension, CacheVariantDimensionInput, CacheVariantDimensionPrivacy, CacheVariantDimensionSource, CacheVariantRouteBudget, CacheVariantRouteBudgetAdmission, ClassifyCacheVariantDimensionDowngradeInput, ClassifyRenderObservationDowngradeInput, CreateDisabledCacheProofDecisionInput, CreateStaticLayoutArtifactReuseDecisionInput, DEFAULT_CACHE_VARIANT_BUDGET, DisabledCacheProofDecision, RenderCacheability, RenderObservation, RenderObservationCompleteness, RenderRequestApiKind, RenderRequestApiObservation, RenderRequestApiStatus, StaticLayoutArtifactReuseDecision, StaticLayoutArtifactReuseProof, StaticLayoutCacheProofOutputScope, StaticLayoutReuseProof, buildBoundaryOutcomeCompatibility, buildCacheVariant, buildCacheVariantWithRouteBudget, buildRenderObservation, buildRenderRequestApiObservations, buildStaticLayoutReuseProof, classifyCacheVariantDimensionDowngrade, classifyRenderObservationDowngrade, createAppRouteCacheProofGraphScope, createCacheEntryReuseProof, createDisabledCacheProofDecision, createStaticLayoutArtifactReuseDecision, enforceCacheVariantRouteBudget, hasCompleteNegativeRequestApiProof };
|
|
319
365
|
//# sourceMappingURL=cache-proof.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fnv1a64 } from "../utils/hash.js";
|
|
2
|
+
import { evaluateArtifactCompatibility } from "./artifact-compatibility.js";
|
|
2
3
|
import { findSortedStringPosition } from "../utils/sorted-array.js";
|
|
3
4
|
//#region src/server/cache-proof.ts
|
|
4
5
|
const CACHE_PROOF_MODEL_SCHEMA_VERSION = 1;
|
|
@@ -617,19 +618,6 @@ function createStaticLayoutDowngradeFallback(downgrade) {
|
|
|
617
618
|
target: downgrade.target
|
|
618
619
|
}, mode);
|
|
619
620
|
}
|
|
620
|
-
function createPrivateVariantDimensionFallback(dimension) {
|
|
621
|
-
const downgrade = classifyCacheVariantDimensionDowngrade({ source: dimension.source });
|
|
622
|
-
if (!downgrade && dimension.privacy !== "private") return null;
|
|
623
|
-
const target = downgrade?.target ?? "private";
|
|
624
|
-
const mode = target === "privateUncacheable" ? "privateUncacheable" : "renderFresh";
|
|
625
|
-
return buildBreakerFallback("CP_STATIC_LAYOUT_PRIVATE_VARIANT_DIMENSION", {
|
|
626
|
-
dimension: dimension.name,
|
|
627
|
-
privacy: dimension.privacy,
|
|
628
|
-
reasonCode: downgrade?.code ?? null,
|
|
629
|
-
source: dimension.source,
|
|
630
|
-
target
|
|
631
|
-
}, mode);
|
|
632
|
-
}
|
|
633
621
|
function outputFieldMismatch(candidate, observation) {
|
|
634
622
|
if (candidate.layoutId !== observation.layoutId) return "layoutId";
|
|
635
623
|
if (candidate.rootBoundaryId !== observation.rootBoundaryId) return "rootBoundaryId";
|
|
@@ -684,13 +672,10 @@ function buildStaticLayoutReuseProof(input) {
|
|
|
684
672
|
kind: "rejected",
|
|
685
673
|
fallback: boundaryCompatibility.fallback
|
|
686
674
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
fallback
|
|
692
|
-
};
|
|
693
|
-
}
|
|
675
|
+
if (input.candidateVariant.dimensions.length > 0) return rejectStaticLayoutReuseProof("CP_STATIC_LAYOUT_VARIANT_DIMENSION_UNPROVEN", {
|
|
676
|
+
dimensionCount: input.candidateVariant.dimensions.length,
|
|
677
|
+
sources: sortedUnique(input.candidateVariant.dimensions.map((dimension) => dimension.source))
|
|
678
|
+
});
|
|
694
679
|
if (!candidateObservation.downgrade.isPublicCacheCandidate) return {
|
|
695
680
|
kind: "rejected",
|
|
696
681
|
fallback: createStaticLayoutDowngradeFallback(candidateObservation.downgrade)
|
|
@@ -707,7 +692,7 @@ function buildStaticLayoutReuseProof(input) {
|
|
|
707
692
|
return {
|
|
708
693
|
kind: "proof",
|
|
709
694
|
proof: {
|
|
710
|
-
authorizesRuntimeReuse:
|
|
695
|
+
authorizesRuntimeReuse: true,
|
|
711
696
|
candidateOutput,
|
|
712
697
|
code: "CP_STATIC_LAYOUT_REUSE_PROVEN",
|
|
713
698
|
currentOutput,
|
|
@@ -724,6 +709,77 @@ function buildStaticLayoutReuseProof(input) {
|
|
|
724
709
|
}
|
|
725
710
|
};
|
|
726
711
|
}
|
|
712
|
+
function createCacheProofHotPathMetric(outcome, code, fields) {
|
|
713
|
+
return {
|
|
714
|
+
name: "vinext.cache.static_layout_artifact_reuse",
|
|
715
|
+
outcome,
|
|
716
|
+
code,
|
|
717
|
+
fields
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
function createStaticLayoutArtifactReuseFallback(fallback) {
|
|
721
|
+
return {
|
|
722
|
+
kind: "fallback",
|
|
723
|
+
canReuse: false,
|
|
724
|
+
fallback,
|
|
725
|
+
metric: createCacheProofHotPathMetric("fallback", fallback.code, fallback.fields)
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function createStaticLayoutArtifactReuseDecision(input) {
|
|
729
|
+
if (input.candidateVariant.kind === "breakerFallback") return createStaticLayoutArtifactReuseFallback(input.candidateVariant.fallback);
|
|
730
|
+
const artifactCompatibility = evaluateArtifactCompatibility(input.currentArtifactCompatibility, input.candidateArtifactCompatibility, { compatibilityMap: input.compatibilityMap });
|
|
731
|
+
if (artifactCompatibility.kind === "unknown") return createStaticLayoutArtifactReuseFallback(buildBreakerFallback("CP_ARTIFACT_COMPATIBILITY_UNKNOWN", {
|
|
732
|
+
compatibilityFallback: artifactCompatibility.fallback,
|
|
733
|
+
reason: artifactCompatibility.reason
|
|
734
|
+
}));
|
|
735
|
+
if (artifactCompatibility.kind === "incompatible") return createStaticLayoutArtifactReuseFallback(buildBreakerFallback("CP_ARTIFACT_COMPATIBILITY_INCOMPATIBLE", {
|
|
736
|
+
compatibilityFallback: artifactCompatibility.fallback,
|
|
737
|
+
reason: artifactCompatibility.reason
|
|
738
|
+
}));
|
|
739
|
+
const proof = buildStaticLayoutReuseProof({
|
|
740
|
+
candidateObservation: input.candidateObservation,
|
|
741
|
+
candidateVariant: input.candidateVariant.variant,
|
|
742
|
+
currentOutput: input.currentOutput
|
|
743
|
+
});
|
|
744
|
+
if (proof.kind === "rejected") return createStaticLayoutArtifactReuseFallback(proof.fallback);
|
|
745
|
+
return {
|
|
746
|
+
kind: "reuse",
|
|
747
|
+
canReuse: true,
|
|
748
|
+
proof: {
|
|
749
|
+
...proof.proof,
|
|
750
|
+
candidateArtifactCompatibility: { ...input.candidateArtifactCompatibility }
|
|
751
|
+
},
|
|
752
|
+
metric: createCacheProofHotPathMetric("reuse", proof.proof.code, proof.proof.fields)
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
function createCacheEntryReuseProof(decision) {
|
|
756
|
+
if (decision === null) return {
|
|
757
|
+
kind: "runtime-cache-entry",
|
|
758
|
+
decision: null
|
|
759
|
+
};
|
|
760
|
+
switch (decision.kind) {
|
|
761
|
+
case "reuse": return {
|
|
762
|
+
kind: "runtime-cache-entry",
|
|
763
|
+
decision: {
|
|
764
|
+
canReuse: true,
|
|
765
|
+
code: decision.proof.code,
|
|
766
|
+
kind: "reuse",
|
|
767
|
+
reuseClass: decision.proof.reuseClass
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
case "fallback": return {
|
|
771
|
+
kind: "runtime-cache-entry",
|
|
772
|
+
decision: {
|
|
773
|
+
canReuse: false,
|
|
774
|
+
code: decision.fallback.code,
|
|
775
|
+
kind: "reject",
|
|
776
|
+
mode: decision.fallback.mode,
|
|
777
|
+
scope: decision.fallback.scope
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
default: return assertNever(decision);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
727
783
|
function createDisabledCacheProofDecision(input) {
|
|
728
784
|
return {
|
|
729
785
|
kind: "disabled",
|
|
@@ -735,6 +791,6 @@ function createDisabledCacheProofDecision(input) {
|
|
|
735
791
|
};
|
|
736
792
|
}
|
|
737
793
|
//#endregion
|
|
738
|
-
export { ALL_RENDER_REQUEST_API_KINDS, CACHE_PROOF_MODEL_SCHEMA_VERSION, DEFAULT_CACHE_VARIANT_BUDGET, buildBoundaryOutcomeCompatibility, buildCacheVariant, buildCacheVariantWithRouteBudget, buildRenderObservation, buildRenderRequestApiObservations, buildStaticLayoutReuseProof, classifyCacheVariantDimensionDowngrade, classifyRenderObservationDowngrade, createAppRouteCacheProofGraphScope, createDisabledCacheProofDecision, enforceCacheVariantRouteBudget, hasCompleteNegativeRequestApiProof };
|
|
794
|
+
export { ALL_RENDER_REQUEST_API_KINDS, CACHE_PROOF_MODEL_SCHEMA_VERSION, DEFAULT_CACHE_VARIANT_BUDGET, buildBoundaryOutcomeCompatibility, buildCacheVariant, buildCacheVariantWithRouteBudget, buildRenderObservation, buildRenderRequestApiObservations, buildStaticLayoutReuseProof, classifyCacheVariantDimensionDowngrade, classifyRenderObservationDowngrade, createAppRouteCacheProofGraphScope, createCacheEntryReuseProof, createDisabledCacheProofDecision, createStaticLayoutArtifactReuseDecision, enforceCacheVariantRouteBudget, hasCompleteNegativeRequestApiProof };
|
|
739
795
|
|
|
740
796
|
//# sourceMappingURL=cache-proof.js.map
|