vinext 0.0.47 → 0.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/build/layout-classification.js +3 -1
- package/dist/build/layout-classification.js.map +1 -1
- package/dist/build/prerender.js +10 -10
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/report.d.ts +8 -4
- package/dist/build/report.js +17 -7
- package/dist/build/report.js.map +1 -1
- package/dist/build/run-prerender.d.ts +5 -0
- package/dist/build/run-prerender.js +4 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/server-manifest.js +2 -7
- package/dist/build/server-manifest.js.map +1 -1
- package/dist/build/standalone.js +3 -5
- package/dist/build/standalone.js.map +1 -1
- package/dist/check.js +45 -29
- package/dist/check.js.map +1 -1
- package/dist/cli-args.d.ts +3 -1
- package/dist/cli-args.js +18 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +9 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/config-matchers.js +46 -37
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/deploy.d.ts +18 -2
- package/dist/deploy.js +47 -4
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +11 -9
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.js +4 -1
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.js +3 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +14 -59
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +12 -3
- package/dist/entries/runtime-entry-module.js +15 -4
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +12 -7
- package/dist/index.js.map +1 -1
- package/dist/plugins/og-assets.js +15 -16
- package/dist/plugins/og-assets.js.map +1 -1
- package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
- package/dist/plugins/rsc-client-shim-excludes.js +10 -1
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +90 -4
- package/dist/routing/app-route-graph.js +210 -7
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +15 -3
- package/dist/routing/app-router.js +20 -23
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +3 -1
- package/dist/routing/file-matcher.js +6 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.js +10 -19
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-matching.d.ts +28 -0
- package/dist/routing/route-matching.js +44 -0
- package/dist/routing/route-matching.js.map +1 -0
- package/dist/routing/route-pattern.js +4 -1
- package/dist/routing/route-pattern.js.map +1 -1
- package/dist/routing/route-trie.d.ts +8 -0
- package/dist/routing/route-trie.js +12 -1
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/route-validation.js +3 -4
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +8 -1
- package/dist/routing/utils.js +25 -2
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/app-browser-entry.js +66 -49
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +7 -5
- package/dist/server/app-browser-navigation-controller.js +43 -35
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +33 -15
- package/dist/server/app-browser-state.js +52 -59
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +68 -0
- package/dist/server/app-browser-visible-commit.js +182 -0
- package/dist/server/app-browser-visible-commit.js.map +1 -0
- package/dist/server/app-client-reference-preloader.d.ts +15 -0
- package/dist/server/app-client-reference-preloader.js +46 -0
- package/dist/server/app-client-reference-preloader.js.map +1 -0
- package/dist/server/app-elements-wire.d.ts +130 -0
- package/dist/server/app-elements-wire.js +205 -0
- package/dist/server/app-elements-wire.js.map +1 -0
- package/dist/server/app-elements.d.ts +2 -84
- package/dist/server/app-elements.js +3 -102
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +1 -1
- package/dist/server/app-middleware.d.ts +2 -1
- package/dist/server/app-middleware.js +34 -11
- package/dist/server/app-middleware.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -1
- package/dist/server/app-page-boundary-render.js +8 -5
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +1 -0
- package/dist/server/app-page-cache.js +8 -13
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +2 -1
- package/dist/server/app-page-dispatch.js +18 -10
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +1 -1
- package/dist/server/app-page-element-builder.js +8 -5
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +23 -5
- package/dist/server/app-page-execution.js +39 -24
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.js +2 -1
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-method.js +2 -5
- package/dist/server/app-page-method.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +1 -1
- package/dist/server/app-page-probe.js +5 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +38 -3
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +7 -10
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +3 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +5 -2
- package/dist/server/app-page-route-wiring.js +15 -12
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +7 -0
- package/dist/server/app-page-stream.js +9 -2
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-endpoints.js +3 -2
- package/dist/server/app-prerender-endpoints.js.map +1 -1
- package/dist/server/app-route-handler-cache.js +2 -1
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.js +6 -5
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-policy.js +13 -13
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.js +2 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +9 -1
- package/dist/server/app-route-handler-runtime.js +11 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js +9 -4
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +34 -0
- package/dist/server/app-rsc-cache-busting.js +137 -0
- package/dist/server/app-rsc-cache-busting.js.map +1 -0
- package/dist/server/app-rsc-handler.js +22 -11
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +4 -2
- package/dist/server/app-rsc-request-normalization.js +10 -6
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.js +8 -4
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-segment-config.js +4 -0
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.js +43 -51
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.js +21 -20
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +44 -0
- package/dist/server/artifact-compatibility.js +82 -0
- package/dist/server/artifact-compatibility.js.map +1 -0
- package/dist/server/cache-proof.d.ts +200 -0
- package/dist/server/cache-proof.js +342 -0
- package/dist/server/cache-proof.js.map +1 -0
- package/dist/server/dev-origin-check.js +8 -4
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-server.js +1 -6
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/http-error-responses.d.ts +67 -0
- package/dist/server/http-error-responses.js +77 -0
- package/dist/server/http-error-responses.js.map +1 -0
- package/dist/server/image-optimization.js +2 -1
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/metadata-route-response.js +6 -5
- package/dist/server/metadata-route-response.js.map +1 -1
- package/dist/server/metadata-routes.d.ts +1 -0
- package/dist/server/metadata-routes.js +6 -0
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.js +2 -2
- package/dist/server/middleware-matcher.js.map +1 -1
- package/dist/server/middleware-response-headers.js +21 -0
- package/dist/server/middleware-response-headers.js.map +1 -1
- package/dist/server/middleware-runtime.js +3 -3
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/navigation-trace.d.ts +33 -0
- package/dist/server/navigation-trace.js +35 -0
- package/dist/server/navigation-trace.js.map +1 -0
- package/dist/server/next-error-digest.d.ts +44 -0
- package/dist/server/next-error-digest.js +40 -0
- package/dist/server/next-error-digest.js.map +1 -0
- package/dist/server/pages-api-route.js +2 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-node-compat.js +4 -16
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +2 -8
- package/dist/server/pages-page-response.js +44 -14
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +6 -0
- package/dist/server/prod-server.js +28 -21
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +42 -1
- package/dist/server/request-pipeline.js +97 -17
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +2 -2
- package/dist/shims/cache-runtime.js +3 -6
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.js +3 -5
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/fetch-cache.js +2 -3
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.js +2 -3
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/headers.js +4 -44
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-state.js +2 -3
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/internal/als-registry.d.ts +15 -0
- package/dist/shims/internal/als-registry.js +55 -0
- package/dist/shims/internal/als-registry.js.map +1 -0
- package/dist/shims/internal/cookie-serialize.d.ts +46 -0
- package/dist/shims/internal/cookie-serialize.js +51 -0
- package/dist/shims/internal/cookie-serialize.js.map +1 -0
- package/dist/shims/link.js +31 -26
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +26 -1
- package/dist/shims/metadata.js +94 -4
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.js +2 -3
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +2 -7
- package/dist/shims/navigation.js +44 -36
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.js +2 -4
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/router-state.js +2 -3
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.js +2 -2
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.js +5 -30
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +1 -1
- package/dist/shims/slot.js +5 -4
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -2
- package/dist/shims/thenable-params.js +26 -6
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +2 -14
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/base-path.d.ts +7 -1
- package/dist/utils/base-path.js +12 -1
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/safe-json-file.d.ts +18 -0
- package/dist/utils/safe-json-file.js +25 -0
- package/dist/utils/safe-json-file.js.map +1 -0
- package/dist/utils/text-stream.d.ts +29 -0
- package/dist/utils/text-stream.js +66 -0
- package/dist/utils/text-stream.js.map +1 -0
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-server-action-execution.js","names":[],"sources":["../../src/server/app-server-action-execution.ts"],"sourcesContent":["import type { HeadersAccessPhase } from \"vinext/shims/headers\";\nimport { type FetchCacheMode, setCurrentFetchCacheMode } from \"vinext/shims/fetch-cache\";\nimport { resolveAppPageActionRerenderTarget } from \"./app-page-request.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { validateCsrfOrigin, validateServerActionPayload } from \"./request-pipeline.js\";\nimport {\n createServerActionNotFoundResponse,\n getServerActionNotFoundMessage,\n isServerActionNotFoundError,\n} from \"./server-action-not-found.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\n\ntype AppServerActionErrorReporter = (\n error: Error,\n request: { path: string; method: string; headers: Record<string, string> },\n route: { routerKind: \"App Router\"; routePath: string; routeType: \"action\" },\n) => void;\n\ntype AppServerActionDecoder = (body: FormData) => Promise<unknown>;\n\ntype ReadFormDataWithLimit = (request: Request, maxBytes: number) => Promise<FormData>;\n\ntype ReadBodyWithLimit = (request: Request, maxBytes: number) => Promise<string>;\n\ntype AppServerActionFunction = (...args: unknown[]) => unknown;\n\ntype AppServerActionReturnValue =\n | {\n data: unknown;\n ok: true;\n }\n | {\n data: unknown;\n ok: false;\n };\n\ntype AppServerActionRedirect = {\n status: number;\n type: string;\n url: string;\n};\n\ntype AppServerActionRoute = {\n pattern: string;\n};\n\ntype AppServerActionMatch<TRoute extends AppServerActionRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype AppServerActionIntercept<TPage = unknown> = {\n matchedParams: AppPageParams;\n page: TPage;\n slotKey: string;\n sourceRouteIndex: number;\n};\n\ntype BuildServerActionPageElementOptions<TRoute extends AppServerActionRoute, TInterceptOpts> = {\n cleanPathname: string;\n interceptOpts: TInterceptOpts | undefined;\n isRscRequest: boolean;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype AppServerActionRscModel<TElement> = {\n returnValue: AppServerActionReturnValue;\n root: TElement;\n};\n\ntype RenderServerActionRscStreamOptions<TTemporaryReferences> = {\n onError: (error: unknown) => unknown;\n temporaryReferences: TTemporaryReferences;\n};\n\ntype DecodeServerActionReplyOptions<TTemporaryReferences> = {\n temporaryReferences: TTemporaryReferences;\n};\n\nexport type HandleProgressiveServerActionRequestOptions = {\n actionId: string | null;\n allowedOrigins: string[];\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n decodeAction: AppServerActionDecoder;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n readFormDataWithLimit: ReadFormDataWithLimit;\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n};\n\nexport type HandleServerActionRscRequestOptions<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n> = {\n actionId: string | null;\n allowedOrigins: string[];\n buildPageElement: (\n options: BuildServerActionPageElementOptions<TRoute, TInterceptOpts>,\n ) => TElement;\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n createNotFoundElement: (routeId: string) => TElement;\n createPayloadRouteId: (pathname: string, interceptionContext: string | null) => string;\n createRscOnErrorHandler: (\n request: Request,\n pathname: string,\n pattern: string,\n ) => (error: unknown) => unknown;\n createTemporaryReferenceSet: () => TTemporaryReferences;\n decodeReply: (\n body: string | FormData,\n options: DecodeServerActionReplyOptions<TTemporaryReferences>,\n ) => Promise<unknown[]> | unknown[];\n findIntercept: (pathname: string) => AppServerActionIntercept<TPage> | null;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n getRouteParamNames: (route: TRoute) => readonly string[];\n getSourceRoute: (sourceRouteIndex: number) => TRoute | undefined;\n isRscRequest: boolean;\n loadServerAction: (actionId: string) => Promise<unknown>;\n matchRoute: (pathname: string) => AppServerActionMatch<TRoute> | null;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n middlewareStatus: number | null | undefined;\n mountedSlotsHeader: string | null;\n readBodyWithLimit: ReadBodyWithLimit;\n readFormDataWithLimit: ReadFormDataWithLimit;\n renderToReadableStream: (\n model: AppServerActionRscModel<TElement>,\n options: RenderServerActionRscStreamOptions<TTemporaryReferences>,\n ) => BodyInit | null | Promise<BodyInit | null>;\n reportRequestError: AppServerActionErrorReporter;\n resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;\n request: Request;\n sanitizeErrorForClient: (error: unknown) => unknown;\n searchParams: URLSearchParams;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n setNavigationContext: (context: {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n }) => void;\n toInterceptOpts: (intercept: AppServerActionIntercept<TPage>) => TInterceptOpts;\n};\n\ntype ActionControlResponse =\n | {\n kind: \"redirect\";\n url: string;\n }\n | {\n kind: \"status\";\n statusCode: number;\n };\n\nfunction isRequestBodyTooLarge(error: unknown): boolean {\n return error instanceof Error && error.message === \"Request body too large\";\n}\n\nfunction isAppServerActionFunction(action: unknown): action is AppServerActionFunction {\n return typeof action === \"function\";\n}\n\nfunction normalizeError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction getServerActionFailureMessage(error: unknown): string {\n return error instanceof Error && error.message ? error.message : String(error);\n}\n\nexport async function readActionBodyWithLimit(request: Request, maxBytes: number): Promise<string> {\n if (!request.body) return \"\";\n\n const reader = request.body.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n let totalSize = 0;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n throw new Error(\"Request body too large\");\n }\n chunks.push(decoder.decode(result.value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n}\n\nexport async function readActionFormDataWithLimit(\n request: Request,\n maxBytes: number,\n): Promise<FormData> {\n if (!request.body) return new FormData();\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n throw new Error(\"Request body too large\");\n }\n chunks.push(result.value);\n }\n\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new Response(combined, {\n headers: { \"Content-Type\": request.headers.get(\"content-type\") || \"\" },\n }).formData();\n}\n\nfunction getErrorDigest(error: unknown): string | null {\n if (!error || typeof error !== \"object\" || !(\"digest\" in error)) {\n return null;\n }\n\n return String(error.digest);\n}\n\nfunction getActionControlResponse(error: unknown): ActionControlResponse | null {\n const digest = getErrorDigest(error);\n if (!digest) return null;\n\n if (digest.startsWith(\"NEXT_REDIRECT;\")) {\n const parts = digest.split(\";\");\n const encodedUrl = parts[2];\n if (!encodedUrl) {\n return null;\n }\n\n return {\n kind: \"redirect\",\n url: decodeURIComponent(encodedUrl),\n };\n }\n\n if (digest === \"NEXT_NOT_FOUND\" || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n const statusCode = digest === \"NEXT_NOT_FOUND\" ? 404 : parseInt(digest.split(\";\")[1], 10);\n if (!Number.isInteger(statusCode)) {\n return null;\n }\n\n return {\n kind: \"status\",\n statusCode,\n };\n }\n\n return null;\n}\n\nfunction getActionRedirect(error: unknown): AppServerActionRedirect | null {\n const digest = getErrorDigest(error);\n if (!digest?.startsWith(\"NEXT_REDIRECT;\")) {\n return null;\n }\n\n const parts = digest.split(\";\");\n const encodedUrl = parts[2];\n if (!encodedUrl) {\n return null;\n }\n\n return {\n status: parts[3] ? parseInt(parts[3], 10) : 307,\n type: parts[1] || \"push\",\n url: decodeURIComponent(encodedUrl),\n };\n}\n\nfunction isActionHttpFallback(error: unknown): boolean {\n const digest = getErrorDigest(error);\n return digest === \"NEXT_NOT_FOUND\" || digest?.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\") === true;\n}\n\nfunction createServerActionErrorResponse(\n error: unknown,\n options: {\n cleanPathname: string;\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n },\n): Response {\n options.getAndClearPendingCookies();\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return new Response(\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n { status: 500 },\n );\n}\n\nfunction createActionNotFoundResponse(\n actionId: string | null,\n options: {\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n },\n): Response {\n options.getAndClearPendingCookies();\n console.warn(getServerActionNotFoundMessage(actionId));\n options.clearRequestContext();\n return createServerActionNotFoundResponse();\n}\n\nexport function isProgressiveServerActionRequest(\n request: Pick<Request, \"method\">,\n contentType: string,\n actionId: string | null,\n): boolean {\n return (\n request.method.toUpperCase() === \"POST\" &&\n contentType.startsWith(\"multipart/form-data\") &&\n !actionId\n );\n}\n\nexport async function handleProgressiveServerActionRequest(\n options: HandleProgressiveServerActionRequestOptions,\n): Promise<Response | null> {\n if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) {\n return csrfResponse;\n }\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n\n try {\n let body: FormData;\n try {\n // Progressive submissions can still fall through to a regular page render when\n // the multipart body is not an action payload. Read a clone so that fallback\n // code can still consume the original request body.\n body = await options.readFormDataWithLimit(\n options.request.clone(),\n options.maxActionBodySize,\n );\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n const action = await options.decodeAction(body);\n if (typeof action !== \"function\") {\n return null;\n }\n\n let actionControlResponse: ActionControlResponse | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n await action();\n } catch (error) {\n actionControlResponse = getActionControlResponse(error);\n if (!actionControlResponse) {\n throw error;\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (!actionControlResponse) {\n // Next.js decodes form state and re-renders after a successful MPA action.\n // vinext currently supports the redirect/error status cases; successful\n // non-redirect actions intentionally fall through to the page render.\n return null;\n }\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n\n const headers = new Headers();\n if (actionControlResponse.kind === \"redirect\") {\n headers.set(\"Location\", new URL(actionControlResponse.url, options.request.url).toString());\n }\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);\n for (const cookie of actionPendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) {\n headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n\n return new Response(null, {\n status: actionControlResponse.kind === \"redirect\" ? 303 : actionControlResponse.statusCode,\n headers,\n });\n } catch (error) {\n if (isServerActionNotFoundError(error, null)) {\n return createActionNotFoundResponse(null, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n options.getAndClearPendingCookies();\n // Next.js rethrows generic MPA action errors into its page render path.\n // vinext does not yet implement that form-state render path, so unexpected\n // action failures remain request failures here.\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return new Response(\n process.env.NODE_ENV === \"production\"\n ? \"Internal Server Error\"\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n { status: 500 },\n );\n }\n}\n\nexport async function handleServerActionRscRequest<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n>(\n options: HandleServerActionRscRequestOptions<\n TElement,\n TRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage\n >,\n): Promise<Response | null> {\n if (options.request.method.toUpperCase() !== \"POST\" || !options.actionId) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) return csrfResponse;\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n\n try {\n let body: string | FormData;\n try {\n body = options.contentType.startsWith(\"multipart/form-data\")\n ? await options.readFormDataWithLimit(options.request, options.maxActionBodySize)\n : await options.readBodyWithLimit(options.request, options.maxActionBodySize);\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return new Response(\"Payload Too Large\", { status: 413 });\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n let action: unknown;\n try {\n action = await options.loadServerAction(options.actionId);\n } catch (error) {\n if (isServerActionNotFoundError(error, options.actionId)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n throw error;\n }\n\n if (!isAppServerActionFunction(action)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n const temporaryReferences = options.createTemporaryReferenceSet();\n const args = await options.decodeReply(body, { temporaryReferences });\n let returnValue: AppServerActionReturnValue;\n let actionRedirect: AppServerActionRedirect | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n try {\n const data = await action.apply(null, args);\n returnValue = { ok: true, data };\n } catch (error) {\n actionRedirect = getActionRedirect(error);\n if (actionRedirect) {\n returnValue = { ok: true, data: undefined };\n } else if (isActionHttpFallback(error)) {\n returnValue = { ok: false, data: error };\n } else {\n console.error(\"[vinext] Server action error:\", error);\n returnValue = { ok: false, data: options.sanitizeErrorForClient(error) };\n }\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (actionRedirect) {\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n const redirectHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);\n redirectHeaders.set(\"x-action-redirect\", actionRedirect.url);\n redirectHeaders.set(\"x-action-redirect-type\", actionRedirect.type);\n redirectHeaders.set(\"x-action-redirect-status\", String(actionRedirect.status));\n for (const cookie of actionPendingCookies) {\n redirectHeaders.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) redirectHeaders.append(\"Set-Cookie\", actionDraftCookie);\n return new Response(\"\", { status: 200, headers: redirectHeaders });\n }\n\n const match = options.matchRoute(options.cleanPathname);\n let element: TElement;\n let errorPattern = match ? match.route.pattern : options.cleanPathname;\n if (match) {\n const { route: actionRoute, params: actionParams } = match;\n const actionRerenderTarget = resolveAppPageActionRerenderTarget({\n cleanPathname: options.cleanPathname,\n currentParams: actionParams,\n currentRoute: actionRoute,\n findIntercept: options.findIntercept,\n getRouteParamNames: options.getRouteParamNames,\n getSourceRoute: options.getSourceRoute,\n isRscRequest: options.isRscRequest,\n toInterceptOpts: options.toInterceptOpts,\n });\n\n options.setNavigationContext({\n pathname: options.cleanPathname,\n searchParams: options.searchParams,\n params: actionRerenderTarget.navigationParams,\n });\n setCurrentFetchCacheMode(\n options.resolveRouteFetchCacheMode?.(actionRerenderTarget.route) ?? null,\n );\n element = options.buildPageElement({\n cleanPathname: options.cleanPathname,\n interceptOpts: actionRerenderTarget.interceptOpts,\n isRscRequest: options.isRscRequest,\n mountedSlotsHeader: options.mountedSlotsHeader,\n params: actionRerenderTarget.params,\n request: options.request,\n route: actionRerenderTarget.route,\n searchParams: options.searchParams,\n });\n errorPattern = actionRerenderTarget.route.pattern;\n } else {\n const actionRouteId = options.createPayloadRouteId(options.cleanPathname, null);\n element = options.createNotFoundElement(actionRouteId);\n }\n\n const onRenderError = options.createRscOnErrorHandler(\n options.request,\n options.cleanPathname,\n errorPattern,\n );\n const rscStream = await options.renderToReadableStream(\n { root: element, returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n\n const actionHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: \"RSC, Accept\",\n });\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n const actionResponse = new Response(rscStream, {\n status: options.middlewareStatus ?? 200,\n headers: actionHeaders,\n });\n if (actionPendingCookies.length > 0 || actionDraftCookie) {\n for (const cookie of actionPendingCookies) {\n actionResponse.headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) actionResponse.headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n return actionResponse;\n } catch (error) {\n return createServerActionErrorResponse(error, {\n cleanPathname: options.cleanPathname,\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n reportRequestError: options.reportRequestError,\n request: options.request,\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-server-action-execution.js","names":[],"sources":["../../src/server/app-server-action-execution.ts"],"sourcesContent":["import type { HeadersAccessPhase } from \"vinext/shims/headers\";\nimport { type FetchCacheMode, setCurrentFetchCacheMode } from \"vinext/shims/fetch-cache\";\nimport { VINEXT_RSC_VARY_HEADER } from \"./app-rsc-cache-busting.js\";\nimport { resolveAppPageActionRerenderTarget } from \"./app-page-request.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport {\n getNextErrorDigest,\n parseNextHttpErrorDigest,\n parseNextRedirectDigest,\n} from \"./next-error-digest.js\";\nimport { validateCsrfOrigin, validateServerActionPayload } from \"./request-pipeline.js\";\nimport { readStreamAsTextWithLimit } from \"../utils/text-stream.js\";\nimport {\n createServerActionNotFoundResponse,\n getServerActionNotFoundMessage,\n isServerActionNotFoundError,\n} from \"./server-action-not-found.js\";\nimport { internalServerErrorResponse, payloadTooLargeResponse } from \"./http-error-responses.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\n\ntype AppServerActionErrorReporter = (\n error: Error,\n request: { path: string; method: string; headers: Record<string, string> },\n route: { routerKind: \"App Router\"; routePath: string; routeType: \"action\" },\n) => void;\n\ntype AppServerActionDecoder = (body: FormData) => Promise<unknown>;\n\ntype ReadFormDataWithLimit = (request: Request, maxBytes: number) => Promise<FormData>;\n\ntype ReadBodyWithLimit = (request: Request, maxBytes: number) => Promise<string>;\n\ntype AppServerActionFunction = (...args: unknown[]) => unknown;\n\ntype AppServerActionReturnValue =\n | {\n data: unknown;\n ok: true;\n }\n | {\n data: unknown;\n ok: false;\n };\n\ntype AppServerActionRedirect = {\n status: number;\n type: string;\n url: string;\n};\n\ntype AppServerActionRoute = {\n pattern: string;\n};\n\ntype AppServerActionMatch<TRoute extends AppServerActionRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype AppServerActionIntercept<TPage = unknown> = {\n matchedParams: AppPageParams;\n page: TPage;\n slotKey: string;\n sourceRouteIndex: number;\n};\n\ntype BuildServerActionPageElementOptions<TRoute extends AppServerActionRoute, TInterceptOpts> = {\n cleanPathname: string;\n interceptOpts: TInterceptOpts | undefined;\n isRscRequest: boolean;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype AppServerActionRscModel<TElement> = {\n returnValue: AppServerActionReturnValue;\n root: TElement;\n};\n\ntype RenderServerActionRscStreamOptions<TTemporaryReferences> = {\n onError: (error: unknown) => unknown;\n temporaryReferences: TTemporaryReferences;\n};\n\ntype DecodeServerActionReplyOptions<TTemporaryReferences> = {\n temporaryReferences: TTemporaryReferences;\n};\n\nexport type HandleProgressiveServerActionRequestOptions = {\n actionId: string | null;\n allowedOrigins: string[];\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n decodeAction: AppServerActionDecoder;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n readFormDataWithLimit: ReadFormDataWithLimit;\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n};\n\nexport type HandleServerActionRscRequestOptions<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n> = {\n actionId: string | null;\n allowedOrigins: string[];\n buildPageElement: (\n options: BuildServerActionPageElementOptions<TRoute, TInterceptOpts>,\n ) => TElement;\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n createNotFoundElement: (routeId: string) => TElement;\n createPayloadRouteId: (pathname: string, interceptionContext: string | null) => string;\n createRscOnErrorHandler: (\n request: Request,\n pathname: string,\n pattern: string,\n ) => (error: unknown) => unknown;\n createTemporaryReferenceSet: () => TTemporaryReferences;\n decodeReply: (\n body: string | FormData,\n options: DecodeServerActionReplyOptions<TTemporaryReferences>,\n ) => Promise<unknown[]> | unknown[];\n findIntercept: (pathname: string) => AppServerActionIntercept<TPage> | null;\n getAndClearPendingCookies: () => string[];\n getDraftModeCookieHeader: () => string | null | undefined;\n getRouteParamNames: (route: TRoute) => readonly string[];\n getSourceRoute: (sourceRouteIndex: number) => TRoute | undefined;\n isRscRequest: boolean;\n loadServerAction: (actionId: string) => Promise<unknown>;\n matchRoute: (pathname: string) => AppServerActionMatch<TRoute> | null;\n maxActionBodySize: number;\n middlewareHeaders: Headers | null;\n middlewareStatus: number | null | undefined;\n mountedSlotsHeader: string | null;\n readBodyWithLimit: ReadBodyWithLimit;\n readFormDataWithLimit: ReadFormDataWithLimit;\n renderToReadableStream: (\n model: AppServerActionRscModel<TElement>,\n options: RenderServerActionRscStreamOptions<TTemporaryReferences>,\n ) => BodyInit | null | Promise<BodyInit | null>;\n reportRequestError: AppServerActionErrorReporter;\n resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;\n request: Request;\n sanitizeErrorForClient: (error: unknown) => unknown;\n searchParams: URLSearchParams;\n setHeadersAccessPhase: (phase: HeadersAccessPhase) => HeadersAccessPhase;\n setNavigationContext: (context: {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n }) => void;\n toInterceptOpts: (intercept: AppServerActionIntercept<TPage>) => TInterceptOpts;\n};\n\ntype ActionControlResponse =\n | {\n kind: \"redirect\";\n url: string;\n }\n | {\n kind: \"status\";\n statusCode: number;\n };\n\n/**\n * Matches Next.js' server action argument cap to prevent stack overflow in\n * Function.prototype.apply when decoding hostile action payloads.\n */\nconst SERVER_ACTION_ARGS_LIMIT = 1000;\n\nfunction isRequestBodyTooLarge(error: unknown): boolean {\n return error instanceof Error && error.message === \"Request body too large\";\n}\n\nfunction isAppServerActionFunction(action: unknown): action is AppServerActionFunction {\n return typeof action === \"function\";\n}\n\nfunction normalizeError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction getServerActionFailureMessage(error: unknown): string {\n return error instanceof Error && error.message ? error.message : String(error);\n}\n\nfunction validateServerActionArgs(args: readonly unknown[]): void {\n if (args.length > SERVER_ACTION_ARGS_LIMIT) {\n throw new Error(\n `Server Action arguments list is too long (${args.length}). Maximum allowed is ${SERVER_ACTION_ARGS_LIMIT}.`,\n );\n }\n}\n\nexport async function readActionBodyWithLimit(request: Request, maxBytes: number): Promise<string> {\n if (!request.body) return \"\";\n return readStreamAsTextWithLimit(request.body, maxBytes, () => {\n throw new Error(\"Request body too large\");\n });\n}\n\nexport async function readActionFormDataWithLimit(\n request: Request,\n maxBytes: number,\n): Promise<FormData> {\n if (!request.body) return new FormData();\n\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let totalSize = 0;\n\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n\n totalSize += result.value.byteLength;\n if (totalSize > maxBytes) {\n await reader.cancel();\n throw new Error(\"Request body too large\");\n }\n chunks.push(result.value);\n }\n\n const combined = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new Response(combined, {\n headers: { \"Content-Type\": request.headers.get(\"content-type\") || \"\" },\n }).formData();\n}\n\nfunction getActionControlResponse(error: unknown): ActionControlResponse | null {\n const digest = getNextErrorDigest(error);\n if (!digest) return null;\n\n const redirect = parseNextRedirectDigest(digest);\n if (redirect) {\n return {\n kind: \"redirect\",\n url: redirect.url,\n };\n }\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (httpError) {\n if (!Number.isInteger(httpError.status)) {\n return null;\n }\n\n return {\n kind: \"status\",\n statusCode: httpError.status,\n };\n }\n\n return null;\n}\n\nfunction getActionRedirect(error: unknown): AppServerActionRedirect | null {\n const digest = getNextErrorDigest(error);\n if (!digest) return null;\n\n const redirect = parseNextRedirectDigest(digest);\n if (!redirect) return null;\n\n return {\n status: redirect.status,\n type: redirect.type,\n url: redirect.url,\n };\n}\n\nfunction isActionHttpFallback(error: unknown): boolean {\n const digest = getNextErrorDigest(error);\n return digest !== null && parseNextHttpErrorDigest(digest) !== null;\n}\n\nfunction createServerActionErrorResponse(\n error: unknown,\n options: {\n cleanPathname: string;\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n reportRequestError: AppServerActionErrorReporter;\n request: Request;\n },\n): Response {\n options.getAndClearPendingCookies();\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return internalServerErrorResponse(\n process.env.NODE_ENV === \"production\"\n ? undefined\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n );\n}\n\nfunction createActionNotFoundResponse(\n actionId: string | null,\n options: {\n clearRequestContext: () => void;\n getAndClearPendingCookies: () => string[];\n },\n): Response {\n options.getAndClearPendingCookies();\n console.warn(getServerActionNotFoundMessage(actionId));\n options.clearRequestContext();\n return createServerActionNotFoundResponse();\n}\n\nexport function isProgressiveServerActionRequest(\n request: Pick<Request, \"method\">,\n contentType: string,\n actionId: string | null,\n): boolean {\n return (\n request.method.toUpperCase() === \"POST\" &&\n contentType.startsWith(\"multipart/form-data\") &&\n !actionId\n );\n}\n\nexport async function handleProgressiveServerActionRequest(\n options: HandleProgressiveServerActionRequestOptions,\n): Promise<Response | null> {\n if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) {\n return csrfResponse;\n }\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return payloadTooLargeResponse();\n }\n\n try {\n let body: FormData;\n try {\n // Progressive submissions can still fall through to a regular page render when\n // the multipart body is not an action payload. Read a clone so that fallback\n // code can still consume the original request body.\n body = await options.readFormDataWithLimit(\n options.request.clone(),\n options.maxActionBodySize,\n );\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return payloadTooLargeResponse();\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n const action = await options.decodeAction(body);\n if (typeof action !== \"function\") {\n return null;\n }\n\n let actionControlResponse: ActionControlResponse | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n await action();\n } catch (error) {\n actionControlResponse = getActionControlResponse(error);\n if (!actionControlResponse) {\n throw error;\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (!actionControlResponse) {\n // Next.js decodes form state and re-renders after a successful MPA action.\n // vinext currently supports the redirect/error status cases; successful\n // non-redirect actions intentionally fall through to the page render.\n return null;\n }\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n\n const headers = new Headers();\n if (actionControlResponse.kind === \"redirect\") {\n headers.set(\"Location\", new URL(actionControlResponse.url, options.request.url).toString());\n }\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);\n for (const cookie of actionPendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) {\n headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n\n return new Response(null, {\n status: actionControlResponse.kind === \"redirect\" ? 303 : actionControlResponse.statusCode,\n headers,\n });\n } catch (error) {\n if (isServerActionNotFoundError(error, null)) {\n return createActionNotFoundResponse(null, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n options.getAndClearPendingCookies();\n // Next.js rethrows generic MPA action errors into its page render path.\n // vinext does not yet implement that form-state render path, so unexpected\n // action failures remain request failures here.\n console.error(\"[vinext] Server action error:\", error);\n options.reportRequestError(\n normalizeError(error),\n {\n path: options.cleanPathname,\n method: options.request.method,\n headers: Object.fromEntries(options.request.headers.entries()),\n },\n { routerKind: \"App Router\", routePath: options.cleanPathname, routeType: \"action\" },\n );\n options.clearRequestContext();\n return internalServerErrorResponse(\n process.env.NODE_ENV === \"production\"\n ? undefined\n : \"Server action failed: \" + getServerActionFailureMessage(error),\n );\n }\n}\n\nexport async function handleServerActionRscRequest<\n TElement,\n TRoute extends AppServerActionRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage = unknown,\n>(\n options: HandleServerActionRscRequestOptions<\n TElement,\n TRoute,\n TInterceptOpts,\n TTemporaryReferences,\n TPage\n >,\n): Promise<Response | null> {\n if (options.request.method.toUpperCase() !== \"POST\" || !options.actionId) {\n return null;\n }\n\n const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);\n if (csrfResponse) return csrfResponse;\n\n const contentLength = parseInt(options.request.headers.get(\"content-length\") || \"0\", 10);\n if (contentLength > options.maxActionBodySize) {\n options.clearRequestContext();\n return payloadTooLargeResponse();\n }\n\n try {\n let body: string | FormData;\n try {\n body = options.contentType.startsWith(\"multipart/form-data\")\n ? await options.readFormDataWithLimit(options.request, options.maxActionBodySize)\n : await options.readBodyWithLimit(options.request, options.maxActionBodySize);\n } catch (error) {\n if (isRequestBodyTooLarge(error)) {\n options.clearRequestContext();\n return payloadTooLargeResponse();\n }\n throw error;\n }\n\n const payloadResponse = await validateServerActionPayload(body);\n if (payloadResponse) {\n options.clearRequestContext();\n return payloadResponse;\n }\n\n let action: unknown;\n try {\n action = await options.loadServerAction(options.actionId);\n } catch (error) {\n if (isServerActionNotFoundError(error, options.actionId)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n throw error;\n }\n\n if (!isAppServerActionFunction(action)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\n }\n\n const temporaryReferences = options.createTemporaryReferenceSet();\n const args = await options.decodeReply(body, { temporaryReferences });\n let returnValue: AppServerActionReturnValue;\n let actionRedirect: AppServerActionRedirect | null = null;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n try {\n validateServerActionArgs(args);\n const data = await action.apply(null, args);\n returnValue = { ok: true, data };\n } catch (error) {\n actionRedirect = getActionRedirect(error);\n if (actionRedirect) {\n returnValue = { ok: true, data: undefined };\n } else if (isActionHttpFallback(error)) {\n returnValue = { ok: false, data: error };\n } else {\n console.error(\"[vinext] Server action error:\", error);\n returnValue = { ok: false, data: options.sanitizeErrorForClient(error) };\n }\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (actionRedirect) {\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n options.clearRequestContext();\n const redirectHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);\n redirectHeaders.set(\"x-action-redirect\", actionRedirect.url);\n redirectHeaders.set(\"x-action-redirect-type\", actionRedirect.type);\n redirectHeaders.set(\"x-action-redirect-status\", String(actionRedirect.status));\n for (const cookie of actionPendingCookies) {\n redirectHeaders.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) redirectHeaders.append(\"Set-Cookie\", actionDraftCookie);\n return new Response(\"\", { status: 200, headers: redirectHeaders });\n }\n\n const match = options.matchRoute(options.cleanPathname);\n let element: TElement;\n let errorPattern = match ? match.route.pattern : options.cleanPathname;\n if (match) {\n const { route: actionRoute, params: actionParams } = match;\n const actionRerenderTarget = resolveAppPageActionRerenderTarget({\n cleanPathname: options.cleanPathname,\n currentParams: actionParams,\n currentRoute: actionRoute,\n findIntercept: options.findIntercept,\n getRouteParamNames: options.getRouteParamNames,\n getSourceRoute: options.getSourceRoute,\n isRscRequest: options.isRscRequest,\n toInterceptOpts: options.toInterceptOpts,\n });\n\n options.setNavigationContext({\n pathname: options.cleanPathname,\n searchParams: options.searchParams,\n params: actionRerenderTarget.navigationParams,\n });\n setCurrentFetchCacheMode(\n options.resolveRouteFetchCacheMode?.(actionRerenderTarget.route) ?? null,\n );\n element = options.buildPageElement({\n cleanPathname: options.cleanPathname,\n interceptOpts: actionRerenderTarget.interceptOpts,\n isRscRequest: options.isRscRequest,\n mountedSlotsHeader: options.mountedSlotsHeader,\n params: actionRerenderTarget.params,\n request: options.request,\n route: actionRerenderTarget.route,\n searchParams: options.searchParams,\n });\n errorPattern = actionRerenderTarget.route.pattern;\n } else {\n const actionRouteId = options.createPayloadRouteId(options.cleanPathname, null);\n element = options.createNotFoundElement(actionRouteId);\n }\n\n const onRenderError = options.createRscOnErrorHandler(\n options.request,\n options.cleanPathname,\n errorPattern,\n );\n const rscStream = await options.renderToReadableStream(\n { root: element, returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n\n const actionHeaders = new Headers({\n \"Content-Type\": \"text/x-component; charset=utf-8\",\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n const actionResponse = new Response(rscStream, {\n status: options.middlewareStatus ?? 200,\n headers: actionHeaders,\n });\n if (actionPendingCookies.length > 0 || actionDraftCookie) {\n for (const cookie of actionPendingCookies) {\n actionResponse.headers.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) actionResponse.headers.append(\"Set-Cookie\", actionDraftCookie);\n }\n return actionResponse;\n } catch (error) {\n return createServerActionErrorResponse(error, {\n cleanPathname: options.cleanPathname,\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n reportRequestError: options.reportRequestError,\n request: options.request,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
+
import { notFoundResponse } from "./http-error-responses.js";
|
|
1
2
|
import { isOpenRedirectShaped } from "./request-pipeline.js";
|
|
2
|
-
import {
|
|
3
|
+
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
|
+
import "./app-elements.js";
|
|
3
5
|
import { ServerInsertedHTMLContext, clearServerInsertedHTML, renderServerInsertedHTML, setNavigationContext, useServerInsertedHTML } from "../shims/navigation.js";
|
|
4
6
|
import { runWithNavigationContext } from "../shims/navigation-state.js";
|
|
5
7
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
6
8
|
import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
|
|
7
9
|
import { ElementsContext, Slot } from "../shims/slot.js";
|
|
10
|
+
import { createClientReferencePreloader } from "./app-client-reference-preloader.js";
|
|
8
11
|
import { deferUntilStreamConsumed } from "./app-page-stream.js";
|
|
9
12
|
import { createRscEmbedTransform, createTickBufferedTransform } from "./app-ssr-stream.js";
|
|
10
13
|
import { Fragment, createElement, use } from "react";
|
|
11
14
|
import { renderToReadableStream, renderToStaticMarkup } from "react-dom/server.edge";
|
|
12
15
|
import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr";
|
|
13
|
-
import
|
|
16
|
+
import clientReferences from "virtual:vite-rsc/client-references";
|
|
14
17
|
//#region src/server/app-ssr-entry.ts
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!refs || !clientRequire) return;
|
|
24
|
-
await Promise.all(Object.keys(refs).map((id) => clientRequire(id).catch((error) => {
|
|
18
|
+
const clientReferencePreloader = createClientReferencePreloader({
|
|
19
|
+
getReferences() {
|
|
20
|
+
return clientReferences;
|
|
21
|
+
},
|
|
22
|
+
getClientRequire() {
|
|
23
|
+
return globalThis.__vite_rsc_client_require__;
|
|
24
|
+
},
|
|
25
|
+
onPreloadError(id, error) {
|
|
25
26
|
if (process.env.NODE_ENV !== "production") console.warn("[vinext] failed to preload client ref:", id, error);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
29
|
function ssrErrorDigest(input) {
|
|
30
30
|
let hash = 5381;
|
|
31
31
|
for (let i = input.length - 1; i >= 0; i--) hash = hash * 33 ^ input.charCodeAt(i);
|
|
@@ -66,7 +66,7 @@ function buildHeadInjectionHtml(navContext, bootstrapScriptContent, insertedHTML
|
|
|
66
66
|
}
|
|
67
67
|
async function handleSsr(rscStream, navContext, fontData, options) {
|
|
68
68
|
return runWithNavigationContext(async () => {
|
|
69
|
-
await
|
|
69
|
+
await clientReferencePreloader.preload();
|
|
70
70
|
if (navContext) setNavigationContext(navContext);
|
|
71
71
|
clearServerInsertedHTML();
|
|
72
72
|
const cleanup = () => {
|
|
@@ -88,8 +88,9 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
88
88
|
let flightRoot = null;
|
|
89
89
|
function VinextFlightRoot() {
|
|
90
90
|
if (!flightRoot) flightRoot = createFromReadableStream(ssrStream);
|
|
91
|
-
const
|
|
92
|
-
const
|
|
91
|
+
const wireElements = use(flightRoot);
|
|
92
|
+
const elements = AppElementsWire.decode(wireElements);
|
|
93
|
+
const metadata = AppElementsWire.readMetadata(elements);
|
|
93
94
|
return createElement(ElementsContext.Provider, { value: elements }, createElement(Slot, { id: metadata.routeId }));
|
|
94
95
|
}
|
|
95
96
|
const root = createElement(VinextFlightRoot);
|
|
@@ -119,10 +120,10 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
122
|
var app_ssr_entry_default = { async fetch(request) {
|
|
122
|
-
if (isOpenRedirectShaped(new URL(request.url).pathname)) return
|
|
123
|
+
if (isOpenRedirectShaped(new URL(request.url).pathname)) return notFoundResponse();
|
|
123
124
|
const result = await (await import.meta.viteRsc.loadModule("rsc", "index")).default(request);
|
|
124
125
|
if (result instanceof Response) return result;
|
|
125
|
-
if (result == null) return
|
|
126
|
+
if (result == null) return notFoundResponse();
|
|
126
127
|
return new Response(String(result), { status: 200 });
|
|
127
128
|
} };
|
|
128
129
|
//#endregion
|
|
@@ -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 type { ReactNode } from \"react\";\nimport { Fragment, createElement as createReactElement, use } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport * as clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"vinext/shims/navigation\";\nimport {\n ServerInsertedHTMLContext,\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 { 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 {\n normalizeAppElements,\n readAppElementsMetadata,\n type AppWireElements,\n} from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"vinext/shims/slot\";\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\ntype ClientRequire = (id: string) => Promise<unknown>;\n\nlet clientRefsPreloaded = false;\n\nfunction getClientReferenceRequire(): ClientRequire | undefined {\n return (\n globalThis as typeof globalThis & {\n __vite_rsc_client_require__?: ClientRequire;\n }\n ).__vite_rsc_client_require__;\n}\n\nasync function preloadClientReferences(): Promise<void> {\n if (clientRefsPreloaded) return;\n\n const refs = (clientReferences as { default?: Record<string, unknown> }).default;\n const clientRequire = getClientReferenceRequire();\n if (!refs || !clientRequire) return;\n\n await Promise.all(\n Object.keys(refs).map((id) =>\n clientRequire(id).catch((error) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n }),\n ),\n );\n\n clientRefsPreloaded = true;\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\nfunction extractModulePreloadHtml(bootstrapScriptContent?: string, nonce?: string): string {\n if (!bootstrapScriptContent) return \"\";\n\n const match = bootstrapScriptContent.match(/import\\(\"([^\"]+)\"\\)/);\n if (!match?.[1]) return \"\";\n\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(match[1])}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapScriptContent: string | undefined,\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\n return (\n paramsScript +\n navScript +\n extractModulePreloadHtml(bootstrapScriptContent, 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 },\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await preloadClientReferences();\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 = normalizeAppElements(wireElements);\n const metadata = readAppElementsMetadata(elements);\n return createReactElement(\n ElementsContext.Provider,\n { value: elements },\n createReactElement(Slot, { id: metadata.routeId }),\n );\n }\n\n const root = createReactElement(VinextFlightRoot);\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 const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\"index\");\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n bootstrapScriptContent,\n nonce: options?.scriptNonce,\n onError(error) {\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 const fontHTML = renderFontHtml(fontData, options?.scriptNonce);\n let didInjectHeadHTML = false;\n const getInsertedHTML = (): string => {\n const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());\n if (didInjectHeadHTML) return insertedHTML;\n\n didInjectHeadHTML = true;\n return buildHeadInjectionHtml(\n navContext,\n bootstrapScriptContent,\n insertedHTML,\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 new Response(\"404 Not Found\", { status: 404 });\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 new Response(\"Not Found\", { status: 404 });\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport type { ReactNode } from \"react\";\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 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 { AppElementsWire, type AppWireElements } from \"./app-elements.js\";\nimport { ElementsContext, Slot } from \"vinext/shims/slot\";\nimport { createClientReferencePreloader } from \"./app-client-reference-preloader.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\nfunction extractModulePreloadHtml(bootstrapScriptContent?: string, nonce?: string): string {\n if (!bootstrapScriptContent) return \"\";\n\n const match = bootstrapScriptContent.match(/import\\(\"([^\"]+)\"\\)/);\n if (!match?.[1]) return \"\";\n\n return `<link rel=\"modulepreload\"${createNonceAttribute(nonce)} href=\"${escapeHtmlAttr(match[1])}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapScriptContent: string | undefined,\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\n return (\n paramsScript +\n navScript +\n extractModulePreloadHtml(bootstrapScriptContent, 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 },\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 root = createReactElement(VinextFlightRoot);\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 const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\"index\");\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n bootstrapScriptContent,\n nonce: options?.scriptNonce,\n onError(error) {\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 const fontHTML = renderFontHtml(fontData, options?.scriptNonce);\n let didInjectHeadHTML = false;\n const getInsertedHTML = (): string => {\n const insertedHTML = renderInsertedHtml(renderServerInsertedHTML());\n if (didInjectHeadHTML) return insertedHTML;\n\n didInjectHeadHTML = true;\n return buildHeadInjectionHtml(\n navContext,\n bootstrapScriptContent,\n insertedHTML,\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":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/server/artifact-compatibility.d.ts
|
|
2
|
+
declare const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;
|
|
3
|
+
declare const APP_ELEMENTS_SCHEMA_VERSION = 1;
|
|
4
|
+
declare const RSC_PAYLOAD_SCHEMA_VERSION = 1;
|
|
5
|
+
type ArtifactCompatibilityEnvelope = Readonly<{
|
|
6
|
+
schemaVersion: typeof ARTIFACT_COMPATIBILITY_SCHEMA_VERSION;
|
|
7
|
+
graphVersion: string | null;
|
|
8
|
+
deploymentVersion: string | null;
|
|
9
|
+
appElementsSchemaVersion: typeof APP_ELEMENTS_SCHEMA_VERSION;
|
|
10
|
+
rscPayloadSchemaVersion: typeof RSC_PAYLOAD_SCHEMA_VERSION;
|
|
11
|
+
rootBoundaryId: string | null;
|
|
12
|
+
renderEpoch: string | null;
|
|
13
|
+
}>;
|
|
14
|
+
type ArtifactCompatibilityEnvelopeInput = Readonly<{
|
|
15
|
+
graphVersion?: string | null;
|
|
16
|
+
deploymentVersion?: string | null;
|
|
17
|
+
rootBoundaryId?: string | null;
|
|
18
|
+
renderEpoch?: string | null;
|
|
19
|
+
}>;
|
|
20
|
+
type ArtifactCompatibilityFallback = "renderFresh";
|
|
21
|
+
type ArtifactCompatibilityUnknownReason = "graphVersionUnknown" | "deploymentVersionUnknown" | "rootBoundaryIdUnknown" | "renderEpochUnknown";
|
|
22
|
+
type ArtifactCompatibilityIncompatibleReason = "appElementsSchemaVersionMismatch" | "deploymentVersionMismatch" | "graphVersionMismatch" | "renderEpochMismatch" | "rootBoundaryIdMismatch" | "rscPayloadSchemaVersionMismatch" | "schemaVersionMismatch";
|
|
23
|
+
type ArtifactCompatibilityDecision = Readonly<{
|
|
24
|
+
kind: "compatible";
|
|
25
|
+
} | {
|
|
26
|
+
kind: "unknown";
|
|
27
|
+
fallback: ArtifactCompatibilityFallback;
|
|
28
|
+
reason: ArtifactCompatibilityUnknownReason;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "incompatible";
|
|
31
|
+
fallback: ArtifactCompatibilityFallback;
|
|
32
|
+
reason: ArtifactCompatibilityIncompatibleReason;
|
|
33
|
+
}>;
|
|
34
|
+
type ArtifactCompatibilityGraphVersionInput = Readonly<{
|
|
35
|
+
routePattern: string;
|
|
36
|
+
rootBoundaryId: string | null;
|
|
37
|
+
}>;
|
|
38
|
+
declare function createArtifactCompatibilityEnvelope(input?: ArtifactCompatibilityEnvelopeInput): ArtifactCompatibilityEnvelope;
|
|
39
|
+
declare function createArtifactCompatibilityGraphVersion(input: ArtifactCompatibilityGraphVersionInput): string;
|
|
40
|
+
declare function parseArtifactCompatibilityEnvelope(value: unknown): ArtifactCompatibilityEnvelope | null;
|
|
41
|
+
declare function evaluateArtifactCompatibility(current: ArtifactCompatibilityEnvelope, candidate: ArtifactCompatibilityEnvelope): ArtifactCompatibilityDecision;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, ArtifactCompatibilityEnvelope, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
|
|
44
|
+
//# sourceMappingURL=artifact-compatibility.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { fnv1a64 } from "../utils/hash.js";
|
|
2
|
+
//#region src/server/artifact-compatibility.ts
|
|
3
|
+
const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;
|
|
4
|
+
const APP_ELEMENTS_SCHEMA_VERSION = 1;
|
|
5
|
+
const RSC_PAYLOAD_SCHEMA_VERSION = 1;
|
|
6
|
+
function createArtifactCompatibilityEnvelope(input = {}) {
|
|
7
|
+
return {
|
|
8
|
+
schemaVersion: 1,
|
|
9
|
+
graphVersion: input.graphVersion ?? null,
|
|
10
|
+
deploymentVersion: input.deploymentVersion ?? null,
|
|
11
|
+
appElementsSchemaVersion: 1,
|
|
12
|
+
rscPayloadSchemaVersion: 1,
|
|
13
|
+
rootBoundaryId: input.rootBoundaryId ?? null,
|
|
14
|
+
renderEpoch: input.renderEpoch ?? null
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function createArtifactCompatibilityGraphVersion(input) {
|
|
18
|
+
return `app-route-graph:${fnv1a64(JSON.stringify([input.routePattern, input.rootBoundaryId]))}`;
|
|
19
|
+
}
|
|
20
|
+
function isRecord(value) {
|
|
21
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
}
|
|
23
|
+
function isStringOrNull(value) {
|
|
24
|
+
return typeof value === "string" || value === null;
|
|
25
|
+
}
|
|
26
|
+
function hasCurrentSchemaVersions(record) {
|
|
27
|
+
return record.schemaVersion === 1 && record.appElementsSchemaVersion === 1 && record.rscPayloadSchemaVersion === 1;
|
|
28
|
+
}
|
|
29
|
+
function parseArtifactCompatibilityEnvelope(value) {
|
|
30
|
+
if (!isRecord(value)) return null;
|
|
31
|
+
if (!hasCurrentSchemaVersions(value)) return null;
|
|
32
|
+
if (!isStringOrNull(value.graphVersion)) return null;
|
|
33
|
+
if (!isStringOrNull(value.deploymentVersion)) return null;
|
|
34
|
+
if (!isStringOrNull(value.rootBoundaryId)) return null;
|
|
35
|
+
if (!isStringOrNull(value.renderEpoch)) return null;
|
|
36
|
+
return {
|
|
37
|
+
schemaVersion: 1,
|
|
38
|
+
graphVersion: value.graphVersion,
|
|
39
|
+
deploymentVersion: value.deploymentVersion,
|
|
40
|
+
appElementsSchemaVersion: 1,
|
|
41
|
+
rscPayloadSchemaVersion: 1,
|
|
42
|
+
rootBoundaryId: value.rootBoundaryId,
|
|
43
|
+
renderEpoch: value.renderEpoch
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function incompatible(reason) {
|
|
47
|
+
return {
|
|
48
|
+
kind: "incompatible",
|
|
49
|
+
fallback: "renderFresh",
|
|
50
|
+
reason
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function unknown(reason) {
|
|
54
|
+
return {
|
|
55
|
+
kind: "unknown",
|
|
56
|
+
fallback: "renderFresh",
|
|
57
|
+
reason
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function compareKnownField(currentValue, candidateValue, unknownReason, mismatchReason) {
|
|
61
|
+
if (currentValue === null || candidateValue === null) return unknown(unknownReason);
|
|
62
|
+
if (currentValue !== candidateValue) return incompatible(mismatchReason);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function evaluateArtifactCompatibility(current, candidate) {
|
|
66
|
+
if (current.schemaVersion !== candidate.schemaVersion) return incompatible("schemaVersionMismatch");
|
|
67
|
+
if (current.appElementsSchemaVersion !== candidate.appElementsSchemaVersion) return incompatible("appElementsSchemaVersionMismatch");
|
|
68
|
+
if (current.rscPayloadSchemaVersion !== candidate.rscPayloadSchemaVersion) return incompatible("rscPayloadSchemaVersionMismatch");
|
|
69
|
+
const graphDecision = compareKnownField(current.graphVersion, candidate.graphVersion, "graphVersionUnknown", "graphVersionMismatch");
|
|
70
|
+
if (graphDecision) return graphDecision;
|
|
71
|
+
const deploymentDecision = compareKnownField(current.deploymentVersion, candidate.deploymentVersion, "deploymentVersionUnknown", "deploymentVersionMismatch");
|
|
72
|
+
if (deploymentDecision) return deploymentDecision;
|
|
73
|
+
const rootBoundaryDecision = compareKnownField(current.rootBoundaryId, candidate.rootBoundaryId, "rootBoundaryIdUnknown", "rootBoundaryIdMismatch");
|
|
74
|
+
if (rootBoundaryDecision) return rootBoundaryDecision;
|
|
75
|
+
const renderEpochDecision = compareKnownField(current.renderEpoch, candidate.renderEpoch, "renderEpochUnknown", "renderEpochMismatch");
|
|
76
|
+
if (renderEpochDecision) return renderEpochDecision;
|
|
77
|
+
return { kind: "compatible" };
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=artifact-compatibility.js.map
|
|
@@ -0,0 +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 ArtifactCompatibilityFallback = \"renderFresh\";\n\ntype ArtifactCompatibilityUnknownReason =\n | \"graphVersionUnknown\"\n | \"deploymentVersionUnknown\"\n | \"rootBoundaryIdUnknown\"\n | \"renderEpochUnknown\";\n\ntype ArtifactCompatibilityIncompatibleReason =\n | \"appElementsSchemaVersionMismatch\"\n | \"deploymentVersionMismatch\"\n | \"graphVersionMismatch\"\n | \"renderEpochMismatch\"\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): ArtifactCompatibilityDecision | null {\n if (currentValue === null || candidateValue === null) {\n return unknown(unknownReason);\n }\n if (currentValue !== candidateValue) {\n return incompatible(mismatchReason);\n }\n return null;\n}\n\nexport function evaluateArtifactCompatibility(\n current: ArtifactCompatibilityEnvelope,\n candidate: ArtifactCompatibilityEnvelope,\n): ArtifactCompatibilityDecision {\n // Pre-positioned for #726-COMPAT-04/05, where cache and visited-response\n // reuse paths will compare the current render proof with a candidate payload.\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 );\n if (graphDecision) return graphDecision;\n\n const deploymentDecision = compareKnownField(\n current.deploymentVersion,\n candidate.deploymentVersion,\n \"deploymentVersionUnknown\",\n \"deploymentVersionMismatch\",\n );\n if (deploymentDecision) return deploymentDecision;\n\n const rootBoundaryDecision = compareKnownField(\n current.rootBoundaryId,\n candidate.rootBoundaryId,\n \"rootBoundaryIdUnknown\",\n \"rootBoundaryIdMismatch\",\n );\n if (rootBoundaryDecision) return rootBoundaryDecision;\n\n const renderEpochDecision = compareKnownField(\n current.renderEpoch,\n candidate.renderEpoch,\n \"renderEpochUnknown\",\n \"renderEpochMismatch\",\n );\n if (renderEpochDecision) return renderEpochDecision;\n\n return { kind: \"compatible\" };\n}\n"],"mappings":";;AAEA,MAAa,wCAAwC;AAKrD,MAAa,8BAA8B;AAC3C,MAAa,6BAA6B;AAuD1C,SAAgB,oCACd,QAA4C,EAAE,EACf;AAC/B,QAAO;EACL,eAAA;EACA,cAAc,MAAM,gBAAgB;EACpC,mBAAmB,MAAM,qBAAqB;EAC9C,0BAAA;EACA,yBAAA;EACA,gBAAgB,MAAM,kBAAkB;EACxC,aAAa,MAAM,eAAe;EACnC;;AAGH,SAAgB,wCACd,OACQ;AAER,QAAO,mBADa,QAAQ,KAAK,UAAU,CAAC,MAAM,cAAc,MAAM,eAAe,CAAC,CAAC;;AAIzF,SAAS,SAAS,OAA4D;AAC5E,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG7E,SAAS,eAAe,OAAwC;AAC9D,QAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,yBAAyB,QAAoD;AACpF,QACE,OAAO,kBAAA,KACP,OAAO,6BAAA,KACP,OAAO,4BAAA;;AAIX,SAAgB,mCACd,OACsC;AACtC,KAAI,CAAC,SAAS,MAAM,CAAE,QAAO;AAI7B,KAAI,CAAC,yBAAyB,MAAM,CAAE,QAAO;AAC7C,KAAI,CAAC,eAAe,MAAM,aAAa,CAAE,QAAO;AAChD,KAAI,CAAC,eAAe,MAAM,kBAAkB,CAAE,QAAO;AACrD,KAAI,CAAC,eAAe,MAAM,eAAe,CAAE,QAAO;AAClD,KAAI,CAAC,eAAe,MAAM,YAAY,CAAE,QAAO;AAK/C,QAAO;EACL,eAAA;EACA,cAAc,MAAM;EACpB,mBAAmB,MAAM;EACzB,0BAAA;EACA,yBAAA;EACA,gBAAgB,MAAM;EACtB,aAAa,MAAM;EACpB;;AAGH,SAAS,aACP,QAC+B;AAC/B,QAAO;EAAE,MAAM;EAAgB,UAAU;EAAe;EAAQ;;AAGlE,SAAS,QAAQ,QAA2E;AAC1F,QAAO;EAAE,MAAM;EAAW,UAAU;EAAe;EAAQ;;AAG7D,SAAS,kBACP,cACA,gBACA,eACA,gBACsC;AACtC,KAAI,iBAAiB,QAAQ,mBAAmB,KAC9C,QAAO,QAAQ,cAAc;AAE/B,KAAI,iBAAiB,eACnB,QAAO,aAAa,eAAe;AAErC,QAAO;;AAGT,SAAgB,8BACd,SACA,WAC+B;AAG/B,KAAI,QAAQ,kBAAkB,UAAU,cACtC,QAAO,aAAa,wBAAwB;AAE9C,KAAI,QAAQ,6BAA6B,UAAU,yBACjD,QAAO,aAAa,mCAAmC;AAEzD,KAAI,QAAQ,4BAA4B,UAAU,wBAChD,QAAO,aAAa,kCAAkC;CAGxD,MAAM,gBAAgB,kBACpB,QAAQ,cACR,UAAU,cACV,uBACA,uBACD;AACD,KAAI,cAAe,QAAO;CAE1B,MAAM,qBAAqB,kBACzB,QAAQ,mBACR,UAAU,mBACV,4BACA,4BACD;AACD,KAAI,mBAAoB,QAAO;CAE/B,MAAM,uBAAuB,kBAC3B,QAAQ,gBACR,UAAU,gBACV,yBACA,yBACD;AACD,KAAI,qBAAsB,QAAO;CAEjC,MAAM,sBAAsB,kBAC1B,QAAQ,aACR,UAAU,aACV,sBACA,sBACD;AACD,KAAI,oBAAqB,QAAO;AAEhC,QAAO,EAAE,MAAM,cAAc"}
|