vinext 0.0.54 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +1 -0
  2. package/dist/check.js +15 -3
  3. package/dist/check.js.map +1 -1
  4. package/dist/client/navigation-runtime.d.ts +1 -0
  5. package/dist/client/navigation-runtime.js +1 -1
  6. package/dist/client/navigation-runtime.js.map +1 -1
  7. package/dist/config/next-config.d.ts +14 -1
  8. package/dist/config/next-config.js +24 -4
  9. package/dist/config/next-config.js.map +1 -1
  10. package/dist/config/tsconfig-paths.d.ts +12 -3
  11. package/dist/config/tsconfig-paths.js +55 -24
  12. package/dist/config/tsconfig-paths.js.map +1 -1
  13. package/dist/entries/app-rsc-entry.d.ts +2 -1
  14. package/dist/entries/app-rsc-entry.js +12 -0
  15. package/dist/entries/app-rsc-entry.js.map +1 -1
  16. package/dist/entries/app-rsc-manifest.js +22 -5
  17. package/dist/entries/app-rsc-manifest.js.map +1 -1
  18. package/dist/entries/pages-server-entry.js +41 -4
  19. package/dist/entries/pages-server-entry.js.map +1 -1
  20. package/dist/index.js +81 -39
  21. package/dist/index.js.map +1 -1
  22. package/dist/plugins/import-meta-url.d.ts +16 -0
  23. package/dist/plugins/import-meta-url.js +193 -0
  24. package/dist/plugins/import-meta-url.js.map +1 -0
  25. package/dist/server/app-browser-action-result.d.ts +9 -16
  26. package/dist/server/app-browser-action-result.js +25 -14
  27. package/dist/server/app-browser-action-result.js.map +1 -1
  28. package/dist/server/app-browser-entry.js +171 -45
  29. package/dist/server/app-browser-entry.js.map +1 -1
  30. package/dist/server/app-browser-mpa-navigation.d.ts +16 -0
  31. package/dist/server/app-browser-mpa-navigation.js +36 -0
  32. package/dist/server/app-browser-mpa-navigation.js.map +1 -0
  33. package/dist/server/app-browser-popstate.d.ts +3 -1
  34. package/dist/server/app-browser-popstate.js +15 -1
  35. package/dist/server/app-browser-popstate.js.map +1 -1
  36. package/dist/server/app-browser-state.js +2 -1
  37. package/dist/server/app-browser-state.js.map +1 -1
  38. package/dist/server/app-layout-param-observation.d.ts +30 -0
  39. package/dist/server/app-layout-param-observation.js +130 -0
  40. package/dist/server/app-layout-param-observation.js.map +1 -0
  41. package/dist/server/app-page-boundary-render.js +2 -2
  42. package/dist/server/app-page-boundary-render.js.map +1 -1
  43. package/dist/server/app-page-dispatch.js +1 -1
  44. package/dist/server/app-page-params.d.ts +2 -1
  45. package/dist/server/app-page-params.js +14 -1
  46. package/dist/server/app-page-params.js.map +1 -1
  47. package/dist/server/app-page-probe.d.ts +12 -1
  48. package/dist/server/app-page-probe.js +116 -1
  49. package/dist/server/app-page-probe.js.map +1 -1
  50. package/dist/server/app-route-handler-response.js +1 -1
  51. package/dist/server/app-route-handler-response.js.map +1 -1
  52. package/dist/server/app-rsc-cache-busting.d.ts +3 -2
  53. package/dist/server/app-rsc-cache-busting.js +9 -7
  54. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  55. package/dist/server/app-rsc-handler.js +11 -1
  56. package/dist/server/app-rsc-handler.js.map +1 -1
  57. package/dist/server/app-segment-config.d.ts +1 -1
  58. package/dist/server/app-segment-config.js +4 -1
  59. package/dist/server/app-segment-config.js.map +1 -1
  60. package/dist/server/app-server-action-execution.d.ts +5 -0
  61. package/dist/server/app-server-action-execution.js +198 -22
  62. package/dist/server/app-server-action-execution.js.map +1 -1
  63. package/dist/server/artifact-compatibility.d.ts +2 -1
  64. package/dist/server/artifact-compatibility.js +10 -1
  65. package/dist/server/artifact-compatibility.js.map +1 -1
  66. package/dist/server/client-reuse-manifest.d.ts +9 -4
  67. package/dist/server/client-reuse-manifest.js +2 -1
  68. package/dist/server/client-reuse-manifest.js.map +1 -1
  69. package/dist/server/dev-server.js +52 -10
  70. package/dist/server/dev-server.js.map +1 -1
  71. package/dist/server/document-initial-head.d.ts +7 -0
  72. package/dist/server/document-initial-head.js +35 -0
  73. package/dist/server/document-initial-head.js.map +1 -0
  74. package/dist/server/pages-document-initial-props.d.ts +84 -2
  75. package/dist/server/pages-document-initial-props.js +127 -1
  76. package/dist/server/pages-document-initial-props.js.map +1 -1
  77. package/dist/server/pages-node-compat.js +1 -1
  78. package/dist/server/pages-page-response.d.ts +14 -0
  79. package/dist/server/pages-page-response.js +31 -8
  80. package/dist/server/pages-page-response.js.map +1 -1
  81. package/dist/server/prod-server.js +13 -6
  82. package/dist/server/prod-server.js.map +1 -1
  83. package/dist/server/skip-cache-proof.d.ts +23 -2
  84. package/dist/server/skip-cache-proof.js +81 -12
  85. package/dist/server/skip-cache-proof.js.map +1 -1
  86. package/dist/server/static-layout-client-reuse-proof.d.ts +16 -0
  87. package/dist/server/static-layout-client-reuse-proof.js +35 -0
  88. package/dist/server/static-layout-client-reuse-proof.js.map +1 -0
  89. package/dist/shims/cache.d.ts +21 -1
  90. package/dist/shims/cache.js +101 -6
  91. package/dist/shims/cache.js.map +1 -1
  92. package/dist/shims/document.d.ts +6 -0
  93. package/dist/shims/document.js +7 -8
  94. package/dist/shims/document.js.map +1 -1
  95. package/dist/shims/error-boundary.d.ts +4 -4
  96. package/dist/shims/error-boundary.js +27 -28
  97. package/dist/shims/error-boundary.js.map +1 -1
  98. package/dist/shims/fetch-cache.d.ts +3 -1
  99. package/dist/shims/fetch-cache.js +16 -5
  100. package/dist/shims/fetch-cache.js.map +1 -1
  101. package/dist/shims/hash-scroll.d.ts +4 -1
  102. package/dist/shims/hash-scroll.js +13 -1
  103. package/dist/shims/hash-scroll.js.map +1 -1
  104. package/dist/shims/head-state.d.ts +1 -0
  105. package/dist/shims/head-state.js +18 -3
  106. package/dist/shims/head-state.js.map +1 -1
  107. package/dist/shims/head.d.ts +35 -1
  108. package/dist/shims/head.js +113 -14
  109. package/dist/shims/head.js.map +1 -1
  110. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +56 -0
  111. package/dist/shims/internal/pages-data-fetch-dedup.js +70 -0
  112. package/dist/shims/internal/pages-data-fetch-dedup.js.map +1 -0
  113. package/dist/shims/link.js +28 -2
  114. package/dist/shims/link.js.map +1 -1
  115. package/dist/shims/navigation.d.ts +39 -1
  116. package/dist/shims/navigation.js +61 -13
  117. package/dist/shims/navigation.js.map +1 -1
  118. package/dist/shims/router.js +37 -17
  119. package/dist/shims/router.js.map +1 -1
  120. package/dist/shims/thenable-params.d.ts +5 -2
  121. package/dist/shims/thenable-params.js +25 -1
  122. package/dist/shims/thenable-params.js.map +1 -1
  123. package/dist/shims/unified-request-context.js +3 -0
  124. package/dist/shims/unified-request-context.js.map +1 -1
  125. package/dist/utils/client-build-manifest.d.ts +15 -0
  126. package/dist/utils/client-build-manifest.js +54 -0
  127. package/dist/utils/client-build-manifest.js.map +1 -0
  128. package/dist/utils/hash.js +1 -1
  129. package/dist/utils/hash.js.map +1 -1
  130. package/dist/utils/lazy-chunks.d.ts +1 -1
  131. package/dist/utils/lazy-chunks.js.map +1 -1
  132. package/dist/utils/vite-version.d.ts +11 -0
  133. package/dist/utils/vite-version.js +36 -0
  134. package/dist/utils/vite-version.js.map +1 -0
  135. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"app-server-action-execution.js","names":[],"sources":["../../src/server/app-server-action-execution.ts"],"sourcesContent":["import { getAndClearActionRevalidationKind, type ActionRevalidationKind } from \"vinext/shims/cache\";\nimport type { HeadersAccessPhase } from \"vinext/shims/headers\";\nimport { type FetchCacheMode, setCurrentFetchCacheMode } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { isExternalUrl } from \"../config/config-matchers.js\";\nimport { addBasePathToPathname, hasBasePath } from \"../utils/base-path.js\";\nimport {\n ACTION_FORWARDED_HEADER,\n ACTION_REDIRECT_HEADER,\n ACTION_REDIRECT_STATUS_HEADER,\n ACTION_REDIRECT_TYPE_HEADER,\n ACTION_REVALIDATED_HEADER,\n} from \"./headers.js\";\nimport {\n VINEXT_RSC_CONTENT_TYPE,\n VINEXT_RSC_VARY_HEADER,\n applyRscCompatibilityIdHeader,\n} from \"./app-rsc-cache-busting.js\";\nimport { applyEdgeRuntimeHeader } from \"./app-page-response.js\";\nimport { resolveAppPageActionRerenderTarget } from \"./app-page-request.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { getSetCookieName } from \"./cookie-utils.js\";\nimport {\n APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.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>;\ntype AppServerActionFormStateDecoder = (\n actionResult: unknown,\n body: FormData,\n) => Promise<ReactFormState | undefined>;\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\n/**\n * Side-effect headers captured during a progressive (no-JS) server action's\n * non-redirect execution. The caller (app-rsc-handler) must apply these to the\n * page render response so that `cookies().set(...)` and revalidation kinds\n * propagate to the browser. Without this, no-JS form submissions silently\n * lose cookie/header mutations — see issue #1483.\n *\n * Next.js' equivalent path mutates `res.setHeader('set-cookie', ...)` during\n * action execution (action-handler.ts → app-render.tsx), then `sendResponse`\n * merges those headers with the rendered Response. vinext works with Response\n * objects directly so the cookies must ride out via the result instead.\n */\ntype ProgressiveServerActionSideEffects = {\n /** `Set-Cookie` headers from `cookies().set(...)` / `cookies().delete(...)`. */\n pendingCookies: string[];\n /** `Set-Cookie` header from `draftMode().enable()/disable()` (if any). */\n draftCookie: string | null | undefined;\n /** Resolved revalidation kind to emit via `x-action-revalidated`. */\n revalidationKind: ActionRevalidationKind;\n};\n\ntype ProgressiveServerActionResult =\n | ({\n formState: ReactFormState | null;\n kind: \"form-state\";\n } & ProgressiveServerActionSideEffects)\n | ({\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n } & ProgressiveServerActionSideEffects);\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 slotId?: string | null;\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 renderMode: AppRscRenderMode;\n};\n\ntype AppServerActionRscModel<TElement> = {\n /**\n * Omitted when the action did not invalidate page data. This mirrors Next.js'\n * empty Flight payload for non-revalidating fetch actions: the client resolves\n * the action value without committing a visible router update.\n */\n root?: TElement;\n returnValue: AppServerActionReturnValue;\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 /** Configured next.config `basePath`. Prefixed onto progressive Location targets. */\n basePath?: string;\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n decodeAction: AppServerActionDecoder;\n decodeFormState: AppServerActionFormStateDecoder;\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 /** Configured next.config `basePath`. Prefixed onto ACTION_REDIRECT_HEADER targets. */\n basePath?: 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 isEdgeRuntime?: boolean;\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\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;\nconst ACTION_DID_NOT_REVALIDATE = 0 satisfies ActionRevalidationKind;\nconst ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1 satisfies ActionRevalidationKind;\n\nfunction setActionRevalidatedHeader(headers: Headers, kind: ActionRevalidationKind): void {\n if (kind === ACTION_DID_NOT_REVALIDATE) return;\n headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(kind));\n}\n\nfunction resolveActionRevalidationKind(hasModifiedCookies: boolean): ActionRevalidationKind {\n const revalidationKind = getAndClearActionRevalidationKind();\n // Cookie mutations are a hard override to STATIC_AND_DYNAMIC: any cookie\n // change can invalidate downstream cached payloads regardless of what\n // (if anything) the action explicitly revalidated, so we always emit the\n // strongest kind. STATIC_AND_DYNAMIC is also the lowest numeric value, so\n // this matches the max-precedence semantics in markActionRevalidation.\n if (hasModifiedCookies) return ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC;\n return revalidationKind;\n}\n\nfunction isRequestBodyTooLarge(error: unknown): boolean {\n return error instanceof Error && error.message === \"Request body too large\";\n}\n\n/**\n * Collapse repeated `cookies().set(name, ...)` / `cookies().delete(name)`\n * calls down to the last value per name, matching Next.js'\n * `MutableRequestCookiesAdapter` semantics. Next.js stores response cookies in\n * a `ResponseCookies` Map keyed by name — multiple sets for the same cookie\n * collapse to the final value, and emit a single Set-Cookie header.\n *\n * Insertion order is preserved by first occurrence (Map iteration order),\n * which mirrors how `ResponseCookies` iterates its underlying Map. See\n * packages/next/src/server/web/spec-extension/adapters/request-cookies.ts.\n * Issue: https://github.com/cloudflare/vinext/issues/1481\n */\nfunction dedupePendingCookies(cookies: readonly string[]): string[] {\n if (cookies.length <= 1) {\n return cookies.slice();\n }\n const byName = new Map<string, string>();\n const unkeyed: string[] = [];\n for (const cookie of cookies) {\n const name = getSetCookieName(cookie);\n if (name === null) {\n unkeyed.push(cookie);\n continue;\n }\n // Map.set on an existing key replaces the value but preserves the\n // insertion position of the original key — exactly the behaviour we need\n // for `cookies().set(\"foo\", \"1\"); cookies().set(\"bar\", \"2\"); cookies().set(\"foo\", \"3\")`\n // to come out as [foo=3, bar=2].\n byName.set(name, cookie);\n }\n return [...unkeyed, ...byName.values()];\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 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 ?? \"push\",\n url: redirect.url,\n };\n}\n\n/**\n * Prepend the configured next.config `basePath` to a server-action redirect\n * target before it goes on the wire.\n *\n * `redirect(\"/foo\")` called from a server action mounted at `/base/...` must\n * land the browser at `/base/foo`, mirroring how Next.js threads basePath\n * through `addPathPrefix(getURLFromRedirectError(err), basePath)` in\n * `app-render.tsx` for SSR redirects and in `action-handler.ts` for action\n * redirects.\n *\n * Idempotent and external-aware:\n * - Empty basePath → returned unchanged.\n * - External URLs (`http://`, `https://`, `data:`, protocol-relative `//`)\n * are returned unchanged because the framework does not own those routes.\n * - Targets that already start with the configured basePath are returned\n * unchanged so this helper can be applied at any layer without risk of\n * double-prefixing (`/base/base/foo`).\n *\n * Exported for tests. Used by both the progressive (no-JS form POST) and\n * RSC (`ACTION_REDIRECT_HEADER`) action redirect paths below.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/action-handler.ts\n */\nexport function applyActionRedirectBasePath(url: string, basePath: string): string {\n if (!basePath) return url;\n if (isExternalUrl(url)) return url;\n // Pathnames that already include basePath are returned as-is.\n if (hasBasePath(url, basePath)) return url;\n // Relative or hash/query-only targets cannot be prefixed safely without an\n // origin; leave them to the caller's URL resolution.\n if (!url.startsWith(\"/\")) return url;\n // Split off optional query+hash so addBasePathToPathname only operates on\n // the path. We must accept hash too because Next.js redirect targets may\n // contain \"#anchor\".\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const splitAt =\n queryIndex === -1 ? hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);\n const pathname = splitAt === -1 ? url : url.slice(0, splitAt);\n const suffix = splitAt === -1 ? \"\" : url.slice(splitAt);\n return `${addBasePathToPathname(pathname, basePath)}${suffix}`;\n}\n\nfunction getActionHttpFallbackStatus(error: unknown): number | null {\n const digest = getNextErrorDigest(error);\n if (!digest) return null;\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (!httpError || !Number.isInteger(httpError.status)) return null;\n\n return httpError.status;\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 | ProgressiveServerActionResult | null> {\n if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) {\n return null;\n }\n\n // Defensive guard: prevent infinite forwarding loops. See handleServerActionRscRequest.\n if (options.request.headers.get(ACTION_FORWARDED_HEADER)) {\n return createActionNotFoundResponse(null, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\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 (!isAppServerActionFunction(action)) {\n return null;\n }\n\n let actionRedirect: AppServerActionRedirect | null = null;\n let actionError: unknown = undefined;\n let actionFailed = false;\n let actionResult: unknown;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n actionResult = await action();\n } catch (error) {\n actionRedirect = getActionRedirect(error);\n if (!actionRedirect) {\n actionError = error;\n actionFailed = true;\n const isControlFlow =\n getActionHttpFallbackStatus(error) !== null || isServerActionNotFoundError(error, null);\n if (!isControlFlow) {\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 }\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (!actionRedirect) {\n // Capture cookies/headers set during action execution so the caller can\n // apply them to the rendered page response. Mirrors Next.js'\n // `res.setHeader('set-cookie', ...)` path in app-render.tsx, which\n // flushes `requestStore.mutableCookies` onto the response before SSR\n // streaming begins. Without this, no-JS server-action form POSTs lose\n // cookies/headers — see issue #1483.\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const revalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n\n if (actionFailed) {\n return {\n kind: \"form-state\",\n formState: null,\n actionError,\n actionFailed,\n pendingCookies: actionPendingCookies,\n draftCookie: actionDraftCookie,\n revalidationKind,\n };\n }\n\n const formState = await options.decodeFormState(actionResult, body);\n return {\n kind: \"form-state\",\n formState: formState ?? null,\n pendingCookies: actionPendingCookies,\n draftCookie: actionDraftCookie,\n revalidationKind,\n };\n }\n\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n options.clearRequestContext();\n\n const headers = new Headers();\n // Prefix the configured basePath onto the redirect target before it\n // becomes an absolute Location URL. Mirrors Next.js, which threads\n // basePath through `addPathPrefix(...)` for server-action redirects.\n const prefixedRedirectUrl = applyActionRedirectBasePath(\n actionRedirect.url,\n options.basePath ?? \"\",\n );\n headers.set(\"Location\", new URL(prefixedRedirectUrl, options.request.url).toString());\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 setActionRevalidatedHeader(headers, actionRevalidationKind);\n\n return new Response(null, {\n status: 303,\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 getAndClearActionRevalidationKind();\n options.getAndClearPendingCookies();\n console.error(\"[vinext] Server action payload parsing 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 parsing 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 // Defensive guard: if this request has already been forwarded between workers,\n // do not attempt to process it again. Prevents infinite forwarding loops when\n // middleware rewrites action POSTs. Matches Next.js behavior:\n // https://github.com/vercel/next.js/commit/20892dd44e1321c13f755f051e48c3cadd75204b\n if (options.request.headers.get(ACTION_FORWARDED_HEADER)) {\n return createActionNotFoundResponse(options.actionId, {\n clearRequestContext: options.clearRequestContext,\n getAndClearPendingCookies: options.getAndClearPendingCookies,\n });\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 let actionStatus = 200;\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 {\n const httpFallbackStatus = getActionHttpFallbackStatus(error);\n if (httpFallbackStatus !== null) {\n actionStatus = httpFallbackStatus;\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 }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (actionRedirect) {\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n options.clearRequestContext();\n const redirectHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(redirectHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(redirectHeaders);\n // Prefix basePath onto the redirect target. The client-side handler in\n // app-browser-entry reads ACTION_REDIRECT_HEADER and calls\n // window.location.assign/replace verbatim, so the value must already\n // be a basePath-prefixed URL.\n redirectHeaders.set(\n ACTION_REDIRECT_HEADER,\n applyActionRedirectBasePath(actionRedirect.url, options.basePath ?? \"\"),\n );\n redirectHeaders.set(ACTION_REDIRECT_TYPE_HEADER, actionRedirect.type);\n redirectHeaders.set(ACTION_REDIRECT_STATUS_HEADER, 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 setActionRevalidatedHeader(redirectHeaders, actionRevalidationKind);\n return new Response(\"\", { status: 200, headers: redirectHeaders });\n }\n\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n\n const shouldSkipPageRendering = actionRevalidationKind === ACTION_DID_NOT_REVALIDATE;\n if (shouldSkipPageRendering) {\n const onRenderError = options.createRscOnErrorHandler(\n options.request,\n options.cleanPathname,\n options.cleanPathname,\n );\n const rscStream = await options.renderToReadableStream(\n { returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n\n options.clearRequestContext();\n\n const actionHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(actionHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(actionHeaders);\n\n return new Response(rscStream, {\n status: options.middlewareStatus ?? actionStatus,\n headers: actionHeaders,\n });\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 renderMode: APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI,\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 actionHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(actionHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(actionHeaders);\n setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);\n const actionResponse = new Response(rscStream, {\n status: options.middlewareStatus ?? actionStatus,\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 getAndClearActionRevalidationKind();\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 { getAndClearActionRevalidationKind, type ActionRevalidationKind } from \"vinext/shims/cache\";\nimport {\n headersContextFromRequest,\n setHeadersContext,\n type HeadersAccessPhase,\n} from \"vinext/shims/headers\";\nimport {\n type FetchCacheMode,\n setCurrentFetchCacheMode,\n setCurrentFetchSoftTags,\n} from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport { isExternalUrl } from \"../config/config-matchers.js\";\nimport { addBasePathToPathname, hasBasePath, stripBasePath } from \"../utils/base-path.js\";\nimport {\n ACTION_FORWARDED_HEADER,\n ACTION_REDIRECT_HEADER,\n ACTION_REDIRECT_STATUS_HEADER,\n ACTION_REDIRECT_TYPE_HEADER,\n ACTION_REVALIDATED_HEADER,\n} from \"./headers.js\";\nimport {\n VINEXT_RSC_CONTENT_TYPE,\n VINEXT_RSC_VARY_HEADER,\n applyRscCompatibilityIdHeader,\n} from \"./app-rsc-cache-busting.js\";\nimport { applyEdgeRuntimeHeader } from \"./app-page-response.js\";\nimport { resolveAppPageActionRerenderTarget } from \"./app-page-request.js\";\nimport { deferUntilStreamConsumed } from \"./app-page-stream.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { getSetCookieName } from \"./cookie-utils.js\";\nimport {\n APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.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>;\ntype AppServerActionFormStateDecoder = (\n actionResult: unknown,\n body: FormData,\n) => Promise<ReactFormState | undefined>;\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 page?: unknown;\n pattern: string;\n routeHandler?: unknown;\n routeSegments?: readonly string[];\n};\n\n/**\n * Side-effect headers captured during a progressive (no-JS) server action's\n * non-redirect execution. The caller (app-rsc-handler) must apply these to the\n * page render response so that `cookies().set(...)` and revalidation kinds\n * propagate to the browser. Without this, no-JS form submissions silently\n * lose cookie/header mutations — see issue #1483.\n *\n * Next.js' equivalent path mutates `res.setHeader('set-cookie', ...)` during\n * action execution (action-handler.ts → app-render.tsx), then `sendResponse`\n * merges those headers with the rendered Response. vinext works with Response\n * objects directly so the cookies must ride out via the result instead.\n */\ntype ProgressiveServerActionSideEffects = {\n /** `Set-Cookie` headers from `cookies().set(...)` / `cookies().delete(...)`. */\n pendingCookies: string[];\n /** `Set-Cookie` header from `draftMode().enable()/disable()` (if any). */\n draftCookie: string | null | undefined;\n /** Resolved revalidation kind to emit via `x-action-revalidated`. */\n revalidationKind: ActionRevalidationKind;\n};\n\ntype AppServerActionRouteRuntime = \"edge\" | \"experimental-edge\" | \"nodejs\" | null;\n\ntype ProgressiveServerActionResult =\n | ({\n formState: ReactFormState | null;\n kind: \"form-state\";\n } & ProgressiveServerActionSideEffects)\n | ({\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n } & ProgressiveServerActionSideEffects);\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 slotId?: string | null;\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 renderMode: AppRscRenderMode;\n};\n\ntype AppServerActionRscModel<TElement> = {\n /**\n * Omitted when the action did not invalidate page data. This mirrors Next.js'\n * empty Flight payload for non-revalidating fetch actions: the client resolves\n * the action value without committing a visible router update.\n */\n root?: TElement;\n returnValue: AppServerActionReturnValue;\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 /** Configured next.config `basePath`. Prefixed onto progressive Location targets. */\n basePath?: string;\n cleanPathname: string;\n clearRequestContext: () => void;\n contentType: string;\n decodeAction: AppServerActionDecoder;\n decodeFormState: AppServerActionFormStateDecoder;\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 /** Configured next.config `basePath`. Prefixed onto ACTION_REDIRECT_HEADER targets. */\n basePath?: 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 isEdgeRuntime?: boolean;\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 resolveRouteRuntime?: (route: TRoute) => AppServerActionRouteRuntime;\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\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;\nconst ACTION_DID_NOT_REVALIDATE = 0 satisfies ActionRevalidationKind;\nconst ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1 satisfies ActionRevalidationKind;\nconst ACTION_REDIRECT_RENDER_STRIPPED_HEADERS = [\n \"accept\",\n \"content-length\",\n \"content-type\",\n \"next-action\",\n \"origin\",\n \"rsc\",\n \"x-action-forwarded\",\n \"x-rsc-action\",\n];\n\nfunction setActionRevalidatedHeader(headers: Headers, kind: ActionRevalidationKind): void {\n if (kind === ACTION_DID_NOT_REVALIDATE) return;\n headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(kind));\n}\n\nfunction resolveActionRevalidationKind(hasModifiedCookies: boolean): ActionRevalidationKind {\n const revalidationKind = getAndClearActionRevalidationKind();\n // Cookie mutations are a hard override to STATIC_AND_DYNAMIC: any cookie\n // change can invalidate downstream cached payloads regardless of what\n // (if anything) the action explicitly revalidated, so we always emit the\n // strongest kind. STATIC_AND_DYNAMIC is also the lowest numeric value, so\n // this matches the max-precedence semantics in markActionRevalidation.\n if (hasModifiedCookies) return ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC;\n return revalidationKind;\n}\n\nfunction cloneActionRedirectHeaders(requestHeaders: Headers): Headers {\n const headers = new Headers(requestHeaders);\n for (const header of ACTION_REDIRECT_RENDER_STRIPPED_HEADERS) {\n headers.delete(header);\n }\n return headers;\n}\n\nfunction readSetCookieNameValue(setCookie: string): { name: string; value: string } | null {\n const equalsIndex = setCookie.indexOf(\"=\");\n if (equalsIndex <= 0) return null;\n\n const name = setCookie.slice(0, equalsIndex).trim();\n const valueEnd = setCookie.indexOf(\";\", equalsIndex + 1);\n const value = setCookie.slice(equalsIndex + 1, valueEnd === -1 ? undefined : valueEnd);\n\n return { name, value };\n}\n\nfunction isExpiredSetCookie(setCookie: string): boolean {\n return (\n /(?:^|;\\s*)max-age=0(?:;|$)/i.test(setCookie) ||\n /(?:^|;\\s*)expires=Thu,\\s*0?1[\\s-]+Jan[\\s-]+1970/i.test(setCookie)\n );\n}\n\nfunction applySetCookieMutationsToRequestCookieHeader(\n cookieHeader: string | null,\n setCookies: readonly string[],\n): string | null {\n const cookies = new Map<string, string>();\n if (cookieHeader) {\n for (const part of cookieHeader.split(\";\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const equalsIndex = trimmed.indexOf(\"=\");\n if (equalsIndex <= 0) continue;\n cookies.set(trimmed.slice(0, equalsIndex), trimmed.slice(equalsIndex + 1));\n }\n }\n\n for (const setCookie of setCookies) {\n const entry = readSetCookieNameValue(setCookie);\n if (!entry) continue;\n if (isExpiredSetCookie(setCookie)) {\n cookies.delete(entry.name);\n } else {\n // Cookie header values are raw (not URL-encoded), and\n // readSetCookieNameValue extracts the value verbatim from the\n // Set-Cookie header, so store it as-is.\n cookies.set(entry.name, entry.value);\n }\n }\n\n return cookies.size === 0\n ? null\n : [...cookies].map(([name, value]) => `${name}=${value}`).join(\"; \");\n}\n\nfunction createActionRedirectRenderRequest(options: {\n pendingCookies: readonly string[];\n request: Request;\n url: URL;\n}): Request {\n const headers = cloneActionRedirectHeaders(options.request.headers);\n const cookieHeader = applySetCookieMutationsToRequestCookieHeader(\n headers.get(\"cookie\"),\n options.pendingCookies,\n );\n if (cookieHeader === null) {\n headers.delete(\"cookie\");\n } else {\n headers.set(\"cookie\", cookieHeader);\n }\n\n return new Request(options.url, {\n headers,\n method: \"GET\",\n });\n}\n\nfunction withoutRscBodyHeaders(headers: Headers): Headers {\n const nextHeaders = new Headers(headers);\n nextHeaders.delete(\"Content-Type\");\n nextHeaders.delete(\"Vary\");\n return nextHeaders;\n}\n\nfunction isReadableStreamBody(body: BodyInit | null): body is ReadableStream<Uint8Array> {\n return typeof ReadableStream !== \"undefined\" && body instanceof ReadableStream;\n}\n\nfunction createServerActionRscResponse(\n body: BodyInit | null,\n init: ResponseInit,\n clearRequestContext: () => void,\n): Response {\n if (!isReadableStreamBody(body)) {\n clearRequestContext();\n return new Response(body, init);\n }\n\n return new Response(deferUntilStreamConsumed(body, clearRequestContext), init);\n}\n\nfunction isRequestBodyTooLarge(error: unknown): boolean {\n return error instanceof Error && error.message === \"Request body too large\";\n}\n\n/**\n * Collapse repeated `cookies().set(name, ...)` / `cookies().delete(name)`\n * calls down to the last value per name, matching Next.js'\n * `MutableRequestCookiesAdapter` semantics. Next.js stores response cookies in\n * a `ResponseCookies` Map keyed by name — multiple sets for the same cookie\n * collapse to the final value, and emit a single Set-Cookie header.\n *\n * Insertion order is preserved by first occurrence (Map iteration order),\n * which mirrors how `ResponseCookies` iterates its underlying Map. See\n * packages/next/src/server/web/spec-extension/adapters/request-cookies.ts.\n * Issue: https://github.com/cloudflare/vinext/issues/1481\n */\nfunction dedupePendingCookies(cookies: readonly string[]): string[] {\n if (cookies.length <= 1) {\n return cookies.slice();\n }\n const byName = new Map<string, string>();\n const unkeyed: string[] = [];\n for (const cookie of cookies) {\n const name = getSetCookieName(cookie);\n if (name === null) {\n unkeyed.push(cookie);\n continue;\n }\n // Map.set on an existing key replaces the value but preserves the\n // insertion position of the original key — exactly the behaviour we need\n // for `cookies().set(\"foo\", \"1\"); cookies().set(\"bar\", \"2\"); cookies().set(\"foo\", \"3\")`\n // to come out as [foo=3, bar=2].\n byName.set(name, cookie);\n }\n return [...unkeyed, ...byName.values()];\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 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 ?? \"push\",\n url: redirect.url,\n };\n}\n\n/**\n * Prepend the configured next.config `basePath` to a server-action redirect\n * target before it goes on the wire.\n *\n * `redirect(\"/foo\")` called from a server action mounted at `/base/...` must\n * land the browser at `/base/foo`, mirroring how Next.js threads basePath\n * through `addPathPrefix(getURLFromRedirectError(err), basePath)` in\n * `app-render.tsx` for SSR redirects and in `action-handler.ts` for action\n * redirects.\n *\n * Idempotent and external-aware:\n * - Empty basePath → returned unchanged.\n * - External URLs (`http://`, `https://`, `data:`, protocol-relative `//`)\n * are returned unchanged because the framework does not own those routes.\n * - Targets that already start with the configured basePath are returned\n * unchanged so this helper can be applied at any layer without risk of\n * double-prefixing (`/base/base/foo`).\n *\n * Exported for tests. Used by both the progressive (no-JS form POST) and\n * RSC (`ACTION_REDIRECT_HEADER`) action redirect paths below.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/action-handler.ts\n */\nexport function applyActionRedirectBasePath(url: string, basePath: string): string {\n if (!basePath) return url;\n if (isExternalUrl(url)) return url;\n // Pathnames that already include basePath are returned as-is.\n if (hasBasePath(url, basePath)) return url;\n // Relative or hash/query-only targets cannot be prefixed safely without an\n // origin; leave them to the caller's URL resolution.\n if (!url.startsWith(\"/\")) return url;\n // Split off optional query+hash so addBasePathToPathname only operates on\n // the path. We must accept hash too because Next.js redirect targets may\n // contain \"#anchor\".\n const queryIndex = url.indexOf(\"?\");\n const hashIndex = url.indexOf(\"#\");\n const splitAt =\n queryIndex === -1 ? hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);\n const pathname = splitAt === -1 ? url : url.slice(0, splitAt);\n const suffix = splitAt === -1 ? \"\" : url.slice(splitAt);\n return `${addBasePathToPathname(pathname, basePath)}${suffix}`;\n}\n\nfunction buildServerActionPageTags(route: AppServerActionRoute, pathname: string): string[] {\n return buildPageCacheTags(pathname, [], [...(route.routeSegments ?? [])], \"page\");\n}\n\nfunction resolveInternalActionRedirectTarget(\n redirectUrl: string,\n requestUrl: string,\n basePath: string,\n): URL | null {\n if (isExternalUrl(redirectUrl)) {\n const requestOrigin = new URL(requestUrl).origin;\n const parsed = new URL(redirectUrl);\n if (parsed.origin !== requestOrigin) return null;\n if (basePath && !hasBasePath(parsed.pathname, basePath)) return null;\n return parsed;\n }\n\n let resolvedBase = requestUrl;\n if (!redirectUrl.startsWith(\"/\") && !/^[a-z]+:/i.test(redirectUrl)) {\n const parsedRequestUrl = new URL(requestUrl);\n let pathname = parsedRequestUrl.pathname;\n if (!pathname.endsWith(\"/\")) {\n pathname = pathname + \"/\";\n }\n resolvedBase = `${parsedRequestUrl.origin}${pathname}${parsedRequestUrl.search}`;\n }\n\n return new URL(redirectUrl, resolvedBase);\n}\n\nfunction isAncestorRouteRedirect(targetPathname: string, currentPathname: string): boolean {\n return targetPathname !== \"/\" && currentPathname.startsWith(`${targetPathname}/`);\n}\n\nfunction splitActionRedirectPathname(pathname: string): string[] {\n return pathname.split(\"/\").filter(Boolean);\n}\n\nfunction isStaleChildSiblingRouteRedirect(\n targetPathname: string,\n currentPathname: string,\n): boolean {\n const targetSegments = splitActionRedirectPathname(targetPathname);\n const currentSegments = splitActionRedirectPathname(currentPathname);\n // Only deeper-to-shallower redirects can be stale in the Next.js worker\n // model (same-depth siblings share the same page worker). The depth guard\n // ensures we don't misclassify same-level redirects.\n if (targetSegments.length === 0 || currentSegments.length <= targetSegments.length) {\n return false;\n }\n\n let commonPrefixLength = 0;\n const maxPrefixLength = Math.min(targetSegments.length, currentSegments.length);\n while (\n commonPrefixLength < maxPrefixLength &&\n targetSegments[commonPrefixLength] === currentSegments[commonPrefixLength]\n ) {\n commonPrefixLength++;\n }\n\n return commonPrefixLength > 0 && commonPrefixLength < targetSegments.length;\n}\n\nfunction normalizeRuntime(runtime: AppServerActionRouteRuntime): \"edge\" | \"nodejs\" {\n if (runtime === \"edge\" || runtime === \"experimental-edge\") {\n return \"edge\";\n }\n return \"nodejs\";\n}\n\nfunction shouldUseForwardedActionRedirectStatus<TRoute extends AppServerActionRoute>(options: {\n actionWasForwarded: boolean;\n currentPathname: string;\n currentRoute: TRoute | null;\n resolveRouteRuntime?: (route: TRoute) => AppServerActionRouteRuntime;\n targetPathname: string;\n targetRoute: TRoute;\n}): boolean {\n if (options.actionWasForwarded) return true;\n if (isAncestorRouteRedirect(options.targetPathname, options.currentPathname)) return true;\n if (isStaleChildSiblingRouteRedirect(options.targetPathname, options.currentPathname)) {\n return true;\n }\n if (!options.currentRoute || !options.resolveRouteRuntime) return false;\n\n const currentRuntime = normalizeRuntime(options.resolveRouteRuntime(options.currentRoute));\n const targetRuntime = normalizeRuntime(options.resolveRouteRuntime(options.targetRoute));\n return currentRuntime !== targetRuntime;\n}\n\nfunction canRenderActionRedirectTarget(route: AppServerActionRoute): boolean {\n if (\"routeHandler\" in route && route.routeHandler) return false;\n return route.page !== null && route.page !== undefined;\n}\n\nfunction getActionHttpFallbackStatus(error: unknown): number | null {\n const digest = getNextErrorDigest(error);\n if (!digest) return null;\n\n const httpError = parseNextHttpErrorDigest(digest);\n if (!httpError || !Number.isInteger(httpError.status)) return null;\n\n return httpError.status;\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 | ProgressiveServerActionResult | null> {\n if (!isProgressiveServerActionRequest(options.request, options.contentType, options.actionId)) {\n return null;\n }\n\n // Progressive form submissions (multipart form data without an actionId)\n // don't carry a forwarded-action header. They route to the visible page\n // directly and can't be redirected cross-runtime, so no forwarded guard is\n // needed here.\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 (!isAppServerActionFunction(action)) {\n return null;\n }\n\n let actionRedirect: AppServerActionRedirect | null = null;\n let actionError: unknown = undefined;\n let actionFailed = false;\n let actionResult: unknown;\n const previousHeadersPhase = options.setHeadersAccessPhase(\"action\");\n try {\n actionResult = await action();\n } catch (error) {\n actionRedirect = getActionRedirect(error);\n if (!actionRedirect) {\n actionError = error;\n actionFailed = true;\n const isControlFlow =\n getActionHttpFallbackStatus(error) !== null || isServerActionNotFoundError(error, null);\n if (!isControlFlow) {\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 }\n }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (!actionRedirect) {\n // Capture cookies/headers set during action execution so the caller can\n // apply them to the rendered page response. Mirrors Next.js'\n // `res.setHeader('set-cookie', ...)` path in app-render.tsx, which\n // flushes `requestStore.mutableCookies` onto the response before SSR\n // streaming begins. Without this, no-JS server-action form POSTs lose\n // cookies/headers — see issue #1483.\n const actionPendingCookies = options.getAndClearPendingCookies();\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const revalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n\n if (actionFailed) {\n return {\n kind: \"form-state\",\n formState: null,\n actionError,\n actionFailed,\n pendingCookies: actionPendingCookies,\n draftCookie: actionDraftCookie,\n revalidationKind,\n };\n }\n\n const formState = await options.decodeFormState(actionResult, body);\n return {\n kind: \"form-state\",\n formState: formState ?? null,\n pendingCookies: actionPendingCookies,\n draftCookie: actionDraftCookie,\n revalidationKind,\n };\n }\n\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n options.clearRequestContext();\n\n const headers = new Headers();\n // Prefix the configured basePath onto the redirect target before it\n // becomes an absolute Location URL. Mirrors Next.js, which threads\n // basePath through `addPathPrefix(...)` for server-action redirects.\n const prefixedRedirectUrl = applyActionRedirectBasePath(\n actionRedirect.url,\n options.basePath ?? \"\",\n );\n headers.set(\"Location\", new URL(prefixedRedirectUrl, options.request.url).toString());\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 setActionRevalidatedHeader(headers, actionRevalidationKind);\n\n return new Response(null, {\n status: 303,\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 getAndClearActionRevalidationKind();\n options.getAndClearPendingCookies();\n console.error(\"[vinext] Server action payload parsing 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 parsing 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 let actionStatus = 200;\n const actionWasForwarded = Boolean(options.request.headers.get(ACTION_FORWARDED_HEADER));\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 {\n const httpFallbackStatus = getActionHttpFallbackStatus(error);\n if (httpFallbackStatus !== null) {\n actionStatus = httpFallbackStatus;\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 }\n } finally {\n options.setHeadersAccessPhase(previousHeadersPhase);\n }\n\n if (actionRedirect) {\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n const redirectHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(redirectHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(redirectHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(redirectHeaders);\n // Prefix basePath onto the redirect target. The client-side handler in\n // app-browser-entry reads ACTION_REDIRECT_HEADER and calls\n // window.location.assign/replace verbatim, so the value must already\n // be a basePath-prefixed URL.\n const actionRedirectUrl = applyActionRedirectBasePath(\n actionRedirect.url,\n options.basePath ?? \"\",\n );\n redirectHeaders.set(ACTION_REDIRECT_HEADER, actionRedirectUrl);\n redirectHeaders.set(ACTION_REDIRECT_TYPE_HEADER, actionRedirect.type);\n redirectHeaders.set(ACTION_REDIRECT_STATUS_HEADER, 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 setActionRevalidatedHeader(redirectHeaders, actionRevalidationKind);\n\n const redirectTarget = resolveInternalActionRedirectTarget(\n actionRedirectUrl,\n options.request.url,\n options.basePath ?? \"\",\n );\n if (!redirectTarget) {\n options.clearRequestContext();\n return new Response(null, {\n status: 303,\n headers: withoutRscBodyHeaders(redirectHeaders),\n });\n }\n\n const targetPathname = stripBasePath(redirectTarget.pathname, options.basePath ?? \"\");\n const targetMatch = options.matchRoute(targetPathname);\n if (!targetMatch || !canRenderActionRedirectTarget(targetMatch.route)) {\n options.clearRequestContext();\n return new Response(null, {\n status: 303,\n headers: withoutRscBodyHeaders(redirectHeaders),\n });\n }\n const currentMatch = options.matchRoute(options.cleanPathname);\n\n const redirectRenderRequest = createActionRedirectRenderRequest({\n pendingCookies: [\n ...actionPendingCookies,\n ...(actionDraftCookie ? [actionDraftCookie] : []),\n ],\n request: options.request,\n url: redirectTarget,\n });\n setHeadersContext(headersContextFromRequest(redirectRenderRequest));\n options.setNavigationContext({\n pathname: targetPathname,\n searchParams: redirectTarget.searchParams,\n params: targetMatch.params,\n });\n setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(targetMatch.route) ?? null);\n setCurrentFetchSoftTags(buildServerActionPageTags(targetMatch.route, targetPathname));\n const element = options.buildPageElement({\n cleanPathname: targetPathname,\n interceptOpts: undefined,\n isRscRequest: true,\n mountedSlotsHeader: null,\n params: targetMatch.params,\n request: redirectRenderRequest,\n route: targetMatch.route,\n searchParams: redirectTarget.searchParams,\n renderMode: APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI,\n });\n const onRenderError = options.createRscOnErrorHandler(\n redirectRenderRequest,\n targetPathname,\n targetMatch.route.pattern,\n );\n const rscStream = await options.renderToReadableStream(\n { root: element, returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n const redirectResponseStatus = shouldUseForwardedActionRedirectStatus({\n actionWasForwarded,\n currentPathname: options.cleanPathname,\n currentRoute: currentMatch?.route ?? null,\n resolveRouteRuntime: options.resolveRouteRuntime,\n targetPathname,\n targetRoute: targetMatch.route,\n })\n ? 200\n : 303;\n\n return createServerActionRscResponse(\n rscStream,\n { status: redirectResponseStatus, headers: redirectHeaders },\n options.clearRequestContext,\n );\n }\n\n const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());\n const actionDraftCookie = options.getDraftModeCookieHeader();\n const actionRevalidationKind = resolveActionRevalidationKind(\n actionPendingCookies.length > 0 || Boolean(actionDraftCookie),\n );\n\n // When an action returned a non-200 HTTP fallback status (e.g. 404 from\n // notFound()), skip the early page render so the error boundary displays\n // the fallback payload embedded in returnValue. Forwarded actions always\n // skip rerendering regardless of status (the forwarded worker doesn't own\n // the page's layout tree). Otherwise only skip when the action status is\n // 200 and no revalidation side-effects occurred.\n const shouldSkipPageRendering =\n actionWasForwarded ||\n (actionStatus === 200 && actionRevalidationKind === ACTION_DID_NOT_REVALIDATE);\n if (shouldSkipPageRendering) {\n const onRenderError = options.createRscOnErrorHandler(\n options.request,\n options.cleanPathname,\n options.cleanPathname,\n );\n const rscStream = await options.renderToReadableStream(\n { returnValue },\n { temporaryReferences, onError: onRenderError },\n );\n\n const actionHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(actionHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(actionHeaders);\n for (const cookie of actionPendingCookies) {\n actionHeaders.append(\"Set-Cookie\", cookie);\n }\n if (actionDraftCookie) actionHeaders.append(\"Set-Cookie\", actionDraftCookie);\n setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);\n\n return createServerActionRscResponse(\n rscStream,\n {\n status: options.middlewareStatus ?? actionStatus,\n headers: actionHeaders,\n },\n options.clearRequestContext,\n );\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 setCurrentFetchSoftTags(\n buildServerActionPageTags(actionRerenderTarget.route, options.cleanPathname),\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 renderMode: APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI,\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 actionHeaders = new Headers({\n \"Content-Type\": VINEXT_RSC_CONTENT_TYPE,\n Vary: VINEXT_RSC_VARY_HEADER,\n });\n applyEdgeRuntimeHeader(actionHeaders, options.isEdgeRuntime);\n mergeMiddlewareResponseHeaders(actionHeaders, options.middlewareHeaders);\n applyRscCompatibilityIdHeader(actionHeaders);\n setActionRevalidatedHeader(actionHeaders, actionRevalidationKind);\n const actionResponse = createServerActionRscResponse(\n rscStream,\n {\n status: options.middlewareStatus ?? actionStatus,\n headers: actionHeaders,\n },\n options.clearRequestContext,\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 getAndClearActionRevalidationKind();\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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"}
