vinext 0.0.46 → 0.0.47

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 (171) hide show
  1. package/README.md +7 -5
  2. package/dist/build/prerender.d.ts +2 -1
  3. package/dist/build/prerender.js +70 -14
  4. package/dist/build/prerender.js.map +1 -1
  5. package/dist/build/report.d.ts +1 -1
  6. package/dist/build/route-classification-injector.d.ts +35 -0
  7. package/dist/build/route-classification-injector.js +61 -0
  8. package/dist/build/route-classification-injector.js.map +1 -0
  9. package/dist/build/route-classification-manifest.d.ts +1 -1
  10. package/dist/build/static-export.d.ts +1 -1
  11. package/dist/cli-args.d.ts +31 -0
  12. package/dist/cli-args.js +104 -0
  13. package/dist/cli-args.js.map +1 -0
  14. package/dist/cli.js +2 -19
  15. package/dist/cli.js.map +1 -1
  16. package/dist/cloudflare/kv-cache-handler.js +29 -9
  17. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  18. package/dist/config/next-config.d.ts +4 -2
  19. package/dist/config/next-config.js +3 -0
  20. package/dist/config/next-config.js.map +1 -1
  21. package/dist/entries/app-rsc-entry.d.ts +4 -3
  22. package/dist/entries/app-rsc-entry.js +373 -854
  23. package/dist/entries/app-rsc-entry.js.map +1 -1
  24. package/dist/entries/app-rsc-manifest.d.ts +1 -1
  25. package/dist/entries/app-rsc-manifest.js +2 -0
  26. package/dist/entries/app-rsc-manifest.js.map +1 -1
  27. package/dist/entries/pages-server-entry.js +5 -2
  28. package/dist/entries/pages-server-entry.js.map +1 -1
  29. package/dist/index.js +28 -51
  30. package/dist/index.js.map +1 -1
  31. package/dist/plugins/fonts.js +54 -32
  32. package/dist/plugins/fonts.js.map +1 -1
  33. package/dist/plugins/rsc-client-shim-excludes.js +1 -0
  34. package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
  35. package/dist/routing/app-route-graph.d.ts +109 -0
  36. package/dist/routing/app-route-graph.js +819 -0
  37. package/dist/routing/app-route-graph.js.map +1 -0
  38. package/dist/routing/app-router.d.ts +2 -88
  39. package/dist/routing/app-router.js +6 -694
  40. package/dist/routing/app-router.js.map +1 -1
  41. package/dist/server/app-browser-entry.js +86 -252
  42. package/dist/server/app-browser-entry.js.map +1 -1
  43. package/dist/server/app-browser-error.d.ts +3 -4
  44. package/dist/server/app-browser-error.js +8 -4
  45. package/dist/server/app-browser-error.js.map +1 -1
  46. package/dist/server/app-browser-navigation-controller.d.ts +73 -0
  47. package/dist/server/app-browser-navigation-controller.js +282 -0
  48. package/dist/server/app-browser-navigation-controller.js.map +1 -0
  49. package/dist/server/app-browser-state.d.ts +1 -1
  50. package/dist/server/app-elements.js +1 -5
  51. package/dist/server/app-elements.js.map +1 -1
  52. package/dist/server/app-fallback-renderer.d.ts +57 -0
  53. package/dist/server/app-fallback-renderer.js +79 -0
  54. package/dist/server/app-fallback-renderer.js.map +1 -0
  55. package/dist/server/app-hook-warning-suppression.d.ts +7 -0
  56. package/dist/server/app-hook-warning-suppression.js +12 -0
  57. package/dist/server/app-hook-warning-suppression.js.map +1 -0
  58. package/dist/server/app-mounted-slots-header.d.ts +17 -0
  59. package/dist/server/app-mounted-slots-header.js +21 -0
  60. package/dist/server/app-mounted-slots-header.js.map +1 -0
  61. package/dist/server/app-page-boundary-render.d.ts +2 -2
  62. package/dist/server/app-page-boundary-render.js.map +1 -1
  63. package/dist/server/app-page-cache.d.ts +18 -4
  64. package/dist/server/app-page-cache.js +53 -10
  65. package/dist/server/app-page-cache.js.map +1 -1
  66. package/dist/server/app-page-dispatch.d.ts +7 -4
  67. package/dist/server/app-page-dispatch.js +24 -8
  68. package/dist/server/app-page-dispatch.js.map +1 -1
  69. package/dist/server/app-page-element-builder.d.ts +61 -0
  70. package/dist/server/app-page-element-builder.js +139 -0
  71. package/dist/server/app-page-element-builder.js.map +1 -0
  72. package/dist/server/app-page-params.d.ts +2 -1
  73. package/dist/server/app-page-params.js +3 -3
  74. package/dist/server/app-page-params.js.map +1 -1
  75. package/dist/server/app-page-render.d.ts +5 -1
  76. package/dist/server/app-page-render.js +80 -27
  77. package/dist/server/app-page-render.js.map +1 -1
  78. package/dist/server/app-page-request.d.ts +19 -4
  79. package/dist/server/app-page-request.js +51 -6
  80. package/dist/server/app-page-request.js.map +1 -1
  81. package/dist/server/app-page-response.d.ts +1 -0
  82. package/dist/server/app-page-response.js +3 -7
  83. package/dist/server/app-page-response.js.map +1 -1
  84. package/dist/server/app-page-route-wiring.d.ts +15 -2
  85. package/dist/server/app-page-route-wiring.js.map +1 -1
  86. package/dist/server/app-post-middleware-context.d.ts +16 -0
  87. package/dist/server/app-post-middleware-context.js +28 -0
  88. package/dist/server/app-post-middleware-context.js.map +1 -0
  89. package/dist/server/app-request-context.d.ts +22 -0
  90. package/dist/server/app-request-context.js +30 -0
  91. package/dist/server/app-request-context.js.map +1 -0
  92. package/dist/server/app-route-handler-cache.d.ts +1 -0
  93. package/dist/server/app-route-handler-cache.js +5 -1
  94. package/dist/server/app-route-handler-cache.js.map +1 -1
  95. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  96. package/dist/server/app-route-handler-dispatch.js +2 -0
  97. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  98. package/dist/server/app-route-handler-execution.d.ts +2 -1
  99. package/dist/server/app-route-handler-execution.js +2 -2
  100. package/dist/server/app-route-handler-execution.js.map +1 -1
  101. package/dist/server/app-route-handler-response.d.ts +4 -2
  102. package/dist/server/app-route-handler-response.js +8 -7
  103. package/dist/server/app-route-handler-response.js.map +1 -1
  104. package/dist/server/app-rsc-error-handler.d.ts +21 -0
  105. package/dist/server/app-rsc-error-handler.js +30 -0
  106. package/dist/server/app-rsc-error-handler.js.map +1 -0
  107. package/dist/server/app-rsc-handler.d.ts +117 -0
  108. package/dist/server/app-rsc-handler.js +260 -0
  109. package/dist/server/app-rsc-handler.js.map +1 -0
  110. package/dist/server/app-rsc-request-normalization.d.ts +40 -0
  111. package/dist/server/app-rsc-request-normalization.js +63 -0
  112. package/dist/server/app-rsc-request-normalization.js.map +1 -0
  113. package/dist/server/app-rsc-response-finalizer.d.ts +30 -0
  114. package/dist/server/app-rsc-response-finalizer.js +38 -0
  115. package/dist/server/app-rsc-response-finalizer.js.map +1 -0
  116. package/dist/server/app-segment-config.d.ts +33 -0
  117. package/dist/server/app-segment-config.js +86 -0
  118. package/dist/server/app-segment-config.js.map +1 -0
  119. package/dist/server/app-server-action-execution.d.ts +2 -0
  120. package/dist/server/app-server-action-execution.js +2 -0
  121. package/dist/server/app-server-action-execution.js.map +1 -1
  122. package/dist/server/cache-control.d.ts +24 -0
  123. package/dist/server/cache-control.js +33 -0
  124. package/dist/server/cache-control.js.map +1 -0
  125. package/dist/server/dev-error-overlay-store.d.ts +23 -0
  126. package/dist/server/dev-error-overlay-store.js +67 -0
  127. package/dist/server/dev-error-overlay-store.js.map +1 -0
  128. package/dist/server/dev-error-overlay.d.ts +15 -0
  129. package/dist/server/dev-error-overlay.js +548 -0
  130. package/dist/server/dev-error-overlay.js.map +1 -0
  131. package/dist/server/instrumentation-runtime.d.ts +44 -0
  132. package/dist/server/instrumentation-runtime.js +29 -0
  133. package/dist/server/instrumentation-runtime.js.map +1 -0
  134. package/dist/server/isr-cache.d.ts +2 -7
  135. package/dist/server/isr-cache.js +7 -10
  136. package/dist/server/isr-cache.js.map +1 -1
  137. package/dist/server/pages-page-data.d.ts +2 -1
  138. package/dist/server/pages-page-data.js +6 -5
  139. package/dist/server/pages-page-data.js.map +1 -1
  140. package/dist/server/pages-page-response.d.ts +2 -1
  141. package/dist/server/pages-page-response.js +3 -2
  142. package/dist/server/pages-page-response.js.map +1 -1
  143. package/dist/server/rsc-stream-hints.d.ts +3 -1
  144. package/dist/server/rsc-stream-hints.js +4 -1
  145. package/dist/server/rsc-stream-hints.js.map +1 -1
  146. package/dist/server/seed-cache.js +19 -8
  147. package/dist/server/seed-cache.js.map +1 -1
  148. package/dist/shims/cache-runtime.js +28 -11
  149. package/dist/shims/cache-runtime.js.map +1 -1
  150. package/dist/shims/cache.d.ts +15 -3
  151. package/dist/shims/cache.js +42 -15
  152. package/dist/shims/cache.js.map +1 -1
  153. package/dist/shims/error-boundary.d.ts +17 -1
  154. package/dist/shims/error-boundary.js +31 -1
  155. package/dist/shims/error-boundary.js.map +1 -1
  156. package/dist/shims/fetch-cache.d.ts +4 -1
  157. package/dist/shims/fetch-cache.js +55 -13
  158. package/dist/shims/fetch-cache.js.map +1 -1
  159. package/dist/shims/image.js +93 -5
  160. package/dist/shims/image.js.map +1 -1
  161. package/dist/shims/request-state-types.d.ts +1 -1
  162. package/dist/shims/unified-request-context.d.ts +1 -1
  163. package/dist/shims/unified-request-context.js +1 -0
  164. package/dist/shims/unified-request-context.js.map +1 -1
  165. package/dist/shims/use-merged-ref.d.ts +7 -0
  166. package/dist/shims/use-merged-ref.js +40 -0
  167. package/dist/shims/use-merged-ref.js.map +1 -0
  168. package/dist/utils/cache-control-metadata.d.ts +6 -0
  169. package/dist/utils/cache-control-metadata.js +16 -0
  170. package/dist/utils/cache-control-metadata.js.map +1 -0
  171. package/package.json +1 -1
@@ -1,17 +1,16 @@
1
1
  import { processMiddlewareHeaders } from "./request-pipeline.js";
2
2
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
3
+ import { NEVER_CACHE_CONTROL, buildCachedRevalidateCacheControl } from "./cache-control.js";
3
4
  //#region src/server/app-route-handler-response.ts
4
- const NEVER_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
5
5
  const APP_ROUTE_REWRITE_ERROR = "NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.";
6
6
  const APP_ROUTE_NEXT_ERROR = "NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler";
7
7
  function hasMiddlewareHeader(headers) {
8
8
  for (const key of headers.keys()) if (key.startsWith("x-middleware-")) return true;
9
9
  return false;
10
10
  }
11
- function buildRouteHandlerCacheControl(cacheState, revalidateSeconds) {
11
+ function buildRouteHandlerCacheControl(cacheState, revalidateSeconds, expireSeconds) {
12
12
  if (revalidateSeconds === 0) return NEVER_CACHE_CONTROL;
13
- if (cacheState === "STALE") return "s-maxage=0, stale-while-revalidate";
14
- return `s-maxage=${revalidateSeconds}, stale-while-revalidate`;
13
+ return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);
15
14
  }
16
15
  function applyRouteHandlerMiddlewareContext(response, middlewareContext) {
17
16
  if (!middlewareContext.headers && middlewareContext.status == null) return response;
@@ -32,14 +31,16 @@ function buildRouteHandlerCachedResponse(cachedValue, options) {
32
31
  for (const [key, value] of Object.entries(cachedValue.headers)) if (Array.isArray(value)) for (const entry of value) headers.append(key, entry);
33
32
  else headers.set(key, value);
34
33
  headers.set("X-Vinext-Cache", options.cacheState);
35
- headers.set("Cache-Control", buildRouteHandlerCacheControl(options.cacheState, options.revalidateSeconds));
34
+ const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;
35
+ const expireSeconds = options.cacheControl === void 0 ? void 0 : options.cacheControl.expire ?? options.expireSeconds;
36
+ headers.set("Cache-Control", buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds));
36
37
  return new Response(options.isHead ? null : cachedValue.body, {
37
38
  status: cachedValue.status,
38
39
  headers
39
40
  });
40
41
  }
41
- function applyRouteHandlerRevalidateHeader(response, revalidateSeconds) {
42
- response.headers.set("cache-control", buildRouteHandlerCacheControl("HIT", revalidateSeconds));
42
+ function applyRouteHandlerRevalidateHeader(response, revalidateSeconds, expireSeconds) {
43
+ response.headers.set("cache-control", buildRouteHandlerCacheControl("HIT", revalidateSeconds, expireSeconds));
43
44
  }
44
45
  function markRouteHandlerCacheMiss(response) {
45
46
  response.headers.set("X-Vinext-Cache", "MISS");
@@ -1 +1 @@
1
- {"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue } from \"vinext/shims/cache\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheState: \"HIT\" | \"STALE\";\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\n// Matches Next.js's getCacheControlHeader for revalidate === 0.\n// See .nextjs-ref/packages/next/src/server/lib/cache-control.ts.\nconst NEVER_CACHE_CONTROL = \"private, no-cache, no-store, max-age=0, must-revalidate\";\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(\"x-middleware-\")) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n if (cacheState === \"STALE\") {\n return \"s-maxage=0, stale-while-revalidate\";\n }\n\n return `s-maxage=${revalidateSeconds}, stale-while-revalidate`;\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(\"x-middleware-rewrite\")) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n headers.set(\"X-Vinext-Cache\", options.cacheState);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, options.revalidateSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n): void {\n response.headers.set(\"cache-control\", buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds));\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n response.headers.set(\"X-Vinext-Cache\", \"MISS\");\n}\n\nfunction getSetCookieName(cookie: string): string | null {\n const equalsIndex = cookie.indexOf(\"=\");\n if (equalsIndex <= 0) {\n return null;\n }\n return cookie.slice(0, equalsIndex);\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === \"x-vinext-cache\" ||\n key === \"cache-control\" ||\n key.startsWith(\"x-middleware-\")\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":";;;AAuBA,MAAM,sBAAsB;AAE5B,MAAM,0BACJ;AACF,MAAM,uBACJ;AAEF,SAAS,oBAAoB,SAA2B;AACtD,MAAK,MAAM,OAAO,QAAQ,MAAM,CAC9B,KAAI,IAAI,WAAW,gBAAgB,CAAE,QAAO;AAE9C,QAAO;;AAGT,SAAS,8BACP,YACA,mBACQ;AACR,KAAI,sBAAsB,EAKxB,QAAO;AAGT,KAAI,eAAe,QACjB,QAAO;AAGT,QAAO,YAAY,kBAAkB;;AAGvC,SAAgB,mCACd,UACA,mBACU;AACV,KAAI,CAAC,kBAAkB,WAAW,kBAAkB,UAAU,KAC5D,QAAO;CAGT,MAAM,kBAAkB,IAAI,QAAQ,SAAS,QAAQ;AACrD,gCAA+B,iBAAiB,kBAAkB,QAAQ;AAE1E,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,kBAAkB,UAAU,SAAS;EAC7C,YAAY,SAAS;EACrB,SAAS;EACV,CAAC;;AAGJ,SAAgB,uCAAuC,UAA0B;AAG/E,KAAI,SAAS,QAAQ,IAAI,uBAAuB,CAC9C,OAAM,IAAI,MAAM,wBAAwB;AAG1C,KAAI,SAAS,QAAQ,IAAI,oBAAoB,KAAK,IAChD,OAAM,IAAI,MAAM,qBAAqB;;AAIzC,SAAgB,gCACd,aACA,SACU;CACV,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,YAAY,QAAQ,CAC5D,KAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,SAAS,MAClB,SAAQ,OAAO,KAAK,MAAM;KAG5B,SAAQ,IAAI,KAAK,MAAM;AAG3B,SAAQ,IAAI,kBAAkB,QAAQ,WAAW;AACjD,SAAQ,IACN,iBACA,8BAA8B,QAAQ,YAAY,QAAQ,kBAAkB,CAC7E;AAED,QAAO,IAAI,SAAS,QAAQ,SAAS,OAAO,YAAY,MAAM;EAC5D,QAAQ,YAAY;EACpB;EACD,CAAC;;AAGJ,SAAgB,kCACd,UACA,mBACM;AACN,UAAS,QAAQ,IAAI,iBAAiB,8BAA8B,OAAO,kBAAkB,CAAC;;AAGhG,SAAgB,0BAA0B,UAA0B;AAClE,UAAS,QAAQ,IAAI,kBAAkB,OAAO;;AAGhD,SAAS,iBAAiB,QAA+B;CACvD,MAAM,cAAc,OAAO,QAAQ,IAAI;AACvC,KAAI,eAAe,EACjB,QAAO;AAET,QAAO,OAAO,MAAM,GAAG,YAAY;;AAGrC,SAAS,4BAA4B,SAAkB,gBAAgC;AACrF,KAAI,eAAe,WAAW,EAC5B;CAGF,MAAM,kBAAkB,QAAQ,cAAc;CAC9C,MAAM,sCAAsB,IAAI,KAAa;AAC7C,MAAK,MAAM,UAAU,iBAAiB;EACpC,MAAM,OAAO,iBAAiB,OAAO;AACrC,MAAI,KACF,qBAAoB,IAAI,KAAK;;CAIjC,MAAM,kCAAkB,IAAI,KAAqB;CACjD,MAAM,yBAAmC,EAAE;AAC3C,MAAK,MAAM,UAAU,gBAAgB;EACnC,MAAM,OAAO,iBAAiB,OAAO;AACrC,MAAI,CAAC,MAAM;AACT,0BAAuB,KAAK,OAAO;AACnC;;AAGF,MAAI,CAAC,oBAAoB,IAAI,KAAK,CAChC,iBAAgB,IAAI,MAAM,OAAO;;AAIrC,SAAQ,OAAO,aAAa;AAC5B,MAAK,MAAM,UAAU,uBACnB,SAAQ,OAAO,cAAc,OAAO;AAEtC,MAAK,MAAM,UAAU,gBAAgB,QAAQ,CAC3C,SAAQ,OAAO,cAAc,OAAO;AAEtC,MAAK,MAAM,UAAU,gBACnB,SAAQ,OAAO,cAAc,OAAO;;AAIxC,eAAsB,wBAAwB,UAA+C;CAC3F,MAAM,OAAO,MAAM,SAAS,aAAa;CACzC,MAAM,UAAuC,EAAE;AAE/C,UAAS,QAAQ,SAAS,OAAO,QAAQ;AACvC,MACE,QAAQ,gBACR,QAAQ,oBACR,QAAQ,mBACR,IAAI,WAAW,gBAAgB,CAE/B;AAEF,UAAQ,OAAO;GACf;CACF,MAAM,aAAa,SAAS,QAAQ,gBAAgB,IAAI,EAAE;AAC1D,KAAI,WAAW,SAAS,EACtB,SAAQ,gBAAgB;AAG1B,QAAO;EACL,MAAM;EACN;EACA,QAAQ,SAAS;EACjB;EACD;;AAGH,SAAgB,6BACd,UACA,SACU;CACV,MAAM,EAAE,gBAAgB,aAAa,WAAW;AAChD,KACE,eAAe,WAAW,KAC1B,CAAC,eACD,CAAC,UACD,CAAC,oBAAoB,SAAS,QAAQ,CAEtC,QAAO;CAGT,MAAM,UAAU,IAAI,QAAQ,SAAS,QAAQ;AAC7C,0BAAyB,QAAQ;AACjC,6BAA4B,SAAS,eAAe;AACpD,KAAI,YACF,SAAQ,OAAO,cAAc,YAAY;AAG3C,QAAO,IAAI,SAAS,SAAS,OAAO,SAAS,MAAM;EACjD,QAAQ,SAAS;EACjB,YAAY,SAAS;EACrB;EACD,CAAC"}
1
+ {"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport { buildCachedRevalidateCacheControl, NEVER_CACHE_CONTROL } from \"./cache-control.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheControl?: CacheControlMetadata;\n cacheState: \"HIT\" | \"STALE\";\n expireSeconds?: number;\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(\"x-middleware-\")) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n expireSeconds?: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(\"x-middleware-rewrite\")) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(\"x-middleware-next\") === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n headers.set(\"X-Vinext-Cache\", options.cacheState);\n const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;\n const expireSeconds =\n options.cacheControl === undefined\n ? undefined\n : (options.cacheControl.expire ?? options.expireSeconds);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n expireSeconds?: number,\n): void {\n response.headers.set(\n \"cache-control\",\n buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds, expireSeconds),\n );\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n response.headers.set(\"X-Vinext-Cache\", \"MISS\");\n}\n\nfunction getSetCookieName(cookie: string): string | null {\n const equalsIndex = cookie.indexOf(\"=\");\n if (equalsIndex <= 0) {\n return null;\n }\n return cookie.slice(0, equalsIndex);\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === \"x-vinext-cache\" ||\n key === \"cache-control\" ||\n key.startsWith(\"x-middleware-\")\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ //#region src/server/app-rsc-error-handler.d.ts
2
+ type ReportRequestError = (error: Error, requestInfo: {
3
+ path: string;
4
+ method: string;
5
+ headers: Record<string, string>;
6
+ }, errorContext: {
7
+ routerKind: "App Router";
8
+ routePath: string;
9
+ routeType: "render";
10
+ }) => void;
11
+ /**
12
+ * Build a per-request RSC error handler that extracts request metadata from
13
+ * the incoming Web `Request`, wires it into a `createRscOnErrorHandler` call,
14
+ * and binds the configured `reportRequestError` reporter.
15
+ *
16
+ * Pure factory: takes all deps explicitly — no closure over module-level state.
17
+ */
18
+ declare function createAppRscOnErrorHandler(reportRequestError: ReportRequestError, request: Request, pathname: string, routePath: string): (error: unknown) => string | undefined;
19
+ //#endregion
20
+ export { createAppRscOnErrorHandler };
21
+ //# sourceMappingURL=app-rsc-error-handler.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { createRscOnErrorHandler } from "./app-rsc-errors.js";
2
+ //#region src/server/app-rsc-error-handler.ts
3
+ /**
4
+ * Build a per-request RSC error handler that extracts request metadata from
5
+ * the incoming Web `Request`, wires it into a `createRscOnErrorHandler` call,
6
+ * and binds the configured `reportRequestError` reporter.
7
+ *
8
+ * Pure factory: takes all deps explicitly — no closure over module-level state.
9
+ */
10
+ function createAppRscOnErrorHandler(reportRequestError, request, pathname, routePath) {
11
+ const requestHeaders = Object.fromEntries(request.headers.entries());
12
+ const requestInfo = {
13
+ path: pathname,
14
+ method: request.method,
15
+ headers: requestHeaders
16
+ };
17
+ return createRscOnErrorHandler({
18
+ errorContext: {
19
+ routerKind: "App Router",
20
+ routePath: routePath || pathname,
21
+ routeType: "render"
22
+ },
23
+ reportRequestError,
24
+ requestInfo
25
+ });
26
+ }
27
+ //#endregion
28
+ export { createAppRscOnErrorHandler };
29
+
30
+ //# sourceMappingURL=app-rsc-error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-rsc-error-handler.js","names":[],"sources":["../../src/server/app-rsc-error-handler.ts"],"sourcesContent":["import { createRscOnErrorHandler } from \"./app-rsc-errors.js\";\n\ntype ReportRequestError = (\n error: Error,\n requestInfo: { path: string; method: string; headers: Record<string, string> },\n errorContext: { routerKind: \"App Router\"; routePath: string; routeType: \"render\" },\n) => void;\n\n/**\n * Build a per-request RSC error handler that extracts request metadata from\n * the incoming Web `Request`, wires it into a `createRscOnErrorHandler` call,\n * and binds the configured `reportRequestError` reporter.\n *\n * Pure factory: takes all deps explicitly — no closure over module-level state.\n */\nexport function createAppRscOnErrorHandler(\n reportRequestError: ReportRequestError,\n request: Request,\n pathname: string,\n routePath: string,\n): (error: unknown) => string | undefined {\n const requestHeaders: Record<string, string> = Object.fromEntries(request.headers.entries());\n const requestInfo = {\n path: pathname,\n method: request.method,\n headers: requestHeaders,\n };\n const errorContext = {\n routerKind: \"App Router\" as const,\n routePath: routePath || pathname,\n routeType: \"render\" as const,\n };\n return createRscOnErrorHandler({\n errorContext,\n reportRequestError,\n requestInfo,\n });\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,2BACd,oBACA,SACA,UACA,WACwC;CACxC,MAAM,iBAAyC,OAAO,YAAY,QAAQ,QAAQ,SAAS,CAAC;CAC5F,MAAM,cAAc;EAClB,MAAM;EACN,QAAQ,QAAQ;EAChB,SAAS;EACV;AAMD,QAAO,wBAAwB;EAC7B,cANmB;GACnB,YAAY;GACZ,WAAW,aAAa;GACxB,WAAW;GACZ;EAGC;EACA;EACD,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
2
+ import { MiddlewareModule } from "./middleware-runtime.js";
3
+ import { AppMiddlewareContext } from "./app-middleware.js";
4
+ import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
5
+ import { handleMetadataRouteRequest } from "./metadata-route-response.js";
6
+
7
+ //#region src/server/app-rsc-handler.d.ts
8
+ type AppPageParams = Record<string, string | string[]>;
9
+ type MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0]["metadataRoutes"];
10
+ type MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0]["makeThenableParams"];
11
+ type StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1]["staticParamsMap"];
12
+ type RootParamNamesMap = Parameters<typeof handleAppPrerenderEndpoint>[1]["rootParamNamesByPattern"];
13
+ type AppRscMiddlewareContext = AppMiddlewareContext;
14
+ type AppRscHandlerRoute = {
15
+ page?: unknown;
16
+ pattern: string;
17
+ rootParamNames?: readonly string[];
18
+ routeHandler?: unknown;
19
+ routeSegments: readonly string[];
20
+ };
21
+ type AppRscRouteMatch<TRoute> = {
22
+ params: AppPageParams;
23
+ route: TRoute;
24
+ };
25
+ type DispatchMatchedPageOptions<TRoute> = {
26
+ cleanPathname: string;
27
+ handlerStart: number;
28
+ interceptionContext: string | null;
29
+ isRscRequest: boolean;
30
+ middlewareContext: AppRscMiddlewareContext;
31
+ mountedSlotsHeader: string | null;
32
+ params: AppPageParams;
33
+ request: Request;
34
+ route: TRoute;
35
+ scriptNonce?: string;
36
+ searchParams: URLSearchParams;
37
+ };
38
+ type DispatchMatchedRouteHandlerOptions<TRoute> = {
39
+ cleanPathname: string;
40
+ middlewareContext: AppRscMiddlewareContext;
41
+ params: AppPageParams;
42
+ request: Request;
43
+ route: TRoute;
44
+ searchParams: URLSearchParams;
45
+ };
46
+ type HandleProgressiveActionRequestOptions = {
47
+ actionId: string | null;
48
+ cleanPathname: string;
49
+ contentType: string;
50
+ middlewareContext: AppRscMiddlewareContext;
51
+ request: Request;
52
+ };
53
+ type HandleServerActionRequestOptions = {
54
+ actionId: string | null;
55
+ cleanPathname: string;
56
+ contentType: string;
57
+ interceptionContext: string | null;
58
+ isRscRequest: boolean;
59
+ middlewareContext: AppRscMiddlewareContext;
60
+ mountedSlotsHeader: string | null;
61
+ request: Request;
62
+ searchParams: URLSearchParams;
63
+ };
64
+ type RenderNotFoundOptions<TRoute> = {
65
+ isRscRequest: boolean;
66
+ matchedParams?: AppPageParams;
67
+ middlewareContext: AppRscMiddlewareContext;
68
+ request: Request;
69
+ route: TRoute | null;
70
+ scriptNonce?: string;
71
+ };
72
+ type RenderPagesFallbackOptions = {
73
+ isRscRequest: boolean;
74
+ middlewareContext: AppRscMiddlewareContext;
75
+ request: Request;
76
+ url: URL;
77
+ };
78
+ type NavigationContextValue = {
79
+ params: AppPageParams;
80
+ pathname: string;
81
+ searchParams: URLSearchParams;
82
+ };
83
+ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
84
+ basePath: string;
85
+ clearRequestContext: () => void;
86
+ configHeaders: NextHeader[];
87
+ configRedirects: NextRedirect[];
88
+ configRewrites: {
89
+ afterFiles: NextRewrite[];
90
+ beforeFiles: NextRewrite[];
91
+ fallback: NextRewrite[];
92
+ };
93
+ dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;
94
+ dispatchMatchedRouteHandler: (options: DispatchMatchedRouteHandlerOptions<TRoute>) => Promise<Response>;
95
+ ensureInstrumentation?: () => Promise<void>;
96
+ handleProgressiveActionRequest: (options: HandleProgressiveActionRequestOptions) => Promise<Response | null>;
97
+ handleServerActionRequest: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
98
+ i18nConfig: NextI18nConfig | null;
99
+ isMiddlewareProxy: boolean;
100
+ loadPrerenderPagesRoutes?: () => Promise<unknown>;
101
+ makeThenableParams: MakeThenableParams;
102
+ matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
103
+ metadataRoutes: MetadataRoutes;
104
+ middlewareModule: MiddlewareModule | null;
105
+ publicFiles: ReadonlySet<string>;
106
+ renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;
107
+ renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;
108
+ rootParamNamesByPattern?: RootParamNamesMap;
109
+ setNavigationContext: (context: NavigationContextValue) => void;
110
+ staticParamsMap: StaticParamsMap;
111
+ trailingSlash: boolean;
112
+ validateDevRequestOrigin?: (request: Request) => Response | null;
113
+ };
114
+ declare function createAppRscHandler<TRoute extends AppRscHandlerRoute>(options: CreateAppRscHandlerOptions<TRoute>): (request: Request, ctx: unknown) => Promise<Response>;
115
+ //#endregion
116
+ export { createAppRscHandler };
117
+ //# sourceMappingURL=app-rsc-handler.d.ts.map
@@ -0,0 +1,260 @@
1
+ import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
+ import { getRequestExecutionContext } from "../shims/request-context.js";
3
+ import { isExternalUrl, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
4
+ import { hasBasePath } from "../utils/base-path.js";
5
+ import { normalizeTrailingSlash, resolvePublicFileRoute, validateImageUrl } from "./request-pipeline.js";
6
+ import { headersContextFromRequest } from "../shims/headers.js";
7
+ import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
8
+ import { getScriptNonceFromHeaderSources } from "./csp.js";
9
+ import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
10
+ import { applyAppMiddleware } from "./app-middleware.js";
11
+ import { buildPageCacheTags } from "./implicit-tags.js";
12
+ import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
13
+ import { pickRootParams, setRootParams } from "../shims/root-params.js";
14
+ import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
15
+ import { flattenErrorCauses } from "../utils/error-cause.js";
16
+ import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
17
+ import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
18
+ import { handleMetadataRouteRequest } from "./metadata-route-response.js";
19
+ import { runWithPrerenderWorkUnit } from "./prerender-work-unit-setup.js";
20
+ //#region src/server/app-rsc-handler.ts
21
+ function hasProperty(value, key) {
22
+ return key in value;
23
+ }
24
+ function isExecutionContextLike(value) {
25
+ if (!value || typeof value !== "object") return false;
26
+ return hasProperty(value, "waitUntil") && typeof value.waitUntil === "function";
27
+ }
28
+ function redirectDestinationWithBasePath(destination, basePath) {
29
+ if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) return destination;
30
+ return basePath + destination;
31
+ }
32
+ async function applyRewrite(options, cleanPathname) {
33
+ if (!options.rewrites.length) return null;
34
+ const rewritten = matchRewrite(cleanPathname, options.rewrites, options.requestContext);
35
+ if (!rewritten) return null;
36
+ if (isExternalUrl(rewritten)) {
37
+ options.clearRequestContext();
38
+ return proxyExternalRequest(options.request, rewritten);
39
+ }
40
+ return rewritten;
41
+ }
42
+ async function handleAppRscRequest(options, request, preMiddlewareRequestContext) {
43
+ const handlerStart = process.env.NODE_ENV !== "production" ? performance.now() : 0;
44
+ if (process.env.NODE_ENV !== "production") {
45
+ const originBlock = options.validateDevRequestOrigin?.(request);
46
+ if (originBlock) return originBlock;
47
+ }
48
+ const normalized = normalizeRscRequest(request, options.basePath);
49
+ if (normalized instanceof Response) return normalized;
50
+ const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader } = normalized;
51
+ let { pathname, cleanPathname } = normalized;
52
+ const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
53
+ isPrerenderEnabled() {
54
+ return process.env.VINEXT_PRERENDER === "1";
55
+ },
56
+ loadPagesRoutes: options.loadPrerenderPagesRoutes,
57
+ pathname,
58
+ rootParamNamesByPattern: options.rootParamNamesByPattern,
59
+ staticParamsMap: options.staticParamsMap
60
+ });
61
+ if (prerenderEndpointResponse) return prerenderEndpointResponse;
62
+ const trailingSlashRedirect = normalizeTrailingSlash(pathname, options.basePath, options.trailingSlash, url.search);
63
+ if (trailingSlashRedirect) return trailingSlashRedirect;
64
+ const redirect = matchRedirect(pathname.endsWith(".rsc") ? pathname.slice(0, -4) : pathname, options.configRedirects, preMiddlewareRequestContext);
65
+ if (redirect) {
66
+ const destination = sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath));
67
+ return new Response(null, {
68
+ status: redirect.permanent ? 308 : 307,
69
+ headers: { Location: destination }
70
+ });
71
+ }
72
+ const middlewareContext = {
73
+ headers: null,
74
+ requestHeaders: null,
75
+ status: null
76
+ };
77
+ if (options.middlewareModule) {
78
+ const middlewareResult = await applyAppMiddleware({
79
+ basePath: options.basePath,
80
+ cleanPathname,
81
+ context: middlewareContext,
82
+ i18nConfig: options.i18nConfig,
83
+ isProxy: options.isMiddlewareProxy,
84
+ module: options.middlewareModule,
85
+ request
86
+ });
87
+ if (middlewareResult.kind === "response") return middlewareResult.response;
88
+ cleanPathname = middlewareResult.cleanPathname;
89
+ if (middlewareResult.search !== null) url.search = middlewareResult.search;
90
+ }
91
+ const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);
92
+ const postMiddlewareRequestContext = buildPostMwRequestContext(request);
93
+ const beforeFilesRewrite = await applyRewrite({
94
+ clearRequestContext: options.clearRequestContext,
95
+ request,
96
+ requestContext: postMiddlewareRequestContext,
97
+ rewrites: options.configRewrites.beforeFiles
98
+ }, cleanPathname);
99
+ if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;
100
+ if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;
101
+ if (cleanPathname === "/_vinext/image") {
102
+ const imageUrlResult = validateImageUrl(url.searchParams.get("url"), request.url);
103
+ if (imageUrlResult instanceof Response) return imageUrlResult;
104
+ return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);
105
+ }
106
+ const metadataRouteResponse = await handleMetadataRouteRequest({
107
+ metadataRoutes: options.metadataRoutes,
108
+ cleanPathname,
109
+ makeThenableParams: options.makeThenableParams
110
+ });
111
+ if (metadataRouteResponse) return metadataRouteResponse;
112
+ const publicFileResponse = resolvePublicFileRoute({
113
+ cleanPathname,
114
+ middlewareContext,
115
+ pathname,
116
+ publicFiles: options.publicFiles,
117
+ request
118
+ });
119
+ if (publicFileResponse) {
120
+ options.clearRequestContext();
121
+ return publicFileResponse;
122
+ }
123
+ options.setNavigationContext({
124
+ pathname: cleanPathname,
125
+ searchParams: url.searchParams,
126
+ params: {}
127
+ });
128
+ const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
129
+ const contentType = request.headers.get("content-type") || "";
130
+ const progressiveActionResponse = await options.handleProgressiveActionRequest({
131
+ actionId,
132
+ cleanPathname,
133
+ contentType,
134
+ middlewareContext,
135
+ request
136
+ });
137
+ if (progressiveActionResponse) return progressiveActionResponse;
138
+ const serverActionResponse = await options.handleServerActionRequest({
139
+ actionId,
140
+ cleanPathname,
141
+ contentType,
142
+ interceptionContext: interceptionContextHeader,
143
+ isRscRequest,
144
+ middlewareContext,
145
+ mountedSlotsHeader,
146
+ request,
147
+ searchParams: url.searchParams
148
+ });
149
+ if (serverActionResponse) return serverActionResponse;
150
+ const afterFilesRewrite = await applyRewrite({
151
+ clearRequestContext: options.clearRequestContext,
152
+ request,
153
+ requestContext: postMiddlewareRequestContext,
154
+ rewrites: options.configRewrites.afterFiles
155
+ }, cleanPathname);
156
+ if (afterFilesRewrite instanceof Response) return afterFilesRewrite;
157
+ if (afterFilesRewrite) cleanPathname = afterFilesRewrite;
158
+ let match = options.matchRoute(cleanPathname);
159
+ if (!match) {
160
+ const fallbackRewrite = await applyRewrite({
161
+ clearRequestContext: options.clearRequestContext,
162
+ request,
163
+ requestContext: postMiddlewareRequestContext,
164
+ rewrites: options.configRewrites.fallback
165
+ }, cleanPathname);
166
+ if (fallbackRewrite instanceof Response) return fallbackRewrite;
167
+ if (fallbackRewrite) {
168
+ cleanPathname = fallbackRewrite;
169
+ match = options.matchRoute(cleanPathname);
170
+ }
171
+ }
172
+ if (!match) {
173
+ const pagesFallbackResponse = await options.renderPagesFallback?.({
174
+ isRscRequest,
175
+ middlewareContext,
176
+ request,
177
+ url
178
+ });
179
+ if (pagesFallbackResponse) {
180
+ options.clearRequestContext();
181
+ return pagesFallbackResponse;
182
+ }
183
+ const notFoundResponse = await options.renderNotFound({
184
+ isRscRequest,
185
+ middlewareContext,
186
+ request,
187
+ route: null,
188
+ scriptNonce
189
+ });
190
+ if (notFoundResponse) return notFoundResponse;
191
+ options.clearRequestContext();
192
+ const headers = new Headers();
193
+ mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
194
+ return new Response("Not Found", {
195
+ status: 404,
196
+ headers
197
+ });
198
+ }
199
+ const { route, params } = match;
200
+ options.setNavigationContext({
201
+ pathname: cleanPathname,
202
+ searchParams: url.searchParams,
203
+ params
204
+ });
205
+ setRootParams(pickRootParams(params, route.rootParamNames));
206
+ if (route.routeHandler) {
207
+ setCurrentFetchSoftTags(buildPageCacheTags(cleanPathname, [], [...route.routeSegments], "route"));
208
+ return options.dispatchMatchedRouteHandler({
209
+ cleanPathname,
210
+ middlewareContext,
211
+ params,
212
+ request,
213
+ route,
214
+ searchParams: url.searchParams
215
+ });
216
+ }
217
+ return options.dispatchMatchedPage({
218
+ cleanPathname,
219
+ handlerStart,
220
+ interceptionContext: interceptionContextHeader,
221
+ isRscRequest,
222
+ middlewareContext,
223
+ mountedSlotsHeader,
224
+ params,
225
+ request,
226
+ route,
227
+ scriptNonce,
228
+ searchParams: url.searchParams
229
+ });
230
+ }
231
+ function createAppRscHandler(options) {
232
+ return async function appRscHandler(request, ctx) {
233
+ await options.ensureInstrumentation?.();
234
+ const executionContext = isExecutionContextLike(ctx) ? ctx : getRequestExecutionContext() ?? null;
235
+ return runWithRequestContext(createRequestContext({
236
+ headersContext: headersContextFromRequest(request),
237
+ executionContext,
238
+ unstableCacheRevalidation: "background"
239
+ }), () => runWithPrerenderWorkUnit(async () => {
240
+ ensureFetchPatch();
241
+ const preMiddlewareRequestContext = requestContextFromRequest(request);
242
+ let response;
243
+ try {
244
+ response = await handleAppRscRequest(options, request, preMiddlewareRequestContext);
245
+ } catch (error) {
246
+ if (process.env.NODE_ENV !== "production") flattenErrorCauses(error);
247
+ throw error;
248
+ }
249
+ return finalizeAppRscResponse(response, request, {
250
+ basePath: options.basePath,
251
+ configHeaders: options.configHeaders,
252
+ requestContext: preMiddlewareRequestContext
253
+ });
254
+ }, { route: () => new URL(request.url).pathname }));
255
+ };
256
+ }
257
+ //#endregion
258
+ export { createAppRscHandler };
259
+
260
+ //# sourceMappingURL=app-rsc-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport {\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n handlerStart: number;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n params: AppPageParams;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(cleanPathname, options.rewrites, options.requestContext);\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader } = normalized;\n let { pathname, cleanPathname } = normalized;\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n const redirectPathname = pathname.endsWith(\".rsc\") ? pathname.slice(0, -4) : pathname;\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: destination },\n });\n }\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n });\n if (middlewareResult.kind === \"response\") return middlewareResult.response;\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n const beforeFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n cleanPathname,\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (cleanPathname === \"/_vinext/image\") {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n const actionId = request.headers.get(\"x-rsc-action\") ?? request.headers.get(\"next-action\");\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResponse = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResponse) return progressiveActionResponse;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n const afterFilesRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n cleanPathname,\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) cleanPathname = afterFilesRewrite;\n\n let match = options.matchRoute(cleanPathname);\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n cleanPathname,\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const notFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (notFoundResponse) return notFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return new Response(\"Not Found\", { status: 404, headers });\n }\n\n const { route, params } = match;\n options.setNavigationContext({\n pathname: cleanPathname,\n searchParams: url.searchParams,\n params,\n });\n setRootParams(pickRootParams(params, route.rootParamNames));\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n params,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n return options.dispatchMatchedPage({\n cleanPathname,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n });\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(request, ctx) {\n await options.ensureInstrumentation?.();\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request);\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(options, request, preMiddlewareRequestContext);\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
2
+
3
+ //#region src/server/app-rsc-request-normalization.d.ts
4
+ type NormalizedRscRequest = {
5
+ /** Parsed URL. Callers may mutate `url.search` after middleware runs. */url: URL; /** Normalized pathname with basePath stripped. Used for all internal routing. */
6
+ pathname: string; /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */
7
+ cleanPathname: string; /** True when the client requests the RSC payload (.rsc suffix or Accept: text/x-component). */
8
+ isRscRequest: boolean; /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
9
+ interceptionContextHeader: string | null; /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */
10
+ mountedSlotsHeader: string | null;
11
+ };
12
+ /**
13
+ * Normalize an App Router RSC request.
14
+ *
15
+ * Performs all security-sensitive and compatibility-sensitive preprocessing before
16
+ * route matching. The ordering of steps is security-critical — changing it introduces
17
+ * vulnerabilities:
18
+ *
19
+ * 1. Parse URL
20
+ * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses
21
+ * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`
22
+ * would bypass the check and reach the trailing-slash redirector, which echoes the
23
+ * path into a `Location` header that browsers interpret as protocol-relative.
24
+ * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must
25
+ * run before basePath check so %2F-encoded slashes cannot create fake basePath prefixes.
26
+ * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
27
+ * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
28
+ * `/__vinext/` bypasses this for internal prerender endpoints.
29
+ * 6. RSC detection: `.rsc` suffix or `Accept: text/x-component`
30
+ * 7. cleanPathname — pathname with `.rsc` suffix stripped
31
+ * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
32
+ * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
33
+ *
34
+ * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
35
+ * or a NormalizedRscRequest for valid requests.
36
+ */
37
+ declare function normalizeRscRequest(request: Request, basePath: string): Response | NormalizedRscRequest;
38
+ //#endregion
39
+ export { NormalizedRscRequest, normalizeMountedSlotsHeader, normalizeRscRequest };
40
+ //# sourceMappingURL=app-rsc-request-normalization.d.ts.map