vinext 0.1.2 → 0.1.3

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 (199) hide show
  1. package/dist/build/prerender.d.ts +9 -1
  2. package/dist/build/prerender.js +41 -12
  3. package/dist/build/run-prerender.d.ts +10 -2
  4. package/dist/build/run-prerender.js +15 -1
  5. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  6. package/dist/client/app-nav-failure-handler.js +44 -0
  7. package/dist/client/vinext-next-data.d.ts +18 -1
  8. package/dist/client/window-next.d.ts +2 -1
  9. package/dist/client/window-next.js +12 -1
  10. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  11. package/dist/config/config-matchers.js +73 -14
  12. package/dist/config/next-config.d.ts +46 -4
  13. package/dist/config/next-config.js +147 -48
  14. package/dist/deploy.d.ts +30 -11
  15. package/dist/deploy.js +180 -99
  16. package/dist/entries/app-browser-entry.d.ts +9 -3
  17. package/dist/entries/app-browser-entry.js +21 -3
  18. package/dist/entries/app-rsc-entry.d.ts +2 -0
  19. package/dist/entries/app-rsc-entry.js +64 -5
  20. package/dist/entries/app-rsc-manifest.js +2 -0
  21. package/dist/entries/app-ssr-entry.js +1 -1
  22. package/dist/entries/pages-client-entry.js +53 -8
  23. package/dist/entries/pages-server-entry.js +41 -5
  24. package/dist/index.js +200 -62
  25. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  26. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  27. package/dist/plugins/optimize-imports.d.ts +2 -1
  28. package/dist/plugins/optimize-imports.js +11 -9
  29. package/dist/plugins/postcss.js +7 -7
  30. package/dist/plugins/typeof-window.d.ts +14 -0
  31. package/dist/plugins/typeof-window.js +150 -0
  32. package/dist/routing/app-route-graph.d.ts +2 -1
  33. package/dist/routing/app-route-graph.js +44 -14
  34. package/dist/routing/file-matcher.d.ts +10 -1
  35. package/dist/routing/file-matcher.js +22 -1
  36. package/dist/routing/pages-router.js +3 -3
  37. package/dist/routing/utils.d.ts +35 -6
  38. package/dist/routing/utils.js +59 -7
  39. package/dist/server/api-handler.d.ts +6 -1
  40. package/dist/server/api-handler.js +21 -15
  41. package/dist/server/app-browser-action-result.d.ts +19 -6
  42. package/dist/server/app-browser-action-result.js +19 -10
  43. package/dist/server/app-browser-entry.js +167 -90
  44. package/dist/server/app-browser-error.d.ts +10 -6
  45. package/dist/server/app-browser-error.js +43 -8
  46. package/dist/server/app-browser-hydration.d.ts +2 -0
  47. package/dist/server/app-browser-hydration.js +1 -0
  48. package/dist/server/app-browser-navigation-controller.d.ts +4 -2
  49. package/dist/server/app-browser-navigation-controller.js +23 -2
  50. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  51. package/dist/server/app-browser-server-action-navigation.js +9 -0
  52. package/dist/server/app-browser-stream.js +86 -43
  53. package/dist/server/app-elements-wire.d.ts +6 -1
  54. package/dist/server/app-elements-wire.js +14 -4
  55. package/dist/server/app-elements.d.ts +2 -2
  56. package/dist/server/app-elements.js +2 -2
  57. package/dist/server/app-fallback-renderer.d.ts +1 -0
  58. package/dist/server/app-fallback-renderer.js +3 -1
  59. package/dist/server/app-optimistic-routing.js +2 -2
  60. package/dist/server/app-page-boundary-render.d.ts +1 -0
  61. package/dist/server/app-page-boundary-render.js +27 -14
  62. package/dist/server/app-page-cache-render.d.ts +53 -0
  63. package/dist/server/app-page-cache-render.js +91 -0
  64. package/dist/server/app-page-cache.d.ts +16 -2
  65. package/dist/server/app-page-cache.js +62 -1
  66. package/dist/server/app-page-dispatch.d.ts +26 -0
  67. package/dist/server/app-page-dispatch.js +149 -92
  68. package/dist/server/app-page-element-builder.d.ts +1 -0
  69. package/dist/server/app-page-element-builder.js +5 -2
  70. package/dist/server/app-page-execution.d.ts +6 -1
  71. package/dist/server/app-page-execution.js +21 -1
  72. package/dist/server/app-page-probe.d.ts +1 -0
  73. package/dist/server/app-page-probe.js +4 -0
  74. package/dist/server/app-page-render-observation.d.ts +3 -1
  75. package/dist/server/app-page-render-observation.js +17 -1
  76. package/dist/server/app-page-render.d.ts +12 -1
  77. package/dist/server/app-page-render.js +42 -4
  78. package/dist/server/app-page-request.d.ts +2 -0
  79. package/dist/server/app-page-request.js +2 -1
  80. package/dist/server/app-page-route-wiring.d.ts +3 -1
  81. package/dist/server/app-page-route-wiring.js +14 -5
  82. package/dist/server/app-page-stream.d.ts +15 -3
  83. package/dist/server/app-page-stream.js +11 -5
  84. package/dist/server/app-pages-bridge.d.ts +18 -0
  85. package/dist/server/app-pages-bridge.js +22 -5
  86. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  87. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  88. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  89. package/dist/server/app-ppr-fallback-shell.js +8 -1
  90. package/dist/server/app-route-handler-dispatch.js +9 -2
  91. package/dist/server/app-route-handler-policy.d.ts +1 -0
  92. package/dist/server/app-router-entry.js +5 -0
  93. package/dist/server/app-rsc-cache-busting.js +2 -0
  94. package/dist/server/app-rsc-handler.d.ts +25 -0
  95. package/dist/server/app-rsc-handler.js +154 -54
  96. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  97. package/dist/server/app-rsc-route-matching.js +2 -0
  98. package/dist/server/app-segment-config.d.ts +9 -1
  99. package/dist/server/app-segment-config.js +12 -3
  100. package/dist/server/app-server-action-execution.d.ts +1 -0
  101. package/dist/server/app-server-action-execution.js +42 -13
  102. package/dist/server/app-ssr-entry.d.ts +2 -0
  103. package/dist/server/app-ssr-entry.js +83 -10
  104. package/dist/server/cache-control.js +4 -0
  105. package/dist/server/dev-server.d.ts +2 -2
  106. package/dist/server/dev-server.js +244 -51
  107. package/dist/server/hybrid-route-priority.d.ts +22 -0
  108. package/dist/server/hybrid-route-priority.js +33 -0
  109. package/dist/server/image-optimization.d.ts +18 -9
  110. package/dist/server/image-optimization.js +37 -23
  111. package/dist/server/implicit-tags.d.ts +2 -1
  112. package/dist/server/implicit-tags.js +4 -1
  113. package/dist/server/navigation-planner.d.ts +133 -30
  114. package/dist/server/navigation-planner.js +114 -0
  115. package/dist/server/navigation-trace.d.ts +8 -1
  116. package/dist/server/navigation-trace.js +8 -1
  117. package/dist/server/pages-api-route.d.ts +6 -0
  118. package/dist/server/pages-api-route.js +13 -2
  119. package/dist/server/pages-asset-tags.d.ts +2 -1
  120. package/dist/server/pages-asset-tags.js +6 -2
  121. package/dist/server/pages-data-route.d.ts +8 -1
  122. package/dist/server/pages-data-route.js +11 -2
  123. package/dist/server/pages-get-initial-props.d.ts +54 -4
  124. package/dist/server/pages-get-initial-props.js +43 -1
  125. package/dist/server/pages-node-compat.js +2 -2
  126. package/dist/server/pages-page-data.d.ts +11 -2
  127. package/dist/server/pages-page-data.js +204 -33
  128. package/dist/server/pages-page-handler.d.ts +4 -2
  129. package/dist/server/pages-page-handler.js +59 -22
  130. package/dist/server/pages-page-response.d.ts +2 -1
  131. package/dist/server/pages-page-response.js +7 -4
  132. package/dist/server/pages-request-pipeline.d.ts +1 -0
  133. package/dist/server/pages-request-pipeline.js +73 -36
  134. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  135. package/dist/server/pregenerated-concrete-paths.js +2 -19
  136. package/dist/server/prerender-manifest.d.ts +33 -0
  137. package/dist/server/prerender-manifest.js +54 -0
  138. package/dist/server/prerender-route-params.d.ts +1 -2
  139. package/dist/server/prod-server.js +9 -3
  140. package/dist/server/request-pipeline.d.ts +3 -15
  141. package/dist/server/request-pipeline.js +58 -47
  142. package/dist/server/rsc-stream-hints.d.ts +5 -1
  143. package/dist/server/rsc-stream-hints.js +6 -1
  144. package/dist/server/seed-cache.js +10 -18
  145. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  146. package/dist/shims/app-router-scroll-state.js +14 -2
  147. package/dist/shims/app-router-scroll.d.ts +3 -0
  148. package/dist/shims/app-router-scroll.js +28 -18
  149. package/dist/shims/cache-runtime.js +3 -2
  150. package/dist/shims/cache.d.ts +1 -0
  151. package/dist/shims/cache.js +1 -1
  152. package/dist/shims/cdn-cache.d.ts +5 -5
  153. package/dist/shims/dynamic-preload-chunks.js +6 -4
  154. package/dist/shims/error-boundary.d.ts +2 -0
  155. package/dist/shims/error-boundary.js +7 -0
  156. package/dist/shims/error.js +3 -2
  157. package/dist/shims/error.react-server.d.ts +9 -0
  158. package/dist/shims/error.react-server.js +6 -0
  159. package/dist/shims/fetch-cache.d.ts +3 -1
  160. package/dist/shims/fetch-cache.js +45 -20
  161. package/dist/shims/hash-scroll.js +6 -1
  162. package/dist/shims/headers.js +29 -4
  163. package/dist/shims/internal/als-registry.js +28 -1
  164. package/dist/shims/internal/app-route-detection.js +8 -17
  165. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  166. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  167. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  168. package/dist/shims/internal/navigation-untracked.js +55 -0
  169. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  170. package/dist/shims/internal/pages-data-target.js +17 -8
  171. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  172. package/dist/shims/internal/pages-router-accessor.js +13 -0
  173. package/dist/shims/internal/router-context.d.ts +2 -1
  174. package/dist/shims/internal/router-context.js +3 -1
  175. package/dist/shims/link.js +12 -5
  176. package/dist/shims/navigation.d.ts +8 -2
  177. package/dist/shims/navigation.js +61 -31
  178. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  179. package/dist/shims/ppr-fallback-shell.js +28 -7
  180. package/dist/shims/router.d.ts +13 -2
  181. package/dist/shims/router.js +419 -128
  182. package/dist/shims/server.d.ts +16 -1
  183. package/dist/shims/server.js +44 -12
  184. package/dist/shims/unified-request-context.js +1 -0
  185. package/dist/utils/built-asset-url.d.ts +4 -0
  186. package/dist/utils/built-asset-url.js +11 -0
  187. package/dist/utils/commonjs-loader.d.ts +16 -0
  188. package/dist/utils/commonjs-loader.js +100 -0
  189. package/dist/utils/deployment-id.d.ts +8 -0
  190. package/dist/utils/deployment-id.js +22 -0
  191. package/dist/utils/html-limited-bots.d.ts +18 -1
  192. package/dist/utils/html-limited-bots.js +23 -1
  193. package/dist/utils/parse-cookie.d.ts +13 -0
  194. package/dist/utils/parse-cookie.js +52 -0
  195. package/dist/utils/path.d.ts +7 -1
  196. package/dist/utils/path.js +9 -1
  197. package/package.json +2 -2
  198. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  199. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -56,32 +56,46 @@ const DEFAULT_IMAGE_SIZES = [
56
56
  256,
57
57
  384
58
58
  ];
59
- /**
60
- * Absolute maximum image width. Even if custom deviceSizes/imageSizes are
61
- * configured, widths above this are always rejected. This prevents resource
62
- * exhaustion from absurdly large resize requests.
63
- */
64
- const ABSOLUTE_MAX_WIDTH = 3840;
59
+ const DEV_BLUR_MAX_WIDTH = 8;
60
+ const DEV_BLUR_QUALITY = 70;
61
+ function resolveDevImageRedirect(requestUrl, allowedWidths = [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES], allowedQualities, options = { isDev: true }) {
62
+ const params = parseImageParams(requestUrl, allowedWidths, allowedQualities, options);
63
+ if (!params) return null;
64
+ if (params.imageUrl.startsWith("/@") || params.imageUrl.startsWith("/__vite") || params.imageUrl.startsWith("/node_modules")) return null;
65
+ const resolved = new URL(params.imageUrl, requestUrl.origin);
66
+ if (resolved.origin !== requestUrl.origin) return null;
67
+ return resolved.pathname + resolved.search;
68
+ }
65
69
  /**
66
70
  * Parse and validate image optimization query parameters.
67
71
  * Returns null if the request is malformed.
68
72
  *
69
- * When `allowedWidths` is provided, the width must be 0 (no resize) or
70
- * exactly match one of the allowed values. This matches Next.js behavior
71
- * where only configured deviceSizes and imageSizes are accepted.
72
- *
73
- * When `allowedWidths` is not provided, any width from 0 to ABSOLUTE_MAX_WIDTH
74
- * is accepted (backwards-compatible fallback).
73
+ * Ported from Next.js:
74
+ * test/integration/image-optimizer/test/index.test.ts
75
+ * https://github.com/vercel/next.js/blob/canary/test/integration/image-optimizer/test/index.test.ts
75
76
  */
76
- function parseImageParams(url, allowedWidths) {
77
+ function parseImageParams(url, allowedWidths = [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES], allowedQualities, options = {}) {
78
+ const allowedParamNames = new Set([
79
+ "url",
80
+ "w",
81
+ "q"
82
+ ]);
83
+ for (const name of url.searchParams.keys()) if (!allowedParamNames.has(name) || url.searchParams.getAll(name).length !== 1) return null;
77
84
  const imageUrl = url.searchParams.get("url");
78
85
  if (!imageUrl) return null;
79
- const w = parseInt(url.searchParams.get("w") || "0", 10);
80
- const q = parseInt(url.searchParams.get("q") || "75", 10);
81
- if (Number.isNaN(w) || w < 0) return null;
82
- if (w > ABSOLUTE_MAX_WIDTH) return null;
83
- if (allowedWidths && w !== 0 && !allowedWidths.includes(w)) return null;
84
- if (Number.isNaN(q) || q < 1 || q > 100) return null;
86
+ if (imageUrl.length > 3072) return null;
87
+ const widthParam = url.searchParams.get("w");
88
+ const qualityParam = url.searchParams.get("q");
89
+ if (!widthParam || !/^[0-9]+$/.test(widthParam)) return null;
90
+ if (!qualityParam || !/^[0-9]+$/.test(qualityParam)) return null;
91
+ const width = Number.parseInt(widthParam, 10);
92
+ const quality = Number.parseInt(qualityParam, 10);
93
+ if (String(width) !== widthParam || String(quality) !== qualityParam) return null;
94
+ const isDevBlurWidth = options.isDev && width <= DEV_BLUR_MAX_WIDTH;
95
+ const isDevBlurQuality = options.isDev && quality === DEV_BLUR_QUALITY;
96
+ if (width <= 0 || !allowedWidths.includes(width) && !isDevBlurWidth) return null;
97
+ if (quality < 1 || quality > 100) return null;
98
+ if (allowedQualities && !allowedQualities.includes(quality) && !isDevBlurQuality) return null;
85
99
  const normalizedUrl = imageUrl.replaceAll("\\", "/");
86
100
  if (!normalizedUrl.startsWith("/") || normalizedUrl.startsWith("//")) return null;
87
101
  try {
@@ -92,8 +106,8 @@ function parseImageParams(url, allowedWidths) {
92
106
  }
93
107
  return {
94
108
  imageUrl: normalizedUrl,
95
- width: w,
96
- quality: q
109
+ width,
110
+ quality
97
111
  };
98
112
  }
99
113
  /**
@@ -174,7 +188,7 @@ function createPassthroughImageResponse(source, config) {
174
188
  * cache headers.
175
189
  */
176
190
  async function handleImageOptimization(request, handlers, allowedWidths, imageConfig) {
177
- const params = parseImageParams(new URL(request.url), allowedWidths);
191
+ const params = parseImageParams(new URL(request.url), allowedWidths, imageConfig?.qualities);
178
192
  if (!params) return badRequestResponse();
179
193
  const { imageUrl, width, quality } = params;
180
194
  const source = await handlers.fetchAsset(imageUrl, request);
@@ -212,4 +226,4 @@ async function handleImageOptimization(request, handlers, allowedWidths, imageCo
212
226
  }
213
227
  }
214
228
  //#endregion
215
- export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, VINEXT_IMAGE_OPTIMIZATION_PATH, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams };
229
+ export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, VINEXT_IMAGE_OPTIMIZATION_PATH, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams, resolveDevImageRedirect };
@@ -1,5 +1,6 @@
1
1
  //#region src/server/implicit-tags.d.ts
2
2
  type AppCacheLeafKind = "page" | "route";
3
+ declare function buildAppPageTags(cleanPathname: string, extraTags: string[], routeSegments: readonly string[]): string[];
3
4
  declare function buildPageCacheTags(pathname: string, extraTags: string[], routeSegments: string[], leafKind: AppCacheLeafKind): string[];
4
5
  //#endregion
5
- export { buildPageCacheTags };
6
+ export { buildAppPageTags, buildPageCacheTags };
@@ -29,6 +29,9 @@ function appendDerivedTags(tags, routePath) {
29
29
  appendUnique(tags, `${NEXT_CACHE_IMPLICIT_TAG_ID}${currentPathname}`);
30
30
  }
31
31
  }
32
+ function buildAppPageTags(cleanPathname, extraTags, routeSegments) {
33
+ return buildPageCacheTags(cleanPathname, extraTags, [...routeSegments], "page");
34
+ }
32
35
  function buildPageCacheTags(pathname, extraTags, routeSegments, leafKind) {
33
36
  const tags = [pathname, `${NEXT_CACHE_IMPLICIT_TAG_ID}${pathname}`];
34
37
  if (pathname === "/") appendUnique(tags, `${NEXT_CACHE_IMPLICIT_TAG_ID}/index`);
@@ -38,4 +41,4 @@ function buildPageCacheTags(pathname, extraTags, routeSegments, leafKind) {
38
41
  return tags.map(encodeCacheTag);
39
42
  }
40
43
  //#endregion
41
- export { buildPageCacheTags };
44
+ export { buildAppPageTags, buildPageCacheTags };
@@ -14,34 +14,34 @@ type OperationToken = {
14
14
  targetSnapshotFingerprint: string;
15
15
  cacheVariantFingerprint?: string;
16
16
  };
17
- type RouteSnapshotV0 = {
18
- interception: InterceptionSnapshotV0 | null;
17
+ type RouteSnapshot = {
18
+ interception: InterceptionSnapshot | null;
19
19
  interceptionContext: string | null;
20
20
  routeId: string;
21
21
  layoutIds: readonly string[];
22
- mountedParallelSlots: readonly MountedParallelSlotSnapshotV0[];
22
+ mountedParallelSlots: readonly MountedParallelSlotSnapshot[];
23
23
  rootBoundaryId: string | null;
24
24
  displayUrl: string;
25
25
  matchedUrl: string;
26
- slotBindings: readonly ParallelSlotBindingSnapshotV0[];
26
+ slotBindings: readonly ParallelSlotBindingSnapshot[];
27
27
  };
28
- type InterceptionSnapshotV0 = {
28
+ type InterceptionSnapshot = {
29
29
  sourceMatchedUrl: string;
30
30
  sourceRouteId: string;
31
31
  slotId: string;
32
32
  targetMatchedUrl: string;
33
33
  targetRouteId: string;
34
34
  };
35
- type MountedParallelSlotSnapshotV0 = {
35
+ type MountedParallelSlotSnapshot = {
36
36
  slotId: string;
37
37
  ownerLayoutId: string | null;
38
38
  };
39
- type ParallelSlotBindingSnapshotV0 = AppElementsSlotBinding;
40
- type NavigationPlannerStateV0 = {
39
+ type ParallelSlotBindingSnapshot = AppElementsSlotBinding;
40
+ type NavigationPlannerState = {
41
41
  nextOperationToken: OperationToken;
42
42
  traceFields?: NavigationTraceFields;
43
43
  visibleCommitVersion: number;
44
- visibleSnapshot: RouteSnapshotV0;
44
+ visibleSnapshot: RouteSnapshot;
45
45
  };
46
46
  type RefreshScope = "visible";
47
47
  type TraverseDirection = "back" | "forward" | "unknown";
@@ -62,7 +62,7 @@ type NavigationEvent = {
62
62
  } | {
63
63
  kind: "flightResponseArrived";
64
64
  token: OperationToken;
65
- result: FlightResultV0;
65
+ result: FlightResult;
66
66
  };
67
67
  type RequestedWork = {
68
68
  kind: "flight";
@@ -82,12 +82,12 @@ type CommitProposal = {
82
82
  preserveElementIds: readonly string[];
83
83
  preservePreviousSlotIds: readonly string[];
84
84
  reason: "currentRootBoundary" | "interceptedCurrentRootBoundary" | "unprovenTopologyFallback";
85
- targetSnapshot: RouteSnapshotV0;
85
+ targetSnapshot: RouteSnapshot;
86
86
  };
87
87
  type NoCommitReason = "prefetchOnly";
88
88
  type HardNavigationReason = "cacheProofRejected" | "interceptionProofRejected" | "rootBoundaryChanged";
89
89
  type RootBoundaryTransition = "currentRootBoundary" | "rootBoundaryChanged" | "rootBoundaryUnknown";
90
- type NavigationDecisionV0 = {
90
+ type NavigationDecision = {
91
91
  kind: "requestWork";
92
92
  token: OperationToken;
93
93
  work: RequestedWork;
@@ -109,13 +109,13 @@ type NavigationDecisionV0 = {
109
109
  reason: HardNavigationReason;
110
110
  trace: NavigationTrace;
111
111
  };
112
- type FlightResultV0 = {
112
+ type FlightResult = {
113
113
  cacheEntryReuseProof?: CacheEntryReuseProof;
114
114
  href: string;
115
- targetSnapshot: RouteSnapshotV0;
115
+ targetSnapshot: RouteSnapshot;
116
116
  };
117
117
  type RscFetchResultSource = "cached" | "live";
118
- type RscFetchResultFactsV0 = {
118
+ type RscFetchResultFacts = {
119
119
  source: RscFetchResultSource;
120
120
  currentHref: string;
121
121
  origin: string;
@@ -130,21 +130,21 @@ type RscFetchResultFactsV0 = {
130
130
  responseUrl: string | null;
131
131
  streamedRedirectTarget: string | null;
132
132
  };
133
- type RscRedirectFollowV0 = {
133
+ type RscRedirectFollow = {
134
134
  href: string;
135
135
  historyUpdateMode: "push" | "replace";
136
136
  previousNextUrl: string | null;
137
137
  redirectDepth: number;
138
138
  };
139
139
  type RscFetchResultHardNavReason = "invalidRscPayload" | "rscCompatibilityMismatch" | "externalRedirectTarget" | "redirectDepthExhausted" | "streamedRedirectLoop";
140
- type RscFetchResultDecisionV0 = {
140
+ type RscFetchResultDecision = {
141
141
  kind: "proceedToCommit";
142
142
  discardBody: false;
143
143
  trace: NavigationTrace;
144
144
  } | {
145
145
  kind: "followRedirect";
146
146
  discardBody: boolean;
147
- redirect: RscRedirectFollowV0;
147
+ redirect: RscRedirectFollow;
148
148
  trace: NavigationTrace;
149
149
  } | {
150
150
  kind: "hardNavigate";
@@ -153,14 +153,14 @@ type RscFetchResultDecisionV0 = {
153
153
  reason: RscFetchResultHardNavReason;
154
154
  trace: NavigationTrace;
155
155
  };
156
- type EarlyNavigationIntentFactsV0 = {
156
+ type EarlyNavigationIntentFacts = {
157
157
  basePath: string;
158
158
  currentHref: string;
159
159
  mode: "push" | "replace";
160
160
  scroll: boolean;
161
161
  targetHref: string;
162
162
  };
163
- type EarlyNavigationIntentDecisionV0 = {
163
+ type EarlyNavigationIntentDecision = {
164
164
  kind: "sameDocumentScroll";
165
165
  hash: string;
166
166
  mode: "push" | "replace";
@@ -171,20 +171,86 @@ type EarlyNavigationIntentDecisionV0 = {
171
171
  bypassNavigationCache: boolean;
172
172
  trace: NavigationTrace;
173
173
  };
174
+ type NavigationReuseNavigationKind = "navigate" | "refresh" | "traverse";
175
+ type VisitedResponseCacheCandidateFacts = {
176
+ candidate: "missing";
177
+ navigationKind: NavigationReuseNavigationKind;
178
+ } | {
179
+ candidate: "present";
180
+ fresh: boolean;
181
+ mountedSlotsMatch: boolean;
182
+ navigationKind: NavigationReuseNavigationKind;
183
+ };
184
+ type VisitedResponseCacheCandidateDecision = {
185
+ kind: "miss";
186
+ } | {
187
+ kind: "evict";
188
+ reason: "mountedSlotsMismatch" | "refresh" | "stale";
189
+ } | {
190
+ kind: "reuse";
191
+ };
192
+ type NavigationReuseCandidateAvailability = {
193
+ status: "available";
194
+ } | {
195
+ status: "unavailable";
196
+ };
197
+ type OptimisticRouteShellCandidateAvailability = {
198
+ status: "available";
199
+ } | {
200
+ status: "unavailable";
201
+ reason: "routeManifestMissing";
202
+ };
203
+ type NavigationReuseFacts = {
204
+ bypassNavigationCache: boolean;
205
+ navigationKind: NavigationReuseNavigationKind;
206
+ optimisticRouteShell: OptimisticRouteShellCandidateAvailability;
207
+ prefetch: NavigationReuseCandidateAvailability;
208
+ targetHref: string;
209
+ visitedResponse: NavigationReuseCandidateAvailability;
210
+ };
211
+ type FreshFetchReason = "cacheBypassed" | "cacheMiss" | "refresh" | "routeManifestMissing";
212
+ type NavigationReuseDecision = {
213
+ kind: "reuseVisitedResponse";
214
+ trace: NavigationTrace;
215
+ } | {
216
+ kind: "consumePrefetch";
217
+ trace: NavigationTrace;
218
+ } | {
219
+ kind: "attemptOptimisticRouteShell";
220
+ trace: NavigationTrace;
221
+ } | {
222
+ kind: "fetchFresh";
223
+ reason: FreshFetchReason;
224
+ trace: NavigationTrace;
225
+ };
226
+ type NavigationPrefetchProbeFacts = {
227
+ bypassNavigationCache: boolean;
228
+ navigationKind: NavigationReuseNavigationKind;
229
+ visitedResponse: NavigationReuseCandidateAvailability;
230
+ };
231
+ type NavigationPrefetchProbeDecision = {
232
+ kind: "probe";
233
+ } | {
234
+ kind: "skip";
235
+ reason: "cacheBypassed" | "refresh" | "visitedResponseAvailable";
236
+ };
174
237
  type NavigationPlannerInput = {
175
238
  routeManifest: RouteManifest | null;
176
- state: NavigationPlannerStateV0;
239
+ state: NavigationPlannerState;
177
240
  event: NavigationEvent;
178
241
  };
179
242
  type AcceptedCacheEntryReuseDecision = Extract<CacheEntryReuseDecision, {
180
243
  canReuse: true;
181
244
  }>;
182
- declare function classifyRscFetchResult(facts: RscFetchResultFactsV0): RscFetchResultDecisionV0;
183
- declare function classifyEarlyNavigationIntent(facts: EarlyNavigationIntentFactsV0): EarlyNavigationIntentDecisionV0;
245
+ declare function classifyRscFetchResult(facts: RscFetchResultFacts): RscFetchResultDecision;
246
+ declare function classifyEarlyNavigationIntent(facts: EarlyNavigationIntentFacts): EarlyNavigationIntentDecision;
247
+ declare function classifyVisitedResponseCacheCandidate(facts: VisitedResponseCacheCandidateFacts): VisitedResponseCacheCandidateDecision;
248
+ declare function classifyNavigationReuse(facts: NavigationReuseFacts): NavigationReuseDecision;
249
+ declare function classifyNavigationPrefetchProbe(facts: NavigationPrefetchProbeFacts): NavigationPrefetchProbeDecision;
184
250
  declare function classifyRootBoundaryTransition(currentRootBoundaryId: string | null, nextRootBoundaryId: string | null): RootBoundaryTransition;
185
- declare function resolveSameLayoutAncestorPersistence(currentSnapshot: RouteSnapshotV0, targetSnapshot: RouteSnapshotV0): readonly string[];
186
- declare function resolveMountedParallelSlotPersistence(currentSnapshot: RouteSnapshotV0, targetSnapshot: RouteSnapshotV0): readonly string[];
187
- declare function resolveCurrentRootBoundaryElementPersistence(currentSnapshot: RouteSnapshotV0, targetSnapshot: RouteSnapshotV0): readonly string[];
251
+ declare function resolveSameLayoutAncestorPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
252
+ declare function resolveMountedParallelSlotPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
253
+ declare function resolveCurrentRootBoundaryElementPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
188
254
  /**
189
255
  * Default/unmatched slot preservation law:
190
256
  *
@@ -196,19 +262,56 @@ declare function resolveCurrentRootBoundaryElementPersistence(currentSnapshot: R
196
262
  * Wire absence and UNMATCHED_SLOT markers are not semantic proof.
197
263
  */
198
264
  declare function resolveDefaultOrUnmatchedSlotPersistenceForLayouts(options: {
199
- currentSlotBindings: readonly ParallelSlotBindingSnapshotV0[];
265
+ currentSlotBindings: readonly ParallelSlotBindingSnapshot[];
200
266
  preservedLayoutIds: readonly string[];
201
- targetSlotBindings: readonly ParallelSlotBindingSnapshotV0[];
267
+ targetSlotBindings: readonly ParallelSlotBindingSnapshot[];
202
268
  }): readonly string[];
203
- declare function planNavigation(input: NavigationPlannerInput): NavigationDecisionV0;
269
+ declare function planNavigation(input: NavigationPlannerInput): NavigationDecision;
270
+ type ServerActionResultFacts = {
271
+ actionRedirectHref: string | null;
272
+ actionRedirectType: "push" | "replace";
273
+ clientCompatibilityId: string | null;
274
+ compatibilityIdHeader: string | null;
275
+ currentHref: string;
276
+ isRscContentType: boolean;
277
+ origin: string;
278
+ responseUrl: string | null;
279
+ };
280
+ type ServerActionResultDecision = {
281
+ kind: "proceed";
282
+ trace: NavigationTrace;
283
+ } | {
284
+ kind: "hardNavigate";
285
+ url: string;
286
+ historyMode?: "assign" | "replace";
287
+ clearClientNavigationCaches: boolean;
288
+ reason: "serverActionRedirectCompatibilityMismatch" | "serverActionRscCompatibilityMismatch";
289
+ trace: NavigationTrace;
290
+ };
291
+ type RscNavigationErrorFacts = {
292
+ currentHref: string;
293
+ };
294
+ type RscNavigationErrorDecision = {
295
+ kind: "hardNavigate";
296
+ url: string;
297
+ reason: "rscNavigationError";
298
+ trace: NavigationTrace;
299
+ };
300
+ declare function classifyServerActionResult(facts: ServerActionResultFacts): ServerActionResultDecision;
301
+ declare function classifyRscNavigationError(facts: RscNavigationErrorFacts): RscNavigationErrorDecision;
204
302
  declare const navigationPlanner: {
205
303
  classifyEarlyNavigationIntent: typeof classifyEarlyNavigationIntent;
304
+ classifyNavigationPrefetchProbe: typeof classifyNavigationPrefetchProbe;
305
+ classifyNavigationReuse: typeof classifyNavigationReuse;
206
306
  classifyRscFetchResult: typeof classifyRscFetchResult;
307
+ classifyRscNavigationError: typeof classifyRscNavigationError;
207
308
  classifyRootBoundaryTransition: typeof classifyRootBoundaryTransition;
309
+ classifyServerActionResult: typeof classifyServerActionResult;
310
+ classifyVisitedResponseCacheCandidate: typeof classifyVisitedResponseCacheCandidate;
208
311
  plan: typeof planNavigation;
209
312
  resolveCurrentRootBoundaryElementPersistence: typeof resolveCurrentRootBoundaryElementPersistence;
210
313
  resolveMountedParallelSlotPersistence: typeof resolveMountedParallelSlotPersistence;
211
314
  resolveSameLayoutAncestorPersistence: typeof resolveSameLayoutAncestorPersistence;
212
315
  };
213
316
  //#endregion
214
- export { EarlyNavigationIntentDecisionV0, EarlyNavigationIntentFactsV0, FlightResultV0, InterceptionSnapshotV0, MountedParallelSlotSnapshotV0, NavigationDecisionV0, NavigationEvent, NavigationPlannerInput, NavigationPlannerStateV0, OperationLane, OperationToken, ParallelSlotBindingSnapshotV0, RefreshScope, RootBoundaryTransition, RouteSnapshotV0, RscFetchResultDecisionV0, RscFetchResultFactsV0, TraverseDirection, navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts };
317
+ export { EarlyNavigationIntentDecision, EarlyNavigationIntentFacts, FlightResult, InterceptionSnapshot, MountedParallelSlotSnapshot, NavigationDecision, NavigationEvent, NavigationPlannerInput, NavigationPlannerState, NavigationReuseDecision, NavigationReuseFacts, OperationLane, OperationToken, ParallelSlotBindingSnapshot, RefreshScope, RootBoundaryTransition, RouteSnapshot, RscFetchResultDecision, RscFetchResultFacts, RscNavigationErrorDecision, RscNavigationErrorFacts, ServerActionResultDecision, ServerActionResultFacts, TraverseDirection, VisitedResponseCacheCandidateFacts, navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts };
@@ -213,6 +213,71 @@ function classifyEarlyNavigationIntent(facts) {
213
213
  trace: createEarlyNavigationIntentTrace(NavigationTraceReasonCodes.crossDocumentFlight, facts)
214
214
  };
215
215
  }
216
+ function classifyVisitedResponseCacheCandidate(facts) {
217
+ if (facts.candidate === "missing") return { kind: "miss" };
218
+ if (!facts.mountedSlotsMatch) return {
219
+ kind: "evict",
220
+ reason: "mountedSlotsMismatch"
221
+ };
222
+ if (facts.navigationKind === "refresh") return {
223
+ kind: "evict",
224
+ reason: "refresh"
225
+ };
226
+ if (!facts.fresh) return {
227
+ kind: "evict",
228
+ reason: "stale"
229
+ };
230
+ return { kind: "reuse" };
231
+ }
232
+ function createNavigationReuseTrace(code, facts, fields = {}) {
233
+ return createNavigationTrace(code, {
234
+ eventKind: facts.navigationKind,
235
+ targetHref: facts.targetHref,
236
+ ...fields
237
+ });
238
+ }
239
+ function createFreshFetchDecision(facts, reason) {
240
+ return {
241
+ kind: "fetchFresh",
242
+ reason,
243
+ trace: createNavigationReuseTrace(NavigationTraceReasonCodes.fetchFresh, facts, { freshFetchReason: reason })
244
+ };
245
+ }
246
+ function classifyNavigationReuse(facts) {
247
+ if (facts.navigationKind === "refresh") return createFreshFetchDecision(facts, "refresh");
248
+ if (!facts.bypassNavigationCache && facts.visitedResponse.status === "available") return {
249
+ kind: "reuseVisitedResponse",
250
+ trace: createNavigationReuseTrace(NavigationTraceReasonCodes.visitedResponseReuse, facts)
251
+ };
252
+ if (!facts.bypassNavigationCache && facts.prefetch.status === "available") return {
253
+ kind: "consumePrefetch",
254
+ trace: createNavigationReuseTrace(NavigationTraceReasonCodes.prefetchResponseReuse, facts)
255
+ };
256
+ if (facts.navigationKind === "navigate") {
257
+ if (facts.optimisticRouteShell.status === "available") return {
258
+ kind: "attemptOptimisticRouteShell",
259
+ trace: createNavigationReuseTrace(NavigationTraceReasonCodes.optimisticRouteShell, facts)
260
+ };
261
+ return createFreshFetchDecision(facts, facts.bypassNavigationCache ? "cacheBypassed" : facts.optimisticRouteShell.reason);
262
+ }
263
+ if (facts.bypassNavigationCache) return createFreshFetchDecision(facts, "cacheBypassed");
264
+ return createFreshFetchDecision(facts, "cacheMiss");
265
+ }
266
+ function classifyNavigationPrefetchProbe(facts) {
267
+ if (facts.visitedResponse.status === "available") return {
268
+ kind: "skip",
269
+ reason: "visitedResponseAvailable"
270
+ };
271
+ if (facts.navigationKind === "refresh") return {
272
+ kind: "skip",
273
+ reason: "refresh"
274
+ };
275
+ if (facts.bypassNavigationCache) return {
276
+ kind: "skip",
277
+ reason: "cacheBypassed"
278
+ };
279
+ return { kind: "probe" };
280
+ }
216
281
  function createSnapshotRouteTopology(snapshot) {
217
282
  return {
218
283
  layoutIds: snapshot.layoutIds,
@@ -680,10 +745,59 @@ function planNavigation(input) {
680
745
  }
681
746
  }
682
747
  }
748
+ function classifyServerActionResult(facts) {
749
+ if (facts.clientCompatibilityId === null) return {
750
+ kind: "proceed",
751
+ trace: createNavigationTrace(NavigationTraceReasonCodes.proceedToCommit, {})
752
+ };
753
+ if (!facts.isRscContentType) return {
754
+ kind: "proceed",
755
+ trace: createNavigationTrace(NavigationTraceReasonCodes.proceedToCommit, {})
756
+ };
757
+ if (resolveRscCompatibilityNavigationDecision({
758
+ clientCompatibilityId: facts.clientCompatibilityId,
759
+ currentHref: facts.currentHref,
760
+ origin: facts.origin,
761
+ responseCompatibilityId: facts.compatibilityIdHeader,
762
+ responseUrl: facts.responseUrl
763
+ }).kind === "compatible") return {
764
+ kind: "proceed",
765
+ trace: createNavigationTrace(NavigationTraceReasonCodes.proceedToCommit, {})
766
+ };
767
+ if (facts.actionRedirectHref !== null) return {
768
+ kind: "hardNavigate",
769
+ url: facts.actionRedirectHref,
770
+ historyMode: facts.actionRedirectType === "push" ? "assign" : "replace",
771
+ clearClientNavigationCaches: true,
772
+ reason: "serverActionRedirectCompatibilityMismatch",
773
+ trace: createNavigationTrace(NavigationTraceReasonCodes.serverActionRedirectCompatibilityMismatch, { targetHref: facts.actionRedirectHref })
774
+ };
775
+ const targetUrl = facts.currentHref;
776
+ return {
777
+ kind: "hardNavigate",
778
+ url: targetUrl,
779
+ clearClientNavigationCaches: false,
780
+ reason: "serverActionRscCompatibilityMismatch",
781
+ trace: createNavigationTrace(NavigationTraceReasonCodes.serverActionRscCompatibilityMismatch, { targetHref: targetUrl })
782
+ };
783
+ }
784
+ function classifyRscNavigationError(facts) {
785
+ return {
786
+ kind: "hardNavigate",
787
+ url: facts.currentHref,
788
+ reason: "rscNavigationError",
789
+ trace: createNavigationTrace(NavigationTraceReasonCodes.rscNavigationError, { targetHref: facts.currentHref })
790
+ };
791
+ }
683
792
  const navigationPlanner = {
684
793
  classifyEarlyNavigationIntent,
794
+ classifyNavigationPrefetchProbe,
795
+ classifyNavigationReuse,
685
796
  classifyRscFetchResult,
797
+ classifyRscNavigationError,
686
798
  classifyRootBoundaryTransition,
799
+ classifyServerActionResult,
800
+ classifyVisitedResponseCacheCandidate,
687
801
  plan: planNavigation,
688
802
  resolveCurrentRootBoundaryElementPersistence,
689
803
  resolveMountedParallelSlotPersistence,
@@ -5,6 +5,7 @@ declare const NavigationTraceReasonCodes: {
5
5
  cacheProofRejected: "NC_CACHE_REJECT";
6
6
  commitCurrent: "NC_COMMIT";
7
7
  crossDocumentFlight: "NC_CROSS_DOC_FLIGHT";
8
+ fetchFresh: "NC_FETCH_FRESH";
8
9
  invalidRscPayload: "NC_RSC_INVALID";
9
10
  interceptedCommitCurrent: "NC_INTERCEPT_COMMIT";
10
11
  interceptedRejectedIncompatibleRoot: "NC_INTERCEPT_REJECT_ROOT";
@@ -13,7 +14,9 @@ declare const NavigationTraceReasonCodes: {
13
14
  interceptedRejectedTargetMismatch: "NC_INTERCEPT_REJECT_TARGET";
14
15
  interceptedRejectedUndeclaredTopology: "NC_INTERCEPT_REJECT_GRAPH";
15
16
  interceptedRejectedUnknownSource: "NC_INTERCEPT_REJECT_SOURCE";
17
+ optimisticRouteShell: "NC_OPTIMISTIC_SHELL";
16
18
  prefetchOnly: "NC_PREFETCH_ONLY";
19
+ prefetchResponseReuse: "NC_PREFETCH_REUSE";
17
20
  proceedToCommit: "NC_RSC_PROCEED";
18
21
  redirectFollow: "NC_RSC_REDIRECT_FOLLOW";
19
22
  redirectTerminalDepth: "NC_RSC_REDIRECT_DEPTH";
@@ -22,10 +25,14 @@ declare const NavigationTraceReasonCodes: {
22
25
  rootBoundaryChanged: "NC_ROOT";
23
26
  rootBoundaryUnknown: "NC_ROOT_UNKNOWN";
24
27
  rscCompatibilityMismatch: "NC_RSC_COMPAT_MISMATCH";
28
+ rscNavigationError: "NC_RSC_NAV_ERROR";
25
29
  sameDocumentScroll: "NC_SAME_DOC_SCROLL";
26
30
  samePageSearch: "NC_SAME_PAGE_SEARCH";
31
+ serverActionRedirectCompatibilityMismatch: "NC_SA_REDIRECT_COMPAT";
32
+ serverActionRscCompatibilityMismatch: "NC_SA_RSC_COMPAT";
27
33
  staleOperation: "NC_STALE";
28
34
  streamedRedirectLoop: "NC_RSC_STREAMED_REDIRECT_LOOP";
35
+ visitedResponseReuse: "NC_VISITED_REUSE";
29
36
  };
30
37
  declare const NavigationTraceTransactionCodes: {
31
38
  hardNavigate: "NT_HARD_NAVIGATE";
@@ -35,7 +42,7 @@ declare const NavigationTraceTransactionCodes: {
35
42
  type NavigationTraceReasonCode = (typeof NavigationTraceReasonCodes)[keyof typeof NavigationTraceReasonCodes];
36
43
  type NavigationTraceTransactionCode = (typeof NavigationTraceTransactionCodes)[keyof typeof NavigationTraceTransactionCodes];
37
44
  type NavigationTraceCode = NavigationTraceReasonCode | NavigationTraceTransactionCode;
38
- type NavigationTraceFieldName = "activeNavigationId" | "cacheProofCode" | "cacheProofMode" | "cacheProofReuseClass" | "cacheProofScope" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "fetchResultSource" | "operationLane" | "pendingOperationId" | "redirectDepth" | "redirectSignal" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
45
+ type NavigationTraceFieldName = "activeNavigationId" | "cacheProofCode" | "cacheProofMode" | "cacheProofReuseClass" | "cacheProofScope" | "currentRootLayoutTreePath" | "currentVisibleCommitVersion" | "nextRootLayoutTreePath" | "eventKind" | "fetchResultSource" | "freshFetchReason" | "operationLane" | "pendingOperationId" | "redirectDepth" | "redirectSignal" | "startedVisibleCommitVersion" | "startedNavigationId" | "targetHref" | "traverseDirection";
39
46
  type NavigationTraceFieldValue = string | number | boolean | null;
40
47
  type NavigationTraceFields = Readonly<Partial<Record<NavigationTraceFieldName, NavigationTraceFieldValue>>>;
41
48
  type NavigationTraceEntry = Readonly<{
@@ -4,6 +4,7 @@ const NavigationTraceReasonCodes = {
4
4
  cacheProofRejected: "NC_CACHE_REJECT",
5
5
  commitCurrent: "NC_COMMIT",
6
6
  crossDocumentFlight: "NC_CROSS_DOC_FLIGHT",
7
+ fetchFresh: "NC_FETCH_FRESH",
7
8
  invalidRscPayload: "NC_RSC_INVALID",
8
9
  interceptedCommitCurrent: "NC_INTERCEPT_COMMIT",
9
10
  interceptedRejectedIncompatibleRoot: "NC_INTERCEPT_REJECT_ROOT",
@@ -12,7 +13,9 @@ const NavigationTraceReasonCodes = {
12
13
  interceptedRejectedTargetMismatch: "NC_INTERCEPT_REJECT_TARGET",
13
14
  interceptedRejectedUndeclaredTopology: "NC_INTERCEPT_REJECT_GRAPH",
14
15
  interceptedRejectedUnknownSource: "NC_INTERCEPT_REJECT_SOURCE",
16
+ optimisticRouteShell: "NC_OPTIMISTIC_SHELL",
15
17
  prefetchOnly: "NC_PREFETCH_ONLY",
18
+ prefetchResponseReuse: "NC_PREFETCH_REUSE",
16
19
  proceedToCommit: "NC_RSC_PROCEED",
17
20
  redirectFollow: "NC_RSC_REDIRECT_FOLLOW",
18
21
  redirectTerminalDepth: "NC_RSC_REDIRECT_DEPTH",
@@ -21,10 +24,14 @@ const NavigationTraceReasonCodes = {
21
24
  rootBoundaryChanged: "NC_ROOT",
22
25
  rootBoundaryUnknown: "NC_ROOT_UNKNOWN",
23
26
  rscCompatibilityMismatch: "NC_RSC_COMPAT_MISMATCH",
27
+ rscNavigationError: "NC_RSC_NAV_ERROR",
24
28
  sameDocumentScroll: "NC_SAME_DOC_SCROLL",
25
29
  samePageSearch: "NC_SAME_PAGE_SEARCH",
30
+ serverActionRedirectCompatibilityMismatch: "NC_SA_REDIRECT_COMPAT",
31
+ serverActionRscCompatibilityMismatch: "NC_SA_RSC_COMPAT",
26
32
  staleOperation: "NC_STALE",
27
- streamedRedirectLoop: "NC_RSC_STREAMED_REDIRECT_LOOP"
33
+ streamedRedirectLoop: "NC_RSC_STREAMED_REDIRECT_LOOP",
34
+ visitedResponseReuse: "NC_VISITED_REUSE"
28
35
  };
29
36
  const NavigationTraceTransactionCodes = {
30
37
  hardNavigate: "NT_HARD_NAVIGATE",
@@ -1,3 +1,4 @@
1
+ import { NextI18nConfig } from "../config/next-config.js";
1
2
  import { Route } from "../routing/pages-router.js";
2
3
  import { ExecutionContextLike } from "../shims/request-context.js";
3
4
  import { PagesReqResRequest, PagesReqResResponse, PagesRequestQuery } from "./pages-node-compat.js";
@@ -71,6 +72,11 @@ type HandlePagesApiRouteOptions = {
71
72
  reportRequestError?: (error: Error, routePattern: string) => void | Promise<void>;
72
73
  request: Request;
73
74
  url: string;
75
+ nextConfig?: {
76
+ basePath?: string;
77
+ i18n?: NextI18nConfig | null;
78
+ trailingSlash?: boolean;
79
+ };
74
80
  };
75
81
  declare function handlePagesApiRoute(options: HandlePagesApiRouteOptions): Promise<Response>;
76
82
  //#endregion
@@ -2,7 +2,8 @@ import "./server-globals.js";
2
2
  import { runWithExecutionContext } from "../shims/request-context.js";
3
3
  import { NextRequest } from "../shims/server.js";
4
4
  import { internalServerErrorResponse } from "./http-error-responses.js";
5
- import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
5
+ import { cloneRequestWithUrl } from "./request-pipeline.js";
6
+ import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
6
7
  import { PagesBodyParseError } from "./pages-media-type.js";
7
8
  import { isEdgeApiRuntime } from "./edge-api-runtime.js";
8
9
  import { resolveBodyParserConfig } from "./pages-body-parser-config.js";
@@ -14,6 +15,12 @@ function resolveModuleRuntime(module) {
14
15
  function buildPagesApiQuery(url, params) {
15
16
  return mergeRouteParamsIntoQuery(parseQueryString(url), params);
16
17
  }
18
+ function createEdgeApiRequest(request, url, params) {
19
+ const resolvedUrl = new URL(request.url);
20
+ resolvedUrl.search = urlQueryToSearchParams(buildPagesApiQuery(url, params)).toString();
21
+ const resolvedUrlString = resolvedUrl.toString();
22
+ return resolvedUrlString === request.url ? request : cloneRequestWithUrl(request, resolvedUrlString);
23
+ }
17
24
  function isEdgeApiRouteModule(module) {
18
25
  return typeof module.default === "function" && isEdgeApiRuntime(resolveModuleRuntime(module));
19
26
  }
@@ -29,7 +36,11 @@ async function _handlePagesApiRoute(options) {
29
36
  const { route, params } = options.match;
30
37
  try {
31
38
  if (isEdgeApiRouteModule(route.module)) {
32
- const nextRequest = new NextRequest(options.request);
39
+ const nextRequest = new NextRequest(createEdgeApiRequest(options.request, options.url, params), options.nextConfig ? { nextConfig: {
40
+ basePath: options.nextConfig.basePath,
41
+ i18n: options.nextConfig.i18n ?? void 0,
42
+ trailingSlash: options.nextConfig.trailingSlash
43
+ } } : void 0);
33
44
  const response = await route.module.default(nextRequest);
34
45
  if (response instanceof Response) return response;
35
46
  throw new Error("Edge API route did not return a Response");