@@ -11,6 +11,7 @@ type ArtifactCompatibilityEnvelope = Readonly<{
11
11
  rootBoundaryId: string | null;
12
12
  renderEpoch: string | null;
13
13
  }>;
14
+ declare const ARTIFACT_COMPATIBILITY_PROOF_FIELDS: readonly (keyof ArtifactCompatibilityEnvelope)[];
14
15
  type ArtifactCompatibilityEnvelopeInput = Readonly<{
15
16
  graphVersion?: string | null;
16
17
  deploymentVersion?: string | null;
@@ -50,5 +51,5 @@ declare function createArtifactCompatibilityGraphVersion(input: ArtifactCompatib
50
51
  declare function parseArtifactCompatibilityEnvelope(value: unknown): ArtifactCompatibilityEnvelope | null;
51
52
  declare function evaluateArtifactCompatibility(current: ArtifactCompatibilityEnvelope, candidate: ArtifactCompatibilityEnvelope, options?: ArtifactCompatibilityEvaluationOptions): ArtifactCompatibilityDecision;
52
53
  //#endregion
53
- export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, ArtifactCompatibilityEnvelope, ArtifactCompatibilityEvaluationOptions, ArtifactCompatibilityMap, ArtifactCompatibilitySet, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
54
+ export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_PROOF_FIELDS, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, ArtifactCompatibilityEnvelope, ArtifactCompatibilityEvaluationOptions, ArtifactCompatibilityMap, ArtifactCompatibilitySet, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
54
55
  //# sourceMappingURL=artifact-compatibility.d.ts.map
@@ -3,6 +3,15 @@ import { fnv1a64 } from "../utils/hash.js";
3
3
  const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;
4
4
  const APP_ELEMENTS_SCHEMA_VERSION = 1;
5
5
  const RSC_PAYLOAD_SCHEMA_VERSION = 1;
6
+ const ARTIFACT_COMPATIBILITY_PROOF_FIELDS = [
7
+ "schemaVersion",
8
+ "graphVersion",
9
+ "deploymentVersion",
10
+ "appElementsSchemaVersion",
11
+ "rscPayloadSchemaVersion",
12
+ "rootBoundaryId",
13
+ "renderEpoch"
14
+ ];
6
15
  function createArtifactCompatibilityEnvelope(input = {}) {
7
16
  return {
8
17
  schemaVersion: 1,
@@ -81,6 +90,6 @@ function evaluateArtifactCompatibility(current, candidate, options = {}) {
81
90
  return { kind: "compatible" };
82
91
  }
83
92
  //#endregion
84
- export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
93
+ export { APP_ELEMENTS_SCHEMA_VERSION, ARTIFACT_COMPATIBILITY_PROOF_FIELDS, ARTIFACT_COMPATIBILITY_SCHEMA_VERSION, RSC_PAYLOAD_SCHEMA_VERSION, createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion, evaluateArtifactCompatibility, parseArtifactCompatibilityEnvelope };
85
94
 
86
95
  //# sourceMappingURL=artifact-compatibility.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-compatibility.js","names":[],"sources":["../../src/server/artifact-compatibility.ts"],"sourcesContent":["import { fnv1a64 } from \"../utils/hash.js\";\n\nexport const ARTIFACT_COMPATIBILITY_SCHEMA_VERSION = 1;\n\n// These versions describe separate protocol layers. For example, a future\n// rolling deploy can bump the flat AppElements row shape while keeping the\n// envelope object and serialized RSC transport version stable.\nexport const APP_ELEMENTS_SCHEMA_VERSION = 1;\nexport const RSC_PAYLOAD_SCHEMA_VERSION = 1;\n\nexport type ArtifactCompatibilityEnvelope = Readonly<{\n schemaVersion: typeof ARTIFACT_COMPATIBILITY_SCHEMA_VERSION;\n graphVersion: string | null;\n deploymentVersion: string | null;\n appElementsSchemaVersion: typeof APP_ELEMENTS_SCHEMA_VERSION;\n rscPayloadSchemaVersion: typeof RSC_PAYLOAD_SCHEMA_VERSION;\n rootBoundaryId: string | null;\n renderEpoch: string | null;\n}>;\n\ntype ArtifactCompatibilityEnvelopeInput = Readonly<{\n graphVersion?: string | null;\n deploymentVersion?: string | null;\n rootBoundaryId?: string | null;\n renderEpoch?: string | null;\n}>;\n\nexport type ArtifactCompatibilitySet = readonly [string, string, ...string[]];\n\nexport type ArtifactCompatibilityMap = Readonly<{\n graphVersions?: readonly ArtifactCompatibilitySet[];\n deploymentVersions?: readonly ArtifactCompatibilitySet[];\n rootBoundaryIds?: readonly ArtifactCompatibilitySet[];\n renderEpochs?: readonly ArtifactCompatibilitySet[];\n}>;\n\nexport type ArtifactCompatibilityEvaluationOptions = Readonly<{\n compatibilityMap?: ArtifactCompatibilityMap;\n}>;\n\ntype ArtifactCompatibilityFallback = \"renderFresh\";\n\ntype ArtifactCompatibilityUnknownReason =\n | \"graphVersionUnknown\"\n | \"deploymentVersionUnknown\"\n | \"rootBoundaryIdUnknown\"\n | \"renderEpochUnknown\";\n\ntype ArtifactCompatibilityIncompatibleReason =\n | \"appElementsSchemaVersionMismatch\"\n | \"deploymentVersionNotDeclaredCompatible\"\n | \"deploymentVersionMismatch\"\n | \"graphVersionNotDeclaredCompatible\"\n | \"graphVersionMismatch\"\n | \"renderEpochNotDeclaredCompatible\"\n | \"renderEpochMismatch\"\n | \"rootBoundaryIdNotDeclaredCompatible\"\n | \"rootBoundaryIdMismatch\"\n | \"rscPayloadSchemaVersionMismatch\"\n | \"schemaVersionMismatch\";\n\ntype ArtifactCompatibilityDecision = Readonly<\n | { kind: \"compatible\" }\n | {\n kind: \"unknown\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityUnknownReason;\n }\n | {\n kind: \"incompatible\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityIncompatibleReason;\n }\n>;\n\ntype ArtifactCompatibilityGraphVersionInput = Readonly<{\n routePattern: string;\n rootBoundaryId: string | null;\n}>;\n\nexport function createArtifactCompatibilityEnvelope(\n input: ArtifactCompatibilityEnvelopeInput = {},\n): ArtifactCompatibilityEnvelope {\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: input.graphVersion ?? null,\n deploymentVersion: input.deploymentVersion ?? null,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: input.rootBoundaryId ?? null,\n renderEpoch: input.renderEpoch ?? null,\n };\n}\n\nexport function createArtifactCompatibilityGraphVersion(\n input: ArtifactCompatibilityGraphVersionInput,\n): string {\n const fingerprint = fnv1a64(JSON.stringify([input.routePattern, input.rootBoundaryId]));\n return `app-route-graph:${fingerprint}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStringOrNull(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction hasCurrentSchemaVersions(record: Readonly<Record<string, unknown>>): boolean {\n return (\n record.schemaVersion === ARTIFACT_COMPATIBILITY_SCHEMA_VERSION &&\n record.appElementsSchemaVersion === APP_ELEMENTS_SCHEMA_VERSION &&\n record.rscPayloadSchemaVersion === RSC_PAYLOAD_SCHEMA_VERSION\n );\n}\n\nexport function parseArtifactCompatibilityEnvelope(\n value: unknown,\n): ArtifactCompatibilityEnvelope | null {\n if (!isRecord(value)) return null;\n // The Wave01 skeleton intentionally collapses version mismatch and malformed\n // metadata into \"not current\". Cache/skip callers must split those cases\n // before treating unknown compatibility as anything other than a miss/reject.\n if (!hasCurrentSchemaVersions(value)) return null;\n if (!isStringOrNull(value.graphVersion)) return null;\n if (!isStringOrNull(value.deploymentVersion)) return null;\n if (!isStringOrNull(value.rootBoundaryId)) return null;\n if (!isStringOrNull(value.renderEpoch)) return null;\n\n // This parser intentionally returns a normalized current-version proof. A\n // future-compatible reader should introduce a separate parsed type instead of\n // widening this Wave01 envelope after the current-version checks above.\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: value.graphVersion,\n deploymentVersion: value.deploymentVersion,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: value.rootBoundaryId,\n renderEpoch: value.renderEpoch,\n };\n}\n\nfunction incompatible(\n reason: ArtifactCompatibilityIncompatibleReason,\n): ArtifactCompatibilityDecision {\n return { kind: \"incompatible\", fallback: \"renderFresh\", reason };\n}\n\nfunction unknown(reason: ArtifactCompatibilityUnknownReason): ArtifactCompatibilityDecision {\n return { kind: \"unknown\", fallback: \"renderFresh\", reason };\n}\n\nfunction compareKnownField(\n currentValue: string | null,\n candidateValue: string | null,\n unknownReason: ArtifactCompatibilityUnknownReason,\n mismatchReason: ArtifactCompatibilityIncompatibleReason,\n notDeclaredCompatibleReason: ArtifactCompatibilityIncompatibleReason,\n compatibilitySets: readonly ArtifactCompatibilitySet[] | undefined,\n): ArtifactCompatibilityDecision | null {\n if (currentValue === null || candidateValue === null) {\n return unknown(unknownReason);\n }\n if (currentValue === candidateValue) {\n return null;\n }\n if (compatibilitySets === undefined) {\n return incompatible(mismatchReason);\n }\n return isDeclaredCompatible(currentValue, candidateValue, compatibilitySets)\n ? null\n : incompatible(notDeclaredCompatibleReason);\n}\n\nfunction isDeclaredCompatible(\n currentValue: string,\n candidateValue: string,\n compatibilitySets: readonly ArtifactCompatibilitySet[],\n): boolean {\n // Compatibility is intentionally scoped to one declared set. Overlapping\n // pair sets like [a,b] and [b,c] must not silently make a compatible with c.\n return compatibilitySets.some(\n (compatibilitySet) =>\n compatibilitySet.includes(currentValue) && compatibilitySet.includes(candidateValue),\n );\n}\n\nexport function evaluateArtifactCompatibility(\n current: ArtifactCompatibilityEnvelope,\n candidate: ArtifactCompatibilityEnvelope,\n options: ArtifactCompatibilityEvaluationOptions = {},\n): ArtifactCompatibilityDecision {\n // This remains a proof evaluator: mismatched fields are compatible only when\n // the current build's compatibility map explicitly declares that relationship.\n if (current.schemaVersion !== candidate.schemaVersion) {\n return incompatible(\"schemaVersionMismatch\");\n }\n if (current.appElementsSchemaVersion !== candidate.appElementsSchemaVersion) {\n return incompatible(\"appElementsSchemaVersionMismatch\");\n }\n if (current.rscPayloadSchemaVersion !== candidate.rscPayloadSchemaVersion) {\n return incompatible(\"rscPayloadSchemaVersionMismatch\");\n }\n\n const graphDecision = compareKnownField(\n current.graphVersion,\n candidate.graphVersion,\n \"graphVersionUnknown\",\n \"graphVersionMismatch\",\n \"graphVersionNotDeclaredCompatible\",\n options.compatibilityMap?.graphVersions,\n );\n if (graphDecision) return graphDecision;\n\n const deploymentDecision = compareKnownField(\n current.deploymentVersion,\n candidate.deploymentVersion,\n \"deploymentVersionUnknown\",\n \"deploymentVersionMismatch\",\n \"deploymentVersionNotDeclaredCompatible\",\n options.compatibilityMap?.deploymentVersions,\n );\n if (deploymentDecision) return deploymentDecision;\n\n const rootBoundaryDecision = compareKnownField(\n current.rootBoundaryId,\n candidate.rootBoundaryId,\n \"rootBoundaryIdUnknown\",\n \"rootBoundaryIdMismatch\",\n \"rootBoundaryIdNotDeclaredCompatible\",\n options.compatibilityMap?.rootBoundaryIds,\n );\n if (rootBoundaryDecision) return rootBoundaryDecision;\n\n const renderEpochDecision = compareKnownField(\n current.renderEpoch,\n candidate.renderEpoch,\n \"renderEpochUnknown\",\n \"renderEpochMismatch\",\n \"renderEpochNotDeclaredCompatible\",\n options.compatibilityMap?.renderEpochs,\n );\n if (renderEpochDecision) return renderEpochDecision;\n\n return { kind: \"compatible\" };\n}\n"],"mappings":"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"}
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\n// Canonical ordered list of every field in ArtifactCompatibilityEnvelope.\n// Order is load-bearing — hash-producing consumers iterate this array to\n// guarantee deterministic ordering across runtimes.\nexport const ARTIFACT_COMPATIBILITY_PROOF_FIELDS: readonly (keyof ArtifactCompatibilityEnvelope)[] =\n [\n \"schemaVersion\",\n \"graphVersion\",\n \"deploymentVersion\",\n \"appElementsSchemaVersion\",\n \"rscPayloadSchemaVersion\",\n \"rootBoundaryId\",\n \"renderEpoch\",\n ];\n\ntype ArtifactCompatibilityEnvelopeInput = Readonly<{\n graphVersion?: string | null;\n deploymentVersion?: string | null;\n rootBoundaryId?: string | null;\n renderEpoch?: string | null;\n}>;\n\nexport type ArtifactCompatibilitySet = readonly [string, string, ...string[]];\n\nexport type ArtifactCompatibilityMap = Readonly<{\n graphVersions?: readonly ArtifactCompatibilitySet[];\n deploymentVersions?: readonly ArtifactCompatibilitySet[];\n rootBoundaryIds?: readonly ArtifactCompatibilitySet[];\n renderEpochs?: readonly ArtifactCompatibilitySet[];\n}>;\n\nexport type ArtifactCompatibilityEvaluationOptions = Readonly<{\n compatibilityMap?: ArtifactCompatibilityMap;\n}>;\n\ntype ArtifactCompatibilityFallback = \"renderFresh\";\n\ntype ArtifactCompatibilityUnknownReason =\n | \"graphVersionUnknown\"\n | \"deploymentVersionUnknown\"\n | \"rootBoundaryIdUnknown\"\n | \"renderEpochUnknown\";\n\ntype ArtifactCompatibilityIncompatibleReason =\n | \"appElementsSchemaVersionMismatch\"\n | \"deploymentVersionNotDeclaredCompatible\"\n | \"deploymentVersionMismatch\"\n | \"graphVersionNotDeclaredCompatible\"\n | \"graphVersionMismatch\"\n | \"renderEpochNotDeclaredCompatible\"\n | \"renderEpochMismatch\"\n | \"rootBoundaryIdNotDeclaredCompatible\"\n | \"rootBoundaryIdMismatch\"\n | \"rscPayloadSchemaVersionMismatch\"\n | \"schemaVersionMismatch\";\n\ntype ArtifactCompatibilityDecision = Readonly<\n | { kind: \"compatible\" }\n | {\n kind: \"unknown\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityUnknownReason;\n }\n | {\n kind: \"incompatible\";\n fallback: ArtifactCompatibilityFallback;\n reason: ArtifactCompatibilityIncompatibleReason;\n }\n>;\n\ntype ArtifactCompatibilityGraphVersionInput = Readonly<{\n routePattern: string;\n rootBoundaryId: string | null;\n}>;\n\nexport function createArtifactCompatibilityEnvelope(\n input: ArtifactCompatibilityEnvelopeInput = {},\n): ArtifactCompatibilityEnvelope {\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: input.graphVersion ?? null,\n deploymentVersion: input.deploymentVersion ?? null,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: input.rootBoundaryId ?? null,\n renderEpoch: input.renderEpoch ?? null,\n };\n}\n\nexport function createArtifactCompatibilityGraphVersion(\n input: ArtifactCompatibilityGraphVersionInput,\n): string {\n const fingerprint = fnv1a64(JSON.stringify([input.routePattern, input.rootBoundaryId]));\n return `app-route-graph:${fingerprint}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStringOrNull(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction hasCurrentSchemaVersions(record: Readonly<Record<string, unknown>>): boolean {\n return (\n record.schemaVersion === ARTIFACT_COMPATIBILITY_SCHEMA_VERSION &&\n record.appElementsSchemaVersion === APP_ELEMENTS_SCHEMA_VERSION &&\n record.rscPayloadSchemaVersion === RSC_PAYLOAD_SCHEMA_VERSION\n );\n}\n\nexport function parseArtifactCompatibilityEnvelope(\n value: unknown,\n): ArtifactCompatibilityEnvelope | null {\n if (!isRecord(value)) return null;\n // The Wave01 skeleton intentionally collapses version mismatch and malformed\n // metadata into \"not current\". Cache/skip callers must split those cases\n // before treating unknown compatibility as anything other than a miss/reject.\n if (!hasCurrentSchemaVersions(value)) return null;\n if (!isStringOrNull(value.graphVersion)) return null;\n if (!isStringOrNull(value.deploymentVersion)) return null;\n if (!isStringOrNull(value.rootBoundaryId)) return null;\n if (!isStringOrNull(value.renderEpoch)) return null;\n\n // This parser intentionally returns a normalized current-version proof. A\n // future-compatible reader should introduce a separate parsed type instead of\n // widening this Wave01 envelope after the current-version checks above.\n return {\n schemaVersion: ARTIFACT_COMPATIBILITY_SCHEMA_VERSION,\n graphVersion: value.graphVersion,\n deploymentVersion: value.deploymentVersion,\n appElementsSchemaVersion: APP_ELEMENTS_SCHEMA_VERSION,\n rscPayloadSchemaVersion: RSC_PAYLOAD_SCHEMA_VERSION,\n rootBoundaryId: value.rootBoundaryId,\n renderEpoch: value.renderEpoch,\n };\n}\n\nfunction incompatible(\n reason: ArtifactCompatibilityIncompatibleReason,\n): ArtifactCompatibilityDecision {\n return { kind: \"incompatible\", fallback: \"renderFresh\", reason };\n}\n\nfunction unknown(reason: ArtifactCompatibilityUnknownReason): ArtifactCompatibilityDecision {\n return { kind: \"unknown\", fallback: \"renderFresh\", reason };\n}\n\nfunction compareKnownField(\n currentValue: string | null,\n candidateValue: string | null,\n unknownReason: ArtifactCompatibilityUnknownReason,\n mismatchReason: ArtifactCompatibilityIncompatibleReason,\n notDeclaredCompatibleReason: ArtifactCompatibilityIncompatibleReason,\n compatibilitySets: readonly ArtifactCompatibilitySet[] | undefined,\n): ArtifactCompatibilityDecision | null {\n if (currentValue === null || candidateValue === null) {\n return unknown(unknownReason);\n }\n if (currentValue === candidateValue) {\n return null;\n }\n if (compatibilitySets === undefined) {\n return incompatible(mismatchReason);\n }\n return isDeclaredCompatible(currentValue, candidateValue, compatibilitySets)\n ? null\n : incompatible(notDeclaredCompatibleReason);\n}\n\nfunction isDeclaredCompatible(\n currentValue: string,\n candidateValue: string,\n compatibilitySets: readonly ArtifactCompatibilitySet[],\n): boolean {\n // Compatibility is intentionally scoped to one declared set. Overlapping\n // pair sets like [a,b] and [b,c] must not silently make a compatible with c.\n return compatibilitySets.some(\n (compatibilitySet) =>\n compatibilitySet.includes(currentValue) && compatibilitySet.includes(candidateValue),\n );\n}\n\nexport function evaluateArtifactCompatibility(\n current: ArtifactCompatibilityEnvelope,\n candidate: ArtifactCompatibilityEnvelope,\n options: ArtifactCompatibilityEvaluationOptions = {},\n): ArtifactCompatibilityDecision {\n // This remains a proof evaluator: mismatched fields are compatible only when\n // the current build's compatibility map explicitly declares that relationship.\n if (current.schemaVersion !== candidate.schemaVersion) {\n return incompatible(\"schemaVersionMismatch\");\n }\n if (current.appElementsSchemaVersion !== candidate.appElementsSchemaVersion) {\n return incompatible(\"appElementsSchemaVersionMismatch\");\n }\n if (current.rscPayloadSchemaVersion !== candidate.rscPayloadSchemaVersion) {\n return incompatible(\"rscPayloadSchemaVersionMismatch\");\n }\n\n const graphDecision = compareKnownField(\n current.graphVersion,\n candidate.graphVersion,\n \"graphVersionUnknown\",\n \"graphVersionMismatch\",\n \"graphVersionNotDeclaredCompatible\",\n options.compatibilityMap?.graphVersions,\n );\n if (graphDecision) return graphDecision;\n\n const deploymentDecision = compareKnownField(\n current.deploymentVersion,\n candidate.deploymentVersion,\n \"deploymentVersionUnknown\",\n \"deploymentVersionMismatch\",\n \"deploymentVersionNotDeclaredCompatible\",\n options.compatibilityMap?.deploymentVersions,\n );\n if (deploymentDecision) return deploymentDecision;\n\n const rootBoundaryDecision = compareKnownField(\n current.rootBoundaryId,\n candidate.rootBoundaryId,\n \"rootBoundaryIdUnknown\",\n \"rootBoundaryIdMismatch\",\n \"rootBoundaryIdNotDeclaredCompatible\",\n options.compatibilityMap?.rootBoundaryIds,\n );\n if (rootBoundaryDecision) return rootBoundaryDecision;\n\n const renderEpochDecision = compareKnownField(\n current.renderEpoch,\n candidate.renderEpoch,\n \"renderEpochUnknown\",\n \"renderEpochMismatch\",\n \"renderEpochNotDeclaredCompatible\",\n options.compatibilityMap?.renderEpochs,\n );\n if (renderEpochDecision) return renderEpochDecision;\n\n return { kind: \"compatible\" };\n}\n"],"mappings":";;AAEA,MAAa,wCAAwC;AAKrD,MAAa,8BAA8B;AAC3C,MAAa,6BAA6B;AAe1C,MAAa,sCACX;CACE;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AA8DH,SAAgB,oCACd,QAA4C,EAAE,EACf;CAC/B,OAAO;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;CAER,OAAO,mBADa,QAAQ,KAAK,UAAU,CAAC,MAAM,cAAc,MAAM,eAAe,CAAC,CACjD;;AAGvC,SAAS,SAAS,OAA4D;CAC5E,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG7E,SAAS,eAAe,OAAwC;CAC9D,OAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,yBAAyB,QAAoD;CACpF,OACE,OAAO,kBAAA,KACP,OAAO,6BAAA,KACP,OAAO,4BAAA;;AAIX,SAAgB,mCACd,OACsC;CACtC,IAAI,CAAC,SAAS,MAAM,EAAE,OAAO;CAI7B,IAAI,CAAC,yBAAyB,MAAM,EAAE,OAAO;CAC7C,IAAI,CAAC,eAAe,MAAM,aAAa,EAAE,OAAO;CAChD,IAAI,CAAC,eAAe,MAAM,kBAAkB,EAAE,OAAO;CACrD,IAAI,CAAC,eAAe,MAAM,eAAe,EAAE,OAAO;CAClD,IAAI,CAAC,eAAe,MAAM,YAAY,EAAE,OAAO;CAK/C,OAAO;EACL,eAAA;EACA,cAAc,MAAM;EACpB,mBAAmB,MAAM;EACzB,0BAAA;EACA,yBAAA;EACA,gBAAgB,MAAM;EACtB,aAAa,MAAM;EACpB;;AAGH,SAAS,aACP,QAC+B;CAC/B,OAAO;EAAE,MAAM;EAAgB,UAAU;EAAe;EAAQ;;AAGlE,SAAS,QAAQ,QAA2E;CAC1F,OAAO;EAAE,MAAM;EAAW,UAAU;EAAe;EAAQ;;AAG7D,SAAS,kBACP,cACA,gBACA,eACA,gBACA,6BACA,mBACsC;CACtC,IAAI,iBAAiB,QAAQ,mBAAmB,MAC9C,OAAO,QAAQ,cAAc;CAE/B,IAAI,iBAAiB,gBACnB,OAAO;CAET,IAAI,sBAAsB,KAAA,GACxB,OAAO,aAAa,eAAe;CAErC,OAAO,qBAAqB,cAAc,gBAAgB,kBAAkB,GACxE,OACA,aAAa,4BAA4B;;AAG/C,SAAS,qBACP,cACA,gBACA,mBACS;CAGT,OAAO,kBAAkB,MACtB,qBACC,iBAAiB,SAAS,aAAa,IAAI,iBAAiB,SAAS,eAAe,CACvF;;AAGH,SAAgB,8BACd,SACA,WACA,UAAkD,EAAE,EACrB;CAG/B,IAAI,QAAQ,kBAAkB,UAAU,eACtC,OAAO,aAAa,wBAAwB;CAE9C,IAAI,QAAQ,6BAA6B,UAAU,0BACjD,OAAO,aAAa,mCAAmC;CAEzD,IAAI,QAAQ,4BAA4B,UAAU,yBAChD,OAAO,aAAa,kCAAkC;CAGxD,MAAM,gBAAgB,kBACpB,QAAQ,cACR,UAAU,cACV,uBACA,wBACA,qCACA,QAAQ,kBAAkB,cAC3B;CACD,IAAI,eAAe,OAAO;CAE1B,MAAM,qBAAqB,kBACzB,QAAQ,mBACR,UAAU,mBACV,4BACA,6BACA,0CACA,QAAQ,kBAAkB,mBAC3B;CACD,IAAI,oBAAoB,OAAO;CAE/B,MAAM,uBAAuB,kBAC3B,QAAQ,gBACR,UAAU,gBACV,yBACA,0BACA,uCACA,QAAQ,kBAAkB,gBAC3B;CACD,IAAI,sBAAsB,OAAO;CAEjC,MAAM,sBAAsB,kBAC1B,QAAQ,aACR,UAAU,aACV,sBACA,uBACA,oCACA,QAAQ,kBAAkB,aAC3B;CACD,IAAI,qBAAqB,OAAO;CAEhC,OAAO,EAAE,MAAM,cAAc"}
@@ -19,6 +19,7 @@ declare const DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS: {
19
19
  maxPayloadHashLength: number;
20
20
  maxVariantCacheKeyLength: number;
21
21
  };
22
+ declare const CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET = 8;
22
23
  type ClientReuseManifestEntryKind = "layout" | "page" | "route" | "slot" | "template";
23
24
  type ClientReuseManifestEntryPrivacy = "private" | "public";
24
25
  type ClientReuseManifestReplayWindow = Readonly<{
@@ -59,8 +60,7 @@ type CreateClientReuseManifestInput = Readonly<{
59
60
  replayWindow?: ClientReuseManifestReplayWindow;
60
61
  visibleCommitVersion: number;
61
62
  }>;
62
- type ClientReuseManifestRejectionCode = "SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE" | "SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN" | "SKIP_CACHE_ARTIFACT_PROOF_MISMATCH" | "SKIP_CACHE_ENTRY_ID_MISMATCH" | "SKIP_CACHE_INVALIDATED" | "SKIP_CACHE_INVALIDATION_UNKNOWN" | "SKIP_CACHE_PAYLOAD_HASH_MISMATCH" | "SKIP_CACHE_PAYLOAD_HASH_MISSING" | "SKIP_CACHE_PROOF_MISSING" | "SKIP_CACHE_PROOF_REJECTED" | "SKIP_CACHE_REUSE_CLASS_UNSUPPORTED" | "SKIP_CACHE_VARIANT_MISMATCH" | "SKIP_ARTIFACT_COMPATIBILITY_INVALID" | "SKIP_ENTRY_COUNT_EXCEEDED" | "SKIP_ENTRY_HASH_INVALID" | "SKIP_ENTRY_ID_INVALID" | "SKIP_ENTRY_ID_TOO_LONG" | "SKIP_ENTRY_MALFORMED" | "SKIP_ENTRY_ORDER_NON_CANONICAL" | "SKIP_HASH_ALGORITHM_UNSUPPORTED" | "SKIP_MANIFEST_MALFORMED" | "SKIP_MANIFEST_SCHEMA_UNSUPPORTED" | "SKIP_MANIFEST_TOO_LARGE" | "SKIP_PRIVATE_ENTRY" | "SKIP_REPLAY_WINDOW_INVALID" | "SKIP_UNKNOWN_ENTRY" | "SKIP_VARIANT_CACHE_KEY_INVALID" | "SKIP_VARIANT_CACHE_KEY_TOO_LONG" | "SKIP_VISIBLE_COMMIT_VERSION_INVALID" | "SKIP_VISIBLE_COMMIT_VERSION_MISMATCH";
63
- type ClientReuseManifestDispositionCode = "SKIP_MODEL_DISABLED";
63
+ type ClientReuseManifestRejectionCode = "SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE" | "SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN" | "SKIP_CACHE_ARTIFACT_PROOF_MISMATCH" | "SKIP_CACHE_ENTRY_ID_MISMATCH" | "SKIP_CACHE_INVALIDATED" | "SKIP_CACHE_INVALIDATION_UNKNOWN" | "SKIP_CACHE_PAYLOAD_HASH_MISMATCH" | "SKIP_CACHE_PAYLOAD_HASH_MISSING" | "SKIP_CACHE_PROOF_MISSING" | "SKIP_CACHE_PROOF_REJECTED" | "SKIP_CACHE_REUSE_CLASS_UNSUPPORTED" | "SKIP_CACHE_VARIANT_MISMATCH" | "SKIP_LAYOUT_CACHE_LIFE_OBSERVED" | "SKIP_LAYOUT_CACHE_TAGS_OBSERVED" | "SKIP_LAYOUT_CACHEABLE_FETCHES_OBSERVED" | "SKIP_LAYOUT_DYNAMIC_FETCHES_OBSERVED" | "SKIP_LAYOUT_PARAMS_OBSERVED" | "SKIP_LAYOUT_PARAMS_OBSERVATION_INCOMPLETE" | "SKIP_LAYOUT_PARAMS_PRESENT" | "SKIP_LAYOUT_REVALIDATE_PRESENT" | "SKIP_LAYOUT_REQUEST_API_OBSERVED" | "SKIP_LAYOUT_UNSTABLE_CACHE_OBSERVED" | "SKIP_ARTIFACT_COMPATIBILITY_INVALID" | "SKIP_ENTRY_COUNT_EXCEEDED" | "SKIP_VERIFICATION_BUDGET_EXCEEDED" | "SKIP_ENTRY_HASH_INVALID" | "SKIP_ENTRY_ID_INVALID" | "SKIP_ENTRY_ID_TOO_LONG" | "SKIP_ENTRY_MALFORMED" | "SKIP_ENTRY_ORDER_NON_CANONICAL" | "SKIP_HASH_ALGORITHM_UNSUPPORTED" | "SKIP_MANIFEST_MALFORMED" | "SKIP_MANIFEST_SCHEMA_UNSUPPORTED" | "SKIP_MANIFEST_TOO_LARGE" | "SKIP_PRIVATE_ENTRY" | "SKIP_REPLAY_WINDOW_INVALID" | "SKIP_UNKNOWN_ENTRY" | "SKIP_VARIANT_CACHE_KEY_INVALID" | "SKIP_VARIANT_CACHE_KEY_TOO_LONG" | "SKIP_VISIBLE_COMMIT_VERSION_INVALID" | "SKIP_VISIBLE_COMMIT_VERSION_MISMATCH";
64
64
  type ClientReuseManifestTraceFieldValue = string | number | boolean | null | readonly string[];
65
65
  type ClientReuseManifestTraceFields = Readonly<Record<string, ClientReuseManifestTraceFieldValue>>;
66
66
  type ClientReuseManifestRejection = Readonly<{
@@ -71,9 +71,14 @@ type ClientReuseManifestEntryRejection = ClientReuseManifestRejection & Readonly
71
71
  entryId: string | null;
72
72
  }>;
73
73
  type ClientReuseManifestSkipDisposition = Readonly<{
74
- code: ClientReuseManifestDispositionCode;
74
+ code: "SKIP_MODEL_DISABLED";
75
75
  enabled: false;
76
76
  mode: "renderAndSend";
77
+ }> | Readonly<{
78
+ code: "SKIP_STATIC_LAYOUT_VERIFIED";
79
+ enabled: true;
80
+ mode: "skipStaticLayout";
81
+ skippedEntryIds: readonly string[];
77
82
  }>;
78
83
  type ClientReuseManifestParseResult = Readonly<{
79
84
  kind: "absent";
@@ -95,5 +100,5 @@ declare function createClientReuseManifest(input: CreateClientReuseManifestInput
95
100
  declare function serializeClientReuseManifest(input: CreateClientReuseManifestInput): string;
96
101
  declare function parseClientReuseManifestHeader(rawHeader: string | null | undefined, options?: ParseClientReuseManifestOptions): ClientReuseManifestParseResult;
97
102
  //#endregion
98
- export { CLIENT_REUSE_MANIFEST_HASH_ALGORITHM, CLIENT_REUSE_MANIFEST_SCHEMA_VERSION, ClientReuseManifest, ClientReuseManifestDispositionCode, ClientReuseManifestEntry, ClientReuseManifestEntryKind, ClientReuseManifestEntryRejection, ClientReuseManifestHashAlgorithm, ClientReuseManifestParseResult, ClientReuseManifestRejection, ClientReuseManifestRejectionCode, ClientReuseManifestReplayWindow, ClientReuseManifestSchemaVersion, ClientReuseManifestSkipDisposition, ClientReuseManifestTraceFieldValue, ClientReuseManifestTraceFields, DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, createClientReuseManifest, createClientReusePayloadHash, parseClientReuseManifestHeader, serializeClientReuseManifest };
103
+ export { CLIENT_REUSE_MANIFEST_HASH_ALGORITHM, CLIENT_REUSE_MANIFEST_SCHEMA_VERSION, CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET, ClientReuseManifest, ClientReuseManifestEntry, ClientReuseManifestEntryKind, ClientReuseManifestEntryRejection, ClientReuseManifestHashAlgorithm, ClientReuseManifestParseResult, ClientReuseManifestRejection, ClientReuseManifestRejectionCode, ClientReuseManifestReplayWindow, ClientReuseManifestSchemaVersion, ClientReuseManifestSkipDisposition, ClientReuseManifestTraceFieldValue, ClientReuseManifestTraceFields, DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, createClientReuseManifest, createClientReusePayloadHash, parseClientReuseManifestHeader, serializeClientReuseManifest };
99
104
  //# sourceMappingURL=client-reuse-manifest.d.ts.map
@@ -12,6 +12,7 @@ const DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS = {
12
12
  maxPayloadHashLength: 16,
13
13
  maxVariantCacheKeyLength: 256
14
14
  };
15
+ const CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET = 8;
15
16
  const HASH_DIGEST_PATTERN = /^[0-9a-z]+$/;
16
17
  const textEncoder = new TextEncoder();
17
18
  function createRejection(code, fields = {}) {
@@ -207,6 +208,6 @@ function parseClientReuseManifestHeader(rawHeader, options = {}) {
207
208
  };
208
209
  }
209
210
  //#endregion
210
- export { CLIENT_REUSE_MANIFEST_HASH_ALGORITHM, CLIENT_REUSE_MANIFEST_SCHEMA_VERSION, DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, createClientReuseManifest, createClientReusePayloadHash, parseClientReuseManifestHeader, serializeClientReuseManifest };
211
+ export { CLIENT_REUSE_MANIFEST_HASH_ALGORITHM, CLIENT_REUSE_MANIFEST_SCHEMA_VERSION, CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET, DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS, createClientReuseManifest, createClientReusePayloadHash, parseClientReuseManifestHeader, serializeClientReuseManifest };
211
212
 
212
213
  //# sourceMappingURL=client-reuse-manifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-reuse-manifest.js","names":[],"sources":["../../src/server/client-reuse-manifest.ts"],"sourcesContent":["import {\n parseArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEnvelope,\n} from \"./artifact-compatibility.js\";\nimport { AppElementsWire } from \"./app-elements-wire.js\";\nimport { fnv1a64 } from \"../utils/hash.js\";\nimport { isUnknownRecord } from \"../utils/record.js\";\n\nexport const CLIENT_REUSE_MANIFEST_SCHEMA_VERSION = 1;\nexport type ClientReuseManifestSchemaVersion = 1;\n\nexport const CLIENT_REUSE_MANIFEST_HASH_ALGORITHM = \"fnv1a64\";\nexport type ClientReuseManifestHashAlgorithm = typeof CLIENT_REUSE_MANIFEST_HASH_ALGORITHM;\n\ntype ClientReuseManifestLimits = Readonly<{\n maxEntryCount: number;\n maxEntryIdLength: number;\n maxManifestBytes: number;\n maxPayloadHashLength: number;\n maxVariantCacheKeyLength: number;\n}>;\n\nexport const DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS = {\n maxEntryCount: 64,\n maxEntryIdLength: 512,\n maxManifestBytes: 4096,\n maxPayloadHashLength: 16,\n maxVariantCacheKeyLength: 256,\n} satisfies ClientReuseManifestLimits;\n\nexport type ClientReuseManifestEntryKind = \"layout\" | \"page\" | \"route\" | \"slot\" | \"template\";\ntype ClientReuseManifestEntryPrivacy = \"private\" | \"public\";\n\nexport type ClientReuseManifestReplayWindow = Readonly<{\n validFromVisibleCommitVersion: number;\n validUntilVisibleCommitVersion: number;\n}>;\n\nexport type ClientReuseManifestEntry = Readonly<{\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n id: string;\n kind: ClientReuseManifestEntryKind;\n payloadHash: string;\n privacy: \"public\";\n variantCacheKey: string;\n}>;\n\ntype ClientReuseManifestWireEntry = Readonly<{\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n id: string;\n payloadHash: string;\n privacy: ClientReuseManifestEntryPrivacy;\n variantCacheKey: string;\n}>;\n\nexport type ClientReuseManifest = Readonly<{\n entries: readonly ClientReuseManifestEntry[];\n hashAlgorithm: ClientReuseManifestHashAlgorithm;\n replayWindow: ClientReuseManifestReplayWindow;\n schemaVersion: ClientReuseManifestSchemaVersion;\n visibleCommitVersion: number;\n}>;\n\n// Internal: createClientReuseManifest returns wire shape while parsing decides\n// which client-declared entries can participate in future reuse.\ntype ClientReuseManifestWire = Readonly<{\n entries: readonly ClientReuseManifestWireEntry[];\n hashAlgorithm: ClientReuseManifestHashAlgorithm;\n replayWindow: ClientReuseManifestReplayWindow;\n schemaVersion: ClientReuseManifestSchemaVersion;\n visibleCommitVersion: number;\n}>;\n\ntype CreateClientReuseManifestInput = Readonly<{\n entries: readonly ClientReuseManifestWireEntry[];\n replayWindow?: ClientReuseManifestReplayWindow;\n visibleCommitVersion: number;\n}>;\n\nexport type ClientReuseManifestRejectionCode =\n | \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE\"\n | \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN\"\n | \"SKIP_CACHE_ARTIFACT_PROOF_MISMATCH\"\n | \"SKIP_CACHE_ENTRY_ID_MISMATCH\"\n | \"SKIP_CACHE_INVALIDATED\"\n | \"SKIP_CACHE_INVALIDATION_UNKNOWN\"\n | \"SKIP_CACHE_PAYLOAD_HASH_MISMATCH\"\n | \"SKIP_CACHE_PAYLOAD_HASH_MISSING\"\n | \"SKIP_CACHE_PROOF_MISSING\"\n | \"SKIP_CACHE_PROOF_REJECTED\"\n | \"SKIP_CACHE_REUSE_CLASS_UNSUPPORTED\"\n | \"SKIP_CACHE_VARIANT_MISMATCH\"\n | \"SKIP_ARTIFACT_COMPATIBILITY_INVALID\"\n | \"SKIP_ENTRY_COUNT_EXCEEDED\"\n | \"SKIP_ENTRY_HASH_INVALID\"\n | \"SKIP_ENTRY_ID_INVALID\"\n | \"SKIP_ENTRY_ID_TOO_LONG\"\n | \"SKIP_ENTRY_MALFORMED\"\n | \"SKIP_ENTRY_ORDER_NON_CANONICAL\"\n | \"SKIP_HASH_ALGORITHM_UNSUPPORTED\"\n | \"SKIP_MANIFEST_MALFORMED\"\n | \"SKIP_MANIFEST_SCHEMA_UNSUPPORTED\"\n | \"SKIP_MANIFEST_TOO_LARGE\"\n | \"SKIP_PRIVATE_ENTRY\"\n | \"SKIP_REPLAY_WINDOW_INVALID\"\n | \"SKIP_UNKNOWN_ENTRY\"\n | \"SKIP_VARIANT_CACHE_KEY_INVALID\"\n | \"SKIP_VARIANT_CACHE_KEY_TOO_LONG\"\n | \"SKIP_VISIBLE_COMMIT_VERSION_INVALID\"\n | \"SKIP_VISIBLE_COMMIT_VERSION_MISMATCH\";\n\nexport type ClientReuseManifestDispositionCode = \"SKIP_MODEL_DISABLED\";\n\nexport type ClientReuseManifestTraceFieldValue =\n | string\n | number\n | boolean\n | null\n | readonly string[];\n\nexport type ClientReuseManifestTraceFields = Readonly<\n Record<string, ClientReuseManifestTraceFieldValue>\n>;\n\nexport type ClientReuseManifestRejection = Readonly<{\n code: ClientReuseManifestRejectionCode;\n fields: ClientReuseManifestTraceFields;\n}>;\n\nexport type ClientReuseManifestEntryRejection = ClientReuseManifestRejection &\n Readonly<{\n entryId: string | null;\n }>;\n\nexport type ClientReuseManifestSkipDisposition = Readonly<{\n code: ClientReuseManifestDispositionCode;\n enabled: false;\n mode: \"renderAndSend\";\n}>;\n\nexport type ClientReuseManifestParseResult =\n | Readonly<{ kind: \"absent\" }>\n | Readonly<{ kind: \"rejected\"; rejection: ClientReuseManifestRejection }>\n | Readonly<{\n entryRejections: readonly ClientReuseManifestEntryRejection[];\n kind: \"parsed\";\n manifest: ClientReuseManifest;\n skipDisposition: ClientReuseManifestSkipDisposition;\n }>;\n\ntype ParseClientReuseManifestOptions = Readonly<{\n currentVisibleCommitVersion?: number;\n limits?: ClientReuseManifestLimits;\n}>;\n\nconst HASH_DIGEST_PATTERN = /^[0-9a-z]+$/;\nconst textEncoder = new TextEncoder();\n\ntype ParseReplayWindowResult =\n | Readonly<{ kind: \"parsed\"; replayWindow: ClientReuseManifestReplayWindow }>\n | Readonly<{ kind: \"rejected\"; rejection: ClientReuseManifestRejection }>;\n\nfunction createRejection(\n code: ClientReuseManifestRejectionCode,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestRejection {\n return { code, fields };\n}\n\nfunction rejectManifest(\n code: ClientReuseManifestRejectionCode,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestParseResult {\n return { kind: \"rejected\", rejection: createRejection(code, fields) };\n}\n\nfunction rejectEntry(\n code: ClientReuseManifestRejectionCode,\n entryId: string | null,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestEntryRejection {\n return { code, entryId, fields };\n}\n\nfunction compareManifestEntries(\n left: Pick<ClientReuseManifestWireEntry, \"id\">,\n right: Pick<ClientReuseManifestWireEntry, \"id\">,\n): number {\n if (left.id < right.id) return -1;\n if (left.id > right.id) return 1;\n return 0;\n}\n\nfunction createCanonicalWireEntries(\n entries: readonly ClientReuseManifestWireEntry[],\n): ClientReuseManifestWireEntry[] {\n const entriesById = new Map<string, ClientReuseManifestWireEntry>();\n for (const entry of entries) {\n if (!entriesById.has(entry.id)) {\n entriesById.set(entry.id, entry);\n }\n }\n\n return Array.from(entriesById.values()).sort(compareManifestEntries);\n}\n\n// The manifest byte budget is enforced once at the untrusted header boundary.\nfunction countUtf8Bytes(input: string): number {\n return textEncoder.encode(input).length;\n}\n\nfunction isVisibleCommitVersion(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction parseReplayWindow(value: unknown, visibleCommitVersion: number): ParseReplayWindowResult {\n if (!isUnknownRecord(value)) {\n return {\n kind: \"rejected\",\n rejection: createRejection(\"SKIP_REPLAY_WINDOW_INVALID\", { field: \"replayWindow\" }),\n };\n }\n\n const validFromVisibleCommitVersion = value.validFromVisibleCommitVersion;\n const validUntilVisibleCommitVersion = value.validUntilVisibleCommitVersion;\n if (\n !isVisibleCommitVersion(validFromVisibleCommitVersion) ||\n !isVisibleCommitVersion(validUntilVisibleCommitVersion) ||\n validFromVisibleCommitVersion > validUntilVisibleCommitVersion ||\n visibleCommitVersion < validFromVisibleCommitVersion ||\n visibleCommitVersion > validUntilVisibleCommitVersion\n ) {\n return {\n kind: \"rejected\",\n rejection: createRejection(\"SKIP_REPLAY_WINDOW_INVALID\", {\n validFromVisibleCommitVersion: isVisibleCommitVersion(validFromVisibleCommitVersion)\n ? validFromVisibleCommitVersion\n : null,\n validUntilVisibleCommitVersion: isVisibleCommitVersion(validUntilVisibleCommitVersion)\n ? validUntilVisibleCommitVersion\n : null,\n visibleCommitVersion,\n }),\n };\n }\n\n return {\n kind: \"parsed\",\n replayWindow: {\n validFromVisibleCommitVersion,\n validUntilVisibleCommitVersion,\n },\n };\n}\n\nfunction currentCommitVersionMatchesReplayWindow(\n currentVisibleCommitVersion: number | undefined,\n replayWindow: ClientReuseManifestReplayWindow,\n): boolean {\n if (currentVisibleCommitVersion === undefined) return true;\n return (\n currentVisibleCommitVersion >= replayWindow.validFromVisibleCommitVersion &&\n currentVisibleCommitVersion <= replayWindow.validUntilVisibleCommitVersion\n );\n}\n\nfunction parseEntryKind(id: string): ClientReuseManifestEntryKind | null {\n const parsed = AppElementsWire.parseElementKey(id);\n if (parsed === null) return null;\n return parsed.kind;\n}\n\nfunction isValidPayloadHash(value: unknown, limits: ClientReuseManifestLimits): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n value.length <= limits.maxPayloadHashLength &&\n HASH_DIGEST_PATTERN.test(value)\n );\n}\n\nfunction parseManifestEntry(\n value: unknown,\n limits: ClientReuseManifestLimits,\n index: number,\n): ClientReuseManifestEntry | ClientReuseManifestEntryRejection {\n if (!isUnknownRecord(value)) {\n return rejectEntry(\"SKIP_ENTRY_MALFORMED\", null, { index });\n }\n\n const id = value.id;\n if (typeof id !== \"string\" || id.length === 0) {\n return rejectEntry(\"SKIP_ENTRY_ID_INVALID\", null, { index });\n }\n if (id.length > limits.maxEntryIdLength) {\n return rejectEntry(\"SKIP_ENTRY_ID_TOO_LONG\", id, {\n idHash: createClientReusePayloadHash(id),\n maxEntryIdLength: limits.maxEntryIdLength,\n });\n }\n\n const kind = parseEntryKind(id);\n if (kind === null) {\n return rejectEntry(\"SKIP_UNKNOWN_ENTRY\", id, { idHash: createClientReusePayloadHash(id) });\n }\n\n const privacy = value.privacy;\n if (privacy === \"private\") {\n return rejectEntry(\"SKIP_PRIVATE_ENTRY\", id, { privacy });\n }\n if (privacy !== \"public\") {\n return rejectEntry(\"SKIP_ENTRY_MALFORMED\", id, { field: \"privacy\" });\n }\n\n const payloadHash = value.payloadHash;\n if (!isValidPayloadHash(payloadHash, limits)) {\n return rejectEntry(\"SKIP_ENTRY_HASH_INVALID\", id, {\n maxPayloadHashLength: limits.maxPayloadHashLength,\n });\n }\n\n const variantCacheKey = value.variantCacheKey;\n if (typeof variantCacheKey !== \"string\" || variantCacheKey.length === 0) {\n return rejectEntry(\"SKIP_VARIANT_CACHE_KEY_INVALID\", id, { field: \"variantCacheKey\" });\n }\n if (variantCacheKey.length > limits.maxVariantCacheKeyLength) {\n return rejectEntry(\"SKIP_VARIANT_CACHE_KEY_TOO_LONG\", id, {\n maxVariantCacheKeyLength: limits.maxVariantCacheKeyLength,\n variantCacheKeyHash: createClientReusePayloadHash(variantCacheKey),\n });\n }\n\n const artifactCompatibility = parseArtifactCompatibilityEnvelope(value.artifactCompatibility);\n if (artifactCompatibility === null) {\n return rejectEntry(\"SKIP_ARTIFACT_COMPATIBILITY_INVALID\", id, {\n field: \"artifactCompatibility\",\n });\n }\n\n return {\n artifactCompatibility,\n id,\n kind,\n payloadHash,\n privacy,\n variantCacheKey,\n };\n}\n\nexport function createClientReusePayloadHash(input: string): string {\n return fnv1a64(input);\n}\n\nexport function createClientReuseManifest(\n input: CreateClientReuseManifestInput,\n): ClientReuseManifestWire {\n const replayWindow =\n input.replayWindow ??\n ({\n validFromVisibleCommitVersion: input.visibleCommitVersion,\n validUntilVisibleCommitVersion: input.visibleCommitVersion,\n } satisfies ClientReuseManifestReplayWindow);\n\n return {\n entries: createCanonicalWireEntries(input.entries),\n hashAlgorithm: CLIENT_REUSE_MANIFEST_HASH_ALGORITHM,\n replayWindow,\n schemaVersion: CLIENT_REUSE_MANIFEST_SCHEMA_VERSION,\n visibleCommitVersion: input.visibleCommitVersion,\n };\n}\n\nexport function serializeClientReuseManifest(input: CreateClientReuseManifestInput): string {\n return JSON.stringify(createClientReuseManifest(input));\n}\n\nexport function parseClientReuseManifestHeader(\n rawHeader: string | null | undefined,\n options: ParseClientReuseManifestOptions = {},\n): ClientReuseManifestParseResult {\n const header = rawHeader?.trim();\n if (!header) return { kind: \"absent\" };\n\n const limits = options.limits ?? DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS;\n const manifestBytes = countUtf8Bytes(header);\n if (manifestBytes > limits.maxManifestBytes) {\n return rejectManifest(\"SKIP_MANIFEST_TOO_LARGE\", {\n manifestBytes,\n maxManifestBytes: limits.maxManifestBytes,\n });\n }\n\n let decoded: unknown;\n try {\n decoded = JSON.parse(header);\n } catch {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\");\n }\n\n if (!isUnknownRecord(decoded)) {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\", { field: \"manifest\" });\n }\n\n if (decoded.schemaVersion !== CLIENT_REUSE_MANIFEST_SCHEMA_VERSION) {\n return rejectManifest(\"SKIP_MANIFEST_SCHEMA_UNSUPPORTED\", {\n schemaVersion:\n typeof decoded.schemaVersion === \"number\" || typeof decoded.schemaVersion === \"string\"\n ? decoded.schemaVersion\n : null,\n });\n }\n\n if (decoded.hashAlgorithm !== CLIENT_REUSE_MANIFEST_HASH_ALGORITHM) {\n return rejectManifest(\"SKIP_HASH_ALGORITHM_UNSUPPORTED\", {\n hashAlgorithm: typeof decoded.hashAlgorithm === \"string\" ? decoded.hashAlgorithm : null,\n });\n }\n\n const visibleCommitVersion = decoded.visibleCommitVersion;\n if (!isVisibleCommitVersion(visibleCommitVersion)) {\n return rejectManifest(\"SKIP_VISIBLE_COMMIT_VERSION_INVALID\", {\n visibleCommitVersion: null,\n });\n }\n\n const replayWindowResult = parseReplayWindow(decoded.replayWindow, visibleCommitVersion);\n if (replayWindowResult.kind === \"rejected\") {\n return { kind: \"rejected\", rejection: replayWindowResult.rejection };\n }\n const { replayWindow } = replayWindowResult;\n if (!currentCommitVersionMatchesReplayWindow(options.currentVisibleCommitVersion, replayWindow)) {\n return rejectManifest(\"SKIP_VISIBLE_COMMIT_VERSION_MISMATCH\", {\n currentVisibleCommitVersion: options.currentVisibleCommitVersion ?? null,\n validFromVisibleCommitVersion: replayWindow.validFromVisibleCommitVersion,\n validUntilVisibleCommitVersion: replayWindow.validUntilVisibleCommitVersion,\n visibleCommitVersion,\n });\n }\n\n const entriesValue = decoded.entries;\n if (!Array.isArray(entriesValue)) {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\", { field: \"entries\" });\n }\n if (entriesValue.length > limits.maxEntryCount) {\n return rejectManifest(\"SKIP_ENTRY_COUNT_EXCEEDED\", {\n entryCount: entriesValue.length,\n maxEntryCount: limits.maxEntryCount,\n });\n }\n\n const entries: ClientReuseManifestEntry[] = [];\n const entryRejections: ClientReuseManifestEntryRejection[] = [];\n let previousEntryId: string | null = null;\n\n for (let index = 0; index < entriesValue.length; index++) {\n const value = entriesValue[index];\n if (isUnknownRecord(value) && typeof value.id === \"string\") {\n // Canonical ordering is enforced over entries with string IDs. Malformed\n // entries cannot advance previousEntryId, so interleaving them cannot hide\n // an ordering violation between valid checkpoints. <= rejects both\n // out-of-order and duplicate IDs.\n if (previousEntryId !== null && value.id <= previousEntryId) {\n return rejectManifest(\"SKIP_ENTRY_ORDER_NON_CANONICAL\", {\n entryIdHash: createClientReusePayloadHash(value.id),\n previousEntryIdHash: createClientReusePayloadHash(previousEntryId),\n });\n }\n previousEntryId = value.id;\n }\n\n const parsedEntry = parseManifestEntry(value, limits, index);\n if (\"code\" in parsedEntry) {\n entryRejections.push(parsedEntry);\n } else {\n entries.push(parsedEntry);\n }\n }\n\n return {\n entryRejections,\n kind: \"parsed\",\n manifest: {\n entries,\n hashAlgorithm: CLIENT_REUSE_MANIFEST_HASH_ALGORITHM,\n replayWindow,\n schemaVersion: CLIENT_REUSE_MANIFEST_SCHEMA_VERSION,\n visibleCommitVersion,\n },\n skipDisposition: {\n code: \"SKIP_MODEL_DISABLED\",\n enabled: false,\n mode: \"renderAndSend\",\n },\n };\n}\n"],"mappings":";;;;;AAQA,MAAa,uCAAuC;AAGpD,MAAa,uCAAuC;AAWpD,MAAa,uCAAuC;CAClD,eAAe;CACf,kBAAkB;CAClB,kBAAkB;CAClB,sBAAsB;CACtB,0BAA0B;CAC3B;AA+HD,MAAM,sBAAsB;AAC5B,MAAM,cAAc,IAAI,aAAa;AAMrC,SAAS,gBACP,MACA,SAAyC,EAAE,EACb;CAC9B,OAAO;EAAE;EAAM;EAAQ;;AAGzB,SAAS,eACP,MACA,SAAyC,EAAE,EACX;CAChC,OAAO;EAAE,MAAM;EAAY,WAAW,gBAAgB,MAAM,OAAO;EAAE;;AAGvE,SAAS,YACP,MACA,SACA,SAAyC,EAAE,EACR;CACnC,OAAO;EAAE;EAAM;EAAS;EAAQ;;AAGlC,SAAS,uBACP,MACA,OACQ;CACR,IAAI,KAAK,KAAK,MAAM,IAAI,OAAO;CAC/B,IAAI,KAAK,KAAK,MAAM,IAAI,OAAO;CAC/B,OAAO;;AAGT,SAAS,2BACP,SACgC;CAChC,MAAM,8BAAc,IAAI,KAA2C;CACnE,KAAK,MAAM,SAAS,SAClB,IAAI,CAAC,YAAY,IAAI,MAAM,GAAG,EAC5B,YAAY,IAAI,MAAM,IAAI,MAAM;CAIpC,OAAO,MAAM,KAAK,YAAY,QAAQ,CAAC,CAAC,KAAK,uBAAuB;;AAItE,SAAS,eAAe,OAAuB;CAC7C,OAAO,YAAY,OAAO,MAAM,CAAC;;AAGnC,SAAS,uBAAuB,OAAiC;CAC/D,OAAO,OAAO,UAAU,YAAY,OAAO,cAAc,MAAM,IAAI,SAAS;;AAG9E,SAAS,kBAAkB,OAAgB,sBAAuD;CAChG,IAAI,CAAC,gBAAgB,MAAM,EACzB,OAAO;EACL,MAAM;EACN,WAAW,gBAAgB,8BAA8B,EAAE,OAAO,gBAAgB,CAAC;EACpF;CAGH,MAAM,gCAAgC,MAAM;CAC5C,MAAM,iCAAiC,MAAM;CAC7C,IACE,CAAC,uBAAuB,8BAA8B,IACtD,CAAC,uBAAuB,+BAA+B,IACvD,gCAAgC,kCAChC,uBAAuB,iCACvB,uBAAuB,gCAEvB,OAAO;EACL,MAAM;EACN,WAAW,gBAAgB,8BAA8B;GACvD,+BAA+B,uBAAuB,8BAA8B,GAChF,gCACA;GACJ,gCAAgC,uBAAuB,+BAA+B,GAClF,iCACA;GACJ;GACD,CAAC;EACH;CAGH,OAAO;EACL,MAAM;EACN,cAAc;GACZ;GACA;GACD;EACF;;AAGH,SAAS,wCACP,6BACA,cACS;CACT,IAAI,gCAAgC,KAAA,GAAW,OAAO;CACtD,OACE,+BAA+B,aAAa,iCAC5C,+BAA+B,aAAa;;AAIhD,SAAS,eAAe,IAAiD;CACvE,MAAM,SAAS,gBAAgB,gBAAgB,GAAG;CAClD,IAAI,WAAW,MAAM,OAAO;CAC5B,OAAO,OAAO;;AAGhB,SAAS,mBAAmB,OAAgB,QAAoD;CAC9F,OACE,OAAO,UAAU,YACjB,MAAM,SAAS,KACf,MAAM,UAAU,OAAO,wBACvB,oBAAoB,KAAK,MAAM;;AAInC,SAAS,mBACP,OACA,QACA,OAC8D;CAC9D,IAAI,CAAC,gBAAgB,MAAM,EACzB,OAAO,YAAY,wBAAwB,MAAM,EAAE,OAAO,CAAC;CAG7D,MAAM,KAAK,MAAM;CACjB,IAAI,OAAO,OAAO,YAAY,GAAG,WAAW,GAC1C,OAAO,YAAY,yBAAyB,MAAM,EAAE,OAAO,CAAC;CAE9D,IAAI,GAAG,SAAS,OAAO,kBACrB,OAAO,YAAY,0BAA0B,IAAI;EAC/C,QAAQ,6BAA6B,GAAG;EACxC,kBAAkB,OAAO;EAC1B,CAAC;CAGJ,MAAM,OAAO,eAAe,GAAG;CAC/B,IAAI,SAAS,MACX,OAAO,YAAY,sBAAsB,IAAI,EAAE,QAAQ,6BAA6B,GAAG,EAAE,CAAC;CAG5F,MAAM,UAAU,MAAM;CACtB,IAAI,YAAY,WACd,OAAO,YAAY,sBAAsB,IAAI,EAAE,SAAS,CAAC;CAE3D,IAAI,YAAY,UACd,OAAO,YAAY,wBAAwB,IAAI,EAAE,OAAO,WAAW,CAAC;CAGtE,MAAM,cAAc,MAAM;CAC1B,IAAI,CAAC,mBAAmB,aAAa,OAAO,EAC1C,OAAO,YAAY,2BAA2B,IAAI,EAChD,sBAAsB,OAAO,sBAC9B,CAAC;CAGJ,MAAM,kBAAkB,MAAM;CAC9B,IAAI,OAAO,oBAAoB,YAAY,gBAAgB,WAAW,GACpE,OAAO,YAAY,kCAAkC,IAAI,EAAE,OAAO,mBAAmB,CAAC;CAExF,IAAI,gBAAgB,SAAS,OAAO,0BAClC,OAAO,YAAY,mCAAmC,IAAI;EACxD,0BAA0B,OAAO;EACjC,qBAAqB,6BAA6B,gBAAgB;EACnE,CAAC;CAGJ,MAAM,wBAAwB,mCAAmC,MAAM,sBAAsB;CAC7F,IAAI,0BAA0B,MAC5B,OAAO,YAAY,uCAAuC,IAAI,EAC5D,OAAO,yBACR,CAAC;CAGJ,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;;AAGH,SAAgB,6BAA6B,OAAuB;CAClE,OAAO,QAAQ,MAAM;;AAGvB,SAAgB,0BACd,OACyB;CACzB,MAAM,eACJ,MAAM,gBACL;EACC,+BAA+B,MAAM;EACrC,gCAAgC,MAAM;EACvC;CAEH,OAAO;EACL,SAAS,2BAA2B,MAAM,QAAQ;EAClD,eAAe;EACf;EACA,eAAA;EACA,sBAAsB,MAAM;EAC7B;;AAGH,SAAgB,6BAA6B,OAA+C;CAC1F,OAAO,KAAK,UAAU,0BAA0B,MAAM,CAAC;;AAGzD,SAAgB,+BACd,WACA,UAA2C,EAAE,EACb;CAChC,MAAM,SAAS,WAAW,MAAM;CAChC,IAAI,CAAC,QAAQ,OAAO,EAAE,MAAM,UAAU;CAEtC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,gBAAgB,eAAe,OAAO;CAC5C,IAAI,gBAAgB,OAAO,kBACzB,OAAO,eAAe,2BAA2B;EAC/C;EACA,kBAAkB,OAAO;EAC1B,CAAC;CAGJ,IAAI;CACJ,IAAI;EACF,UAAU,KAAK,MAAM,OAAO;SACtB;EACN,OAAO,eAAe,0BAA0B;;CAGlD,IAAI,CAAC,gBAAgB,QAAQ,EAC3B,OAAO,eAAe,2BAA2B,EAAE,OAAO,YAAY,CAAC;CAGzE,IAAI,QAAQ,kBAAA,GACV,OAAO,eAAe,oCAAoC,EACxD,eACE,OAAO,QAAQ,kBAAkB,YAAY,OAAO,QAAQ,kBAAkB,WAC1E,QAAQ,gBACR,MACP,CAAC;CAGJ,IAAI,QAAQ,kBAAA,WACV,OAAO,eAAe,mCAAmC,EACvD,eAAe,OAAO,QAAQ,kBAAkB,WAAW,QAAQ,gBAAgB,MACpF,CAAC;CAGJ,MAAM,uBAAuB,QAAQ;CACrC,IAAI,CAAC,uBAAuB,qBAAqB,EAC/C,OAAO,eAAe,uCAAuC,EAC3D,sBAAsB,MACvB,CAAC;CAGJ,MAAM,qBAAqB,kBAAkB,QAAQ,cAAc,qBAAqB;CACxF,IAAI,mBAAmB,SAAS,YAC9B,OAAO;EAAE,MAAM;EAAY,WAAW,mBAAmB;EAAW;CAEtE,MAAM,EAAE,iBAAiB;CACzB,IAAI,CAAC,wCAAwC,QAAQ,6BAA6B,aAAa,EAC7F,OAAO,eAAe,wCAAwC;EAC5D,6BAA6B,QAAQ,+BAA+B;EACpE,+BAA+B,aAAa;EAC5C,gCAAgC,aAAa;EAC7C;EACD,CAAC;CAGJ,MAAM,eAAe,QAAQ;CAC7B,IAAI,CAAC,MAAM,QAAQ,aAAa,EAC9B,OAAO,eAAe,2BAA2B,EAAE,OAAO,WAAW,CAAC;CAExE,IAAI,aAAa,SAAS,OAAO,eAC/B,OAAO,eAAe,6BAA6B;EACjD,YAAY,aAAa;EACzB,eAAe,OAAO;EACvB,CAAC;CAGJ,MAAM,UAAsC,EAAE;CAC9C,MAAM,kBAAuD,EAAE;CAC/D,IAAI,kBAAiC;CAErC,KAAK,IAAI,QAAQ,GAAG,QAAQ,aAAa,QAAQ,SAAS;EACxD,MAAM,QAAQ,aAAa;EAC3B,IAAI,gBAAgB,MAAM,IAAI,OAAO,MAAM,OAAO,UAAU;GAK1D,IAAI,oBAAoB,QAAQ,MAAM,MAAM,iBAC1C,OAAO,eAAe,kCAAkC;IACtD,aAAa,6BAA6B,MAAM,GAAG;IACnD,qBAAqB,6BAA6B,gBAAgB;IACnE,CAAC;GAEJ,kBAAkB,MAAM;;EAG1B,MAAM,cAAc,mBAAmB,OAAO,QAAQ,MAAM;EAC5D,IAAI,UAAU,aACZ,gBAAgB,KAAK,YAAY;OAEjC,QAAQ,KAAK,YAAY;;CAI7B,OAAO;EACL;EACA,MAAM;EACN,UAAU;GACR;GACA,eAAe;GACf;GACA,eAAA;GACA;GACD;EACD,iBAAiB;GACf,MAAM;GACN,SAAS;GACT,MAAM;GACP;EACF"}
1
+ {"version":3,"file":"client-reuse-manifest.js","names":[],"sources":["../../src/server/client-reuse-manifest.ts"],"sourcesContent":["import {\n parseArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEnvelope,\n} from \"./artifact-compatibility.js\";\nimport { AppElementsWire } from \"./app-elements-wire.js\";\nimport { fnv1a64 } from \"../utils/hash.js\";\nimport { isUnknownRecord } from \"../utils/record.js\";\n\nexport const CLIENT_REUSE_MANIFEST_SCHEMA_VERSION = 1;\nexport type ClientReuseManifestSchemaVersion = 1;\n\nexport const CLIENT_REUSE_MANIFEST_HASH_ALGORITHM = \"fnv1a64\";\nexport type ClientReuseManifestHashAlgorithm = typeof CLIENT_REUSE_MANIFEST_HASH_ALGORITHM;\n\ntype ClientReuseManifestLimits = Readonly<{\n maxEntryCount: number;\n maxEntryIdLength: number;\n maxManifestBytes: number;\n maxPayloadHashLength: number;\n maxVariantCacheKeyLength: number;\n}>;\n\nexport const DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS = {\n maxEntryCount: 64,\n maxEntryIdLength: 512,\n maxManifestBytes: 4096,\n maxPayloadHashLength: 16,\n maxVariantCacheKeyLength: 256,\n} satisfies ClientReuseManifestLimits;\n\n// Producer cap for normal browser manifests. The parser accepts a larger\n// hostile-input envelope, but browser-produced manifests should stay within\n// the server skip planner's verification budget.\nexport const CLIENT_REUSE_MANIFEST_SKIP_VERIFICATION_ENTRY_BUDGET = 8;\n\nexport type ClientReuseManifestEntryKind = \"layout\" | \"page\" | \"route\" | \"slot\" | \"template\";\ntype ClientReuseManifestEntryPrivacy = \"private\" | \"public\";\n\nexport type ClientReuseManifestReplayWindow = Readonly<{\n validFromVisibleCommitVersion: number;\n validUntilVisibleCommitVersion: number;\n}>;\n\nexport type ClientReuseManifestEntry = Readonly<{\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n id: string;\n kind: ClientReuseManifestEntryKind;\n payloadHash: string;\n privacy: \"public\";\n variantCacheKey: string;\n}>;\n\ntype ClientReuseManifestWireEntry = Readonly<{\n artifactCompatibility: ArtifactCompatibilityEnvelope;\n id: string;\n payloadHash: string;\n privacy: ClientReuseManifestEntryPrivacy;\n variantCacheKey: string;\n}>;\n\nexport type ClientReuseManifest = Readonly<{\n entries: readonly ClientReuseManifestEntry[];\n hashAlgorithm: ClientReuseManifestHashAlgorithm;\n replayWindow: ClientReuseManifestReplayWindow;\n schemaVersion: ClientReuseManifestSchemaVersion;\n visibleCommitVersion: number;\n}>;\n\n// Internal: createClientReuseManifest returns wire shape while parsing decides\n// which client-declared entries can participate in future reuse.\ntype ClientReuseManifestWire = Readonly<{\n entries: readonly ClientReuseManifestWireEntry[];\n hashAlgorithm: ClientReuseManifestHashAlgorithm;\n replayWindow: ClientReuseManifestReplayWindow;\n schemaVersion: ClientReuseManifestSchemaVersion;\n visibleCommitVersion: number;\n}>;\n\ntype CreateClientReuseManifestInput = Readonly<{\n entries: readonly ClientReuseManifestWireEntry[];\n replayWindow?: ClientReuseManifestReplayWindow;\n visibleCommitVersion: number;\n}>;\n\nexport type ClientReuseManifestRejectionCode =\n | \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE\"\n | \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN\"\n | \"SKIP_CACHE_ARTIFACT_PROOF_MISMATCH\"\n | \"SKIP_CACHE_ENTRY_ID_MISMATCH\"\n | \"SKIP_CACHE_INVALIDATED\"\n | \"SKIP_CACHE_INVALIDATION_UNKNOWN\"\n | \"SKIP_CACHE_PAYLOAD_HASH_MISMATCH\"\n | \"SKIP_CACHE_PAYLOAD_HASH_MISSING\"\n | \"SKIP_CACHE_PROOF_MISSING\"\n | \"SKIP_CACHE_PROOF_REJECTED\"\n | \"SKIP_CACHE_REUSE_CLASS_UNSUPPORTED\"\n | \"SKIP_CACHE_VARIANT_MISMATCH\"\n // Forward declarations — emitted by the render-observation tracker in a\n // later slice. The planner never produces them, but the rejection code\n // union must carry them so the tracker's entry rejection is assignable to\n // ClientReuseManifestRejectionCode without a cast.\n | \"SKIP_LAYOUT_CACHE_LIFE_OBSERVED\"\n | \"SKIP_LAYOUT_CACHE_TAGS_OBSERVED\"\n | \"SKIP_LAYOUT_CACHEABLE_FETCHES_OBSERVED\"\n | \"SKIP_LAYOUT_DYNAMIC_FETCHES_OBSERVED\"\n | \"SKIP_LAYOUT_PARAMS_OBSERVED\"\n | \"SKIP_LAYOUT_PARAMS_OBSERVATION_INCOMPLETE\"\n | \"SKIP_LAYOUT_PARAMS_PRESENT\"\n | \"SKIP_LAYOUT_REVALIDATE_PRESENT\"\n | \"SKIP_LAYOUT_REQUEST_API_OBSERVED\"\n | \"SKIP_LAYOUT_UNSTABLE_CACHE_OBSERVED\"\n | \"SKIP_ARTIFACT_COMPATIBILITY_INVALID\"\n | \"SKIP_ENTRY_COUNT_EXCEEDED\"\n | \"SKIP_VERIFICATION_BUDGET_EXCEEDED\"\n | \"SKIP_ENTRY_HASH_INVALID\"\n | \"SKIP_ENTRY_ID_INVALID\"\n | \"SKIP_ENTRY_ID_TOO_LONG\"\n | \"SKIP_ENTRY_MALFORMED\"\n | \"SKIP_ENTRY_ORDER_NON_CANONICAL\"\n | \"SKIP_HASH_ALGORITHM_UNSUPPORTED\"\n | \"SKIP_MANIFEST_MALFORMED\"\n | \"SKIP_MANIFEST_SCHEMA_UNSUPPORTED\"\n | \"SKIP_MANIFEST_TOO_LARGE\"\n | \"SKIP_PRIVATE_ENTRY\"\n | \"SKIP_REPLAY_WINDOW_INVALID\"\n | \"SKIP_UNKNOWN_ENTRY\"\n | \"SKIP_VARIANT_CACHE_KEY_INVALID\"\n | \"SKIP_VARIANT_CACHE_KEY_TOO_LONG\"\n | \"SKIP_VISIBLE_COMMIT_VERSION_INVALID\"\n | \"SKIP_VISIBLE_COMMIT_VERSION_MISMATCH\";\n\nexport type ClientReuseManifestTraceFieldValue =\n | string\n | number\n | boolean\n | null\n | readonly string[];\n\nexport type ClientReuseManifestTraceFields = Readonly<\n Record<string, ClientReuseManifestTraceFieldValue>\n>;\n\nexport type ClientReuseManifestRejection = Readonly<{\n code: ClientReuseManifestRejectionCode;\n fields: ClientReuseManifestTraceFields;\n}>;\n\nexport type ClientReuseManifestEntryRejection = ClientReuseManifestRejection &\n Readonly<{\n entryId: string | null;\n }>;\n\nexport type ClientReuseManifestSkipDisposition =\n | Readonly<{\n code: \"SKIP_MODEL_DISABLED\";\n enabled: false;\n mode: \"renderAndSend\";\n }>\n | Readonly<{\n code: \"SKIP_STATIC_LAYOUT_VERIFIED\";\n enabled: true;\n mode: \"skipStaticLayout\";\n skippedEntryIds: readonly string[];\n }>;\n\nexport type ClientReuseManifestParseResult =\n | Readonly<{ kind: \"absent\" }>\n | Readonly<{ kind: \"rejected\"; rejection: ClientReuseManifestRejection }>\n | Readonly<{\n entryRejections: readonly ClientReuseManifestEntryRejection[];\n kind: \"parsed\";\n manifest: ClientReuseManifest;\n skipDisposition: ClientReuseManifestSkipDisposition;\n }>;\n\ntype ParseClientReuseManifestOptions = Readonly<{\n currentVisibleCommitVersion?: number;\n limits?: ClientReuseManifestLimits;\n}>;\n\nconst HASH_DIGEST_PATTERN = /^[0-9a-z]+$/;\nconst textEncoder = new TextEncoder();\n\ntype ParseReplayWindowResult =\n | Readonly<{ kind: \"parsed\"; replayWindow: ClientReuseManifestReplayWindow }>\n | Readonly<{ kind: \"rejected\"; rejection: ClientReuseManifestRejection }>;\n\nfunction createRejection(\n code: ClientReuseManifestRejectionCode,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestRejection {\n return { code, fields };\n}\n\nfunction rejectManifest(\n code: ClientReuseManifestRejectionCode,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestParseResult {\n return { kind: \"rejected\", rejection: createRejection(code, fields) };\n}\n\nfunction rejectEntry(\n code: ClientReuseManifestRejectionCode,\n entryId: string | null,\n fields: ClientReuseManifestTraceFields = {},\n): ClientReuseManifestEntryRejection {\n return { code, entryId, fields };\n}\n\nfunction compareManifestEntries(\n left: Pick<ClientReuseManifestWireEntry, \"id\">,\n right: Pick<ClientReuseManifestWireEntry, \"id\">,\n): number {\n if (left.id < right.id) return -1;\n if (left.id > right.id) return 1;\n return 0;\n}\n\nfunction createCanonicalWireEntries(\n entries: readonly ClientReuseManifestWireEntry[],\n): ClientReuseManifestWireEntry[] {\n const entriesById = new Map<string, ClientReuseManifestWireEntry>();\n for (const entry of entries) {\n if (!entriesById.has(entry.id)) {\n entriesById.set(entry.id, entry);\n }\n }\n\n return Array.from(entriesById.values()).sort(compareManifestEntries);\n}\n\n// Manifest byte budgets are enforced over UTF-8 encoded header values.\nfunction countUtf8Bytes(input: string): number {\n return textEncoder.encode(input).length;\n}\n\nfunction isVisibleCommitVersion(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction parseReplayWindow(value: unknown, visibleCommitVersion: number): ParseReplayWindowResult {\n if (!isUnknownRecord(value)) {\n return {\n kind: \"rejected\",\n rejection: createRejection(\"SKIP_REPLAY_WINDOW_INVALID\", { field: \"replayWindow\" }),\n };\n }\n\n const validFromVisibleCommitVersion = value.validFromVisibleCommitVersion;\n const validUntilVisibleCommitVersion = value.validUntilVisibleCommitVersion;\n if (\n !isVisibleCommitVersion(validFromVisibleCommitVersion) ||\n !isVisibleCommitVersion(validUntilVisibleCommitVersion) ||\n validFromVisibleCommitVersion > validUntilVisibleCommitVersion ||\n visibleCommitVersion < validFromVisibleCommitVersion ||\n visibleCommitVersion > validUntilVisibleCommitVersion\n ) {\n return {\n kind: \"rejected\",\n rejection: createRejection(\"SKIP_REPLAY_WINDOW_INVALID\", {\n validFromVisibleCommitVersion: isVisibleCommitVersion(validFromVisibleCommitVersion)\n ? validFromVisibleCommitVersion\n : null,\n validUntilVisibleCommitVersion: isVisibleCommitVersion(validUntilVisibleCommitVersion)\n ? validUntilVisibleCommitVersion\n : null,\n visibleCommitVersion,\n }),\n };\n }\n\n return {\n kind: \"parsed\",\n replayWindow: {\n validFromVisibleCommitVersion,\n validUntilVisibleCommitVersion,\n },\n };\n}\n\nfunction currentCommitVersionMatchesReplayWindow(\n currentVisibleCommitVersion: number | undefined,\n replayWindow: ClientReuseManifestReplayWindow,\n): boolean {\n if (currentVisibleCommitVersion === undefined) return true;\n return (\n currentVisibleCommitVersion >= replayWindow.validFromVisibleCommitVersion &&\n currentVisibleCommitVersion <= replayWindow.validUntilVisibleCommitVersion\n );\n}\n\nfunction parseEntryKind(id: string): ClientReuseManifestEntryKind | null {\n const parsed = AppElementsWire.parseElementKey(id);\n if (parsed === null) return null;\n return parsed.kind;\n}\n\nfunction isValidPayloadHash(value: unknown, limits: ClientReuseManifestLimits): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n value.length <= limits.maxPayloadHashLength &&\n HASH_DIGEST_PATTERN.test(value)\n );\n}\n\nfunction parseManifestEntry(\n value: unknown,\n limits: ClientReuseManifestLimits,\n index: number,\n): ClientReuseManifestEntry | ClientReuseManifestEntryRejection {\n if (!isUnknownRecord(value)) {\n return rejectEntry(\"SKIP_ENTRY_MALFORMED\", null, { index });\n }\n\n const id = value.id;\n if (typeof id !== \"string\" || id.length === 0) {\n return rejectEntry(\"SKIP_ENTRY_ID_INVALID\", null, { index });\n }\n if (id.length > limits.maxEntryIdLength) {\n return rejectEntry(\"SKIP_ENTRY_ID_TOO_LONG\", id, {\n idHash: createClientReusePayloadHash(id),\n maxEntryIdLength: limits.maxEntryIdLength,\n });\n }\n\n const kind = parseEntryKind(id);\n if (kind === null) {\n return rejectEntry(\"SKIP_UNKNOWN_ENTRY\", id, { idHash: createClientReusePayloadHash(id) });\n }\n\n const privacy = value.privacy;\n if (privacy === \"private\") {\n return rejectEntry(\"SKIP_PRIVATE_ENTRY\", id, { privacy });\n }\n if (privacy !== \"public\") {\n return rejectEntry(\"SKIP_ENTRY_MALFORMED\", id, { field: \"privacy\" });\n }\n\n const payloadHash = value.payloadHash;\n if (!isValidPayloadHash(payloadHash, limits)) {\n return rejectEntry(\"SKIP_ENTRY_HASH_INVALID\", id, {\n maxPayloadHashLength: limits.maxPayloadHashLength,\n });\n }\n\n const variantCacheKey = value.variantCacheKey;\n if (typeof variantCacheKey !== \"string\" || variantCacheKey.length === 0) {\n return rejectEntry(\"SKIP_VARIANT_CACHE_KEY_INVALID\", id, { field: \"variantCacheKey\" });\n }\n if (variantCacheKey.length > limits.maxVariantCacheKeyLength) {\n return rejectEntry(\"SKIP_VARIANT_CACHE_KEY_TOO_LONG\", id, {\n maxVariantCacheKeyLength: limits.maxVariantCacheKeyLength,\n variantCacheKeyHash: createClientReusePayloadHash(variantCacheKey),\n });\n }\n\n const artifactCompatibility = parseArtifactCompatibilityEnvelope(value.artifactCompatibility);\n if (artifactCompatibility === null) {\n return rejectEntry(\"SKIP_ARTIFACT_COMPATIBILITY_INVALID\", id, {\n field: \"artifactCompatibility\",\n });\n }\n\n return {\n artifactCompatibility,\n id,\n kind,\n payloadHash,\n privacy,\n variantCacheKey,\n };\n}\n\nexport function createClientReusePayloadHash(input: string): string {\n return fnv1a64(input);\n}\n\nexport function createClientReuseManifest(\n input: CreateClientReuseManifestInput,\n): ClientReuseManifestWire {\n const replayWindow =\n input.replayWindow ??\n ({\n validFromVisibleCommitVersion: input.visibleCommitVersion,\n validUntilVisibleCommitVersion: input.visibleCommitVersion,\n } satisfies ClientReuseManifestReplayWindow);\n\n return {\n entries: createCanonicalWireEntries(input.entries),\n hashAlgorithm: CLIENT_REUSE_MANIFEST_HASH_ALGORITHM,\n replayWindow,\n schemaVersion: CLIENT_REUSE_MANIFEST_SCHEMA_VERSION,\n visibleCommitVersion: input.visibleCommitVersion,\n };\n}\n\nexport function serializeClientReuseManifest(input: CreateClientReuseManifestInput): string {\n return JSON.stringify(createClientReuseManifest(input));\n}\n\nexport function parseClientReuseManifestHeader(\n rawHeader: string | null | undefined,\n options: ParseClientReuseManifestOptions = {},\n): ClientReuseManifestParseResult {\n const header = rawHeader?.trim();\n if (!header) return { kind: \"absent\" };\n\n const limits = options.limits ?? DEFAULT_CLIENT_REUSE_MANIFEST_LIMITS;\n const manifestBytes = countUtf8Bytes(header);\n if (manifestBytes > limits.maxManifestBytes) {\n return rejectManifest(\"SKIP_MANIFEST_TOO_LARGE\", {\n manifestBytes,\n maxManifestBytes: limits.maxManifestBytes,\n });\n }\n\n let decoded: unknown;\n try {\n decoded = JSON.parse(header);\n } catch {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\");\n }\n\n if (!isUnknownRecord(decoded)) {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\", { field: \"manifest\" });\n }\n\n if (decoded.schemaVersion !== CLIENT_REUSE_MANIFEST_SCHEMA_VERSION) {\n return rejectManifest(\"SKIP_MANIFEST_SCHEMA_UNSUPPORTED\", {\n schemaVersion:\n typeof decoded.schemaVersion === \"number\" || typeof decoded.schemaVersion === \"string\"\n ? decoded.schemaVersion\n : null,\n });\n }\n\n if (decoded.hashAlgorithm !== CLIENT_REUSE_MANIFEST_HASH_ALGORITHM) {\n return rejectManifest(\"SKIP_HASH_ALGORITHM_UNSUPPORTED\", {\n hashAlgorithm: typeof decoded.hashAlgorithm === \"string\" ? decoded.hashAlgorithm : null,\n });\n }\n\n const visibleCommitVersion = decoded.visibleCommitVersion;\n if (!isVisibleCommitVersion(visibleCommitVersion)) {\n return rejectManifest(\"SKIP_VISIBLE_COMMIT_VERSION_INVALID\", {\n visibleCommitVersion: null,\n });\n }\n\n const replayWindowResult = parseReplayWindow(decoded.replayWindow, visibleCommitVersion);\n if (replayWindowResult.kind === \"rejected\") {\n return { kind: \"rejected\", rejection: replayWindowResult.rejection };\n }\n const { replayWindow } = replayWindowResult;\n if (!currentCommitVersionMatchesReplayWindow(options.currentVisibleCommitVersion, replayWindow)) {\n return rejectManifest(\"SKIP_VISIBLE_COMMIT_VERSION_MISMATCH\", {\n currentVisibleCommitVersion: options.currentVisibleCommitVersion ?? null,\n validFromVisibleCommitVersion: replayWindow.validFromVisibleCommitVersion,\n validUntilVisibleCommitVersion: replayWindow.validUntilVisibleCommitVersion,\n visibleCommitVersion,\n });\n }\n\n const entriesValue = decoded.entries;\n if (!Array.isArray(entriesValue)) {\n return rejectManifest(\"SKIP_MANIFEST_MALFORMED\", { field: \"entries\" });\n }\n if (entriesValue.length > limits.maxEntryCount) {\n return rejectManifest(\"SKIP_ENTRY_COUNT_EXCEEDED\", {\n entryCount: entriesValue.length,\n maxEntryCount: limits.maxEntryCount,\n });\n }\n\n const entries: ClientReuseManifestEntry[] = [];\n const entryRejections: ClientReuseManifestEntryRejection[] = [];\n let previousEntryId: string | null = null;\n\n for (let index = 0; index < entriesValue.length; index++) {\n const value = entriesValue[index];\n if (isUnknownRecord(value) && typeof value.id === \"string\") {\n // Canonical ordering is enforced over entries with string IDs. Malformed\n // entries cannot advance previousEntryId, so interleaving them cannot hide\n // an ordering violation between valid checkpoints. <= rejects both\n // out-of-order and duplicate IDs.\n if (previousEntryId !== null && value.id <= previousEntryId) {\n return rejectManifest(\"SKIP_ENTRY_ORDER_NON_CANONICAL\", {\n entryIdHash: createClientReusePayloadHash(value.id),\n previousEntryIdHash: createClientReusePayloadHash(previousEntryId),\n });\n }\n previousEntryId = value.id;\n }\n\n const parsedEntry = parseManifestEntry(value, limits, index);\n if (\"code\" in parsedEntry) {\n entryRejections.push(parsedEntry);\n } else {\n entries.push(parsedEntry);\n }\n }\n\n return {\n entryRejections,\n kind: \"parsed\",\n manifest: {\n entries,\n hashAlgorithm: CLIENT_REUSE_MANIFEST_HASH_ALGORITHM,\n replayWindow,\n schemaVersion: CLIENT_REUSE_MANIFEST_SCHEMA_VERSION,\n visibleCommitVersion,\n },\n skipDisposition: {\n code: \"SKIP_MODEL_DISABLED\",\n enabled: false,\n mode: \"renderAndSend\",\n },\n };\n}\n"],"mappings":"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"}