vinext 0.1.2 → 0.1.4

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 (243) hide show
  1. package/dist/build/client-build-config.d.ts +11 -2
  2. package/dist/build/client-build-config.js +17 -6
  3. package/dist/build/prerender.d.ts +9 -1
  4. package/dist/build/prerender.js +42 -12
  5. package/dist/build/run-prerender.d.ts +10 -2
  6. package/dist/build/run-prerender.js +15 -1
  7. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  8. package/dist/client/app-nav-failure-handler.js +44 -0
  9. package/dist/client/pages-router-link-navigation.d.ts +33 -7
  10. package/dist/client/pages-router-link-navigation.js +32 -2
  11. package/dist/client/vinext-next-data.d.ts +18 -1
  12. package/dist/client/vinext-next-data.js +2 -0
  13. package/dist/client/window-next.d.ts +2 -1
  14. package/dist/client/window-next.js +12 -1
  15. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  16. package/dist/config/config-matchers.d.ts +11 -1
  17. package/dist/config/config-matchers.js +87 -16
  18. package/dist/config/next-config.d.ts +46 -4
  19. package/dist/config/next-config.js +147 -48
  20. package/dist/config/tsconfig-paths.js +14 -1
  21. package/dist/deploy.d.ts +30 -11
  22. package/dist/deploy.js +200 -112
  23. package/dist/entries/app-browser-entry.d.ts +9 -3
  24. package/dist/entries/app-browser-entry.js +21 -3
  25. package/dist/entries/app-rsc-entry.d.ts +2 -0
  26. package/dist/entries/app-rsc-entry.js +65 -5
  27. package/dist/entries/app-rsc-manifest.js +2 -0
  28. package/dist/entries/app-ssr-entry.js +1 -1
  29. package/dist/entries/pages-client-entry.js +66 -20
  30. package/dist/entries/pages-server-entry.js +47 -31
  31. package/dist/index.js +417 -102
  32. package/dist/plugins/dynamic-preload-metadata.js +2 -4
  33. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  34. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  35. package/dist/plugins/fonts.js +5 -4
  36. package/dist/plugins/optimize-imports.d.ts +2 -1
  37. package/dist/plugins/optimize-imports.js +11 -9
  38. package/dist/plugins/postcss.js +7 -7
  39. package/dist/plugins/strip-server-exports.d.ts +9 -7
  40. package/dist/plugins/strip-server-exports.js +493 -46
  41. package/dist/plugins/typeof-window.d.ts +14 -0
  42. package/dist/plugins/typeof-window.js +150 -0
  43. package/dist/routing/app-route-graph.d.ts +2 -1
  44. package/dist/routing/app-route-graph.js +46 -16
  45. package/dist/routing/file-matcher.d.ts +10 -1
  46. package/dist/routing/file-matcher.js +22 -1
  47. package/dist/routing/pages-router.js +3 -3
  48. package/dist/routing/utils.d.ts +35 -6
  49. package/dist/routing/utils.js +59 -7
  50. package/dist/server/api-handler.d.ts +6 -1
  51. package/dist/server/api-handler.js +21 -15
  52. package/dist/server/app-browser-action-result.d.ts +19 -6
  53. package/dist/server/app-browser-action-result.js +20 -11
  54. package/dist/server/app-browser-entry.js +175 -91
  55. package/dist/server/app-browser-error.d.ts +10 -6
  56. package/dist/server/app-browser-error.js +43 -8
  57. package/dist/server/app-browser-hydration.d.ts +2 -0
  58. package/dist/server/app-browser-hydration.js +1 -0
  59. package/dist/server/app-browser-navigation-controller.d.ts +5 -3
  60. package/dist/server/app-browser-navigation-controller.js +23 -2
  61. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  62. package/dist/server/app-browser-server-action-navigation.js +9 -0
  63. package/dist/server/app-browser-state.d.ts +1 -1
  64. package/dist/server/app-browser-state.js +19 -11
  65. package/dist/server/app-browser-stream.js +86 -43
  66. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  67. package/dist/server/app-elements-wire.d.ts +6 -1
  68. package/dist/server/app-elements-wire.js +14 -4
  69. package/dist/server/app-elements.d.ts +2 -2
  70. package/dist/server/app-elements.js +2 -2
  71. package/dist/server/app-fallback-renderer.d.ts +1 -0
  72. package/dist/server/app-fallback-renderer.js +3 -1
  73. package/dist/server/app-optimistic-routing.js +2 -2
  74. package/dist/server/app-page-boundary-render.d.ts +1 -0
  75. package/dist/server/app-page-boundary-render.js +27 -14
  76. package/dist/server/app-page-cache-render.d.ts +53 -0
  77. package/dist/server/app-page-cache-render.js +91 -0
  78. package/dist/server/app-page-cache.d.ts +16 -2
  79. package/dist/server/app-page-cache.js +62 -1
  80. package/dist/server/app-page-dispatch.d.ts +26 -0
  81. package/dist/server/app-page-dispatch.js +149 -92
  82. package/dist/server/app-page-element-builder.d.ts +1 -0
  83. package/dist/server/app-page-element-builder.js +5 -2
  84. package/dist/server/app-page-execution.d.ts +6 -1
  85. package/dist/server/app-page-execution.js +21 -1
  86. package/dist/server/app-page-probe.d.ts +1 -0
  87. package/dist/server/app-page-probe.js +4 -0
  88. package/dist/server/app-page-render-observation.d.ts +3 -1
  89. package/dist/server/app-page-render-observation.js +17 -1
  90. package/dist/server/app-page-render.d.ts +12 -1
  91. package/dist/server/app-page-render.js +42 -4
  92. package/dist/server/app-page-request.d.ts +2 -0
  93. package/dist/server/app-page-request.js +2 -1
  94. package/dist/server/app-page-route-wiring.d.ts +3 -1
  95. package/dist/server/app-page-route-wiring.js +14 -5
  96. package/dist/server/app-page-stream.d.ts +15 -3
  97. package/dist/server/app-page-stream.js +11 -5
  98. package/dist/server/app-pages-bridge.d.ts +23 -1
  99. package/dist/server/app-pages-bridge.js +26 -17
  100. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  101. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  102. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  103. package/dist/server/app-ppr-fallback-shell.js +8 -1
  104. package/dist/server/app-route-handler-dispatch.js +9 -2
  105. package/dist/server/app-route-handler-policy.d.ts +1 -0
  106. package/dist/server/app-router-entry.js +5 -0
  107. package/dist/server/app-rsc-cache-busting.js +2 -0
  108. package/dist/server/app-rsc-handler.d.ts +28 -0
  109. package/dist/server/app-rsc-handler.js +195 -59
  110. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  111. package/dist/server/app-rsc-route-matching.js +8 -2
  112. package/dist/server/app-segment-config.d.ts +9 -1
  113. package/dist/server/app-segment-config.js +12 -3
  114. package/dist/server/app-server-action-execution.d.ts +1 -0
  115. package/dist/server/app-server-action-execution.js +47 -15
  116. package/dist/server/app-ssr-entry.d.ts +2 -0
  117. package/dist/server/app-ssr-entry.js +84 -39
  118. package/dist/server/before-interactive-head.d.ts +17 -0
  119. package/dist/server/before-interactive-head.js +35 -0
  120. package/dist/server/cache-control.js +4 -0
  121. package/dist/server/csp.js +1 -4
  122. package/dist/server/dev-server.d.ts +2 -2
  123. package/dist/server/dev-server.js +321 -83
  124. package/dist/server/hybrid-route-priority.d.ts +22 -0
  125. package/dist/server/hybrid-route-priority.js +33 -0
  126. package/dist/server/image-optimization.d.ts +18 -9
  127. package/dist/server/image-optimization.js +37 -23
  128. package/dist/server/implicit-tags.d.ts +2 -1
  129. package/dist/server/implicit-tags.js +4 -1
  130. package/dist/server/middleware-matcher.js +12 -3
  131. package/dist/server/middleware-runtime.d.ts +3 -4
  132. package/dist/server/middleware-runtime.js +2 -0
  133. package/dist/server/navigation-planner.d.ts +135 -41
  134. package/dist/server/navigation-planner.js +138 -0
  135. package/dist/server/navigation-trace.d.ts +9 -1
  136. package/dist/server/navigation-trace.js +9 -1
  137. package/dist/server/operation-token.d.ts +40 -0
  138. package/dist/server/operation-token.js +85 -0
  139. package/dist/server/pages-api-route.d.ts +6 -0
  140. package/dist/server/pages-api-route.js +13 -2
  141. package/dist/server/pages-asset-tags.d.ts +2 -1
  142. package/dist/server/pages-asset-tags.js +6 -2
  143. package/dist/server/pages-data-route.d.ts +9 -2
  144. package/dist/server/pages-data-route.js +18 -6
  145. package/dist/server/pages-dev-module-url.d.ts +4 -0
  146. package/dist/server/pages-dev-module-url.js +15 -0
  147. package/dist/server/pages-document-initial-props.d.ts +4 -15
  148. package/dist/server/pages-document-initial-props.js +27 -56
  149. package/dist/server/pages-get-initial-props.d.ts +54 -4
  150. package/dist/server/pages-get-initial-props.js +43 -1
  151. package/dist/server/pages-i18n.js +2 -2
  152. package/dist/server/pages-node-compat.js +2 -2
  153. package/dist/server/pages-page-data.d.ts +11 -2
  154. package/dist/server/pages-page-data.js +207 -34
  155. package/dist/server/pages-page-handler.d.ts +4 -2
  156. package/dist/server/pages-page-handler.js +62 -23
  157. package/dist/server/pages-page-response.d.ts +4 -1
  158. package/dist/server/pages-page-response.js +11 -8
  159. package/dist/server/pages-readiness.js +1 -1
  160. package/dist/server/pages-request-pipeline.d.ts +8 -7
  161. package/dist/server/pages-request-pipeline.js +126 -47
  162. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  163. package/dist/server/pregenerated-concrete-paths.js +2 -19
  164. package/dist/server/prerender-manifest.d.ts +33 -0
  165. package/dist/server/prerender-manifest.js +54 -0
  166. package/dist/server/prerender-route-params.d.ts +1 -2
  167. package/dist/server/prod-server.d.ts +3 -1
  168. package/dist/server/prod-server.js +50 -13
  169. package/dist/server/request-pipeline.d.ts +3 -15
  170. package/dist/server/request-pipeline.js +58 -47
  171. package/dist/server/rsc-stream-hints.d.ts +5 -1
  172. package/dist/server/rsc-stream-hints.js +6 -1
  173. package/dist/server/seed-cache.js +10 -18
  174. package/dist/server/static-file-cache.js +16 -4
  175. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  176. package/dist/shims/app-router-scroll-state.js +14 -2
  177. package/dist/shims/app-router-scroll.d.ts +3 -0
  178. package/dist/shims/app-router-scroll.js +28 -18
  179. package/dist/shims/before-interactive-context.d.ts +14 -3
  180. package/dist/shims/cache-runtime.js +3 -2
  181. package/dist/shims/cache.d.ts +1 -0
  182. package/dist/shims/cache.js +1 -1
  183. package/dist/shims/cdn-cache.d.ts +5 -5
  184. package/dist/shims/document.d.ts +15 -20
  185. package/dist/shims/document.js +5 -8
  186. package/dist/shims/dynamic-preload-chunks.js +6 -4
  187. package/dist/shims/error-boundary.d.ts +2 -0
  188. package/dist/shims/error-boundary.js +7 -0
  189. package/dist/shims/error.js +3 -2
  190. package/dist/shims/error.react-server.d.ts +9 -0
  191. package/dist/shims/error.react-server.js +6 -0
  192. package/dist/shims/fetch-cache.d.ts +3 -1
  193. package/dist/shims/fetch-cache.js +45 -20
  194. package/dist/shims/hash-scroll.js +6 -1
  195. package/dist/shims/headers.js +29 -4
  196. package/dist/shims/image.js +9 -2
  197. package/dist/shims/internal/als-registry.js +28 -1
  198. package/dist/shims/internal/app-route-detection.js +8 -17
  199. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  200. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  201. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  202. package/dist/shims/internal/navigation-untracked.js +55 -0
  203. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
  204. package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
  205. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  206. package/dist/shims/internal/pages-data-target.js +17 -8
  207. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  208. package/dist/shims/internal/pages-router-accessor.js +13 -0
  209. package/dist/shims/internal/router-context.d.ts +2 -1
  210. package/dist/shims/internal/router-context.js +3 -1
  211. package/dist/shims/link.js +47 -19
  212. package/dist/shims/metadata.js +4 -4
  213. package/dist/shims/navigation.d.ts +8 -2
  214. package/dist/shims/navigation.js +63 -31
  215. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  216. package/dist/shims/ppr-fallback-shell.js +28 -7
  217. package/dist/shims/router.d.ts +18 -3
  218. package/dist/shims/router.js +512 -142
  219. package/dist/shims/script.js +8 -4
  220. package/dist/shims/server.d.ts +16 -1
  221. package/dist/shims/server.js +44 -12
  222. package/dist/shims/unified-request-context.js +1 -0
  223. package/dist/utils/built-asset-url.d.ts +4 -0
  224. package/dist/utils/built-asset-url.js +11 -0
  225. package/dist/utils/commonjs-loader.d.ts +16 -0
  226. package/dist/utils/commonjs-loader.js +100 -0
  227. package/dist/utils/deployment-id.d.ts +8 -0
  228. package/dist/utils/deployment-id.js +22 -0
  229. package/dist/utils/has-trailing-comma.d.ts +24 -0
  230. package/dist/utils/has-trailing-comma.js +62 -0
  231. package/dist/utils/html-limited-bots.d.ts +18 -1
  232. package/dist/utils/html-limited-bots.js +23 -1
  233. package/dist/utils/parse-cookie.d.ts +13 -0
  234. package/dist/utils/parse-cookie.js +52 -0
  235. package/dist/utils/path.d.ts +7 -1
  236. package/dist/utils/path.js +9 -1
  237. package/dist/utils/text-stream.d.ts +1 -1
  238. package/dist/utils/text-stream.js +2 -2
  239. package/dist/utils/vite-version.d.ts +12 -1
  240. package/dist/utils/vite-version.js +9 -1
  241. package/package.json +2 -2
  242. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  243. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -0,0 +1,22 @@
1
+ //#region src/server/hybrid-route-priority.d.ts
2
+ type HybridRoutePriorityRoute = {
3
+ isDynamic: boolean;
4
+ pattern: string;
5
+ sourcePath?: string | null;
6
+ };
7
+ declare function validateHybridRouteConflicts(pagesRoutes: readonly HybridRoutePriorityRoute[], appRoutes: readonly HybridRoutePriorityRoute[]): void;
8
+ /**
9
+ * Return whether a matched Pages Router route should own the request instead
10
+ * of a matched App Router route.
11
+ *
12
+ * Next.js registers Pages providers before App providers, then sorts all
13
+ * dynamic route pathnames together in DefaultRouteMatcherManager. Vinext keeps
14
+ * separate route tries for each router, so the hybrid boundary needs to apply
15
+ * that same cross-router ordering after both routers have produced their best
16
+ * local match. The decision itself lives in
17
+ * `routing/utils.ts#compareHybridRoutePatterns` so the server and client
18
+ * always reach the same answer.
19
+ */
20
+ declare function pagesRouteHasPriorityOverAppRoute(pagesRoute: HybridRoutePriorityRoute, appRoute: HybridRoutePriorityRoute | null): boolean;
21
+ //#endregion
22
+ export { HybridRoutePriorityRoute, pagesRouteHasPriorityOverAppRoute, validateHybridRouteConflicts };
@@ -0,0 +1,33 @@
1
+ import { compareHybridRoutePatterns } from "../routing/utils.js";
2
+ import { validateRoutePatterns } from "../routing/route-validation.js";
3
+ //#region src/server/hybrid-route-priority.ts
4
+ function validateHybridRouteConflicts(pagesRoutes, appRoutes) {
5
+ const pagesByPattern = new Map(pagesRoutes.map((route) => [route.pattern, route]));
6
+ const conflicts = appRoutes.flatMap((appRoute) => {
7
+ const pagesRoute = pagesByPattern.get(appRoute.pattern);
8
+ return pagesRoute === void 0 ? [] : [[pagesRoute, appRoute]];
9
+ });
10
+ if (conflicts.length > 0) {
11
+ const message = `Conflicting app and page file${conflicts.length === 1 ? " was" : "s were"} found, please remove the conflicting files to continue:`;
12
+ throw new Error(`${message}\n${conflicts.map(([pagesRoute, appRoute]) => ` "${pagesRoute.sourcePath ?? pagesRoute.pattern}" - "${appRoute.sourcePath ?? appRoute.pattern}"`).join("\n")}`);
13
+ }
14
+ validateRoutePatterns([...pagesRoutes.map((route) => route.pattern), ...appRoutes.map((route) => route.pattern)]);
15
+ }
16
+ /**
17
+ * Return whether a matched Pages Router route should own the request instead
18
+ * of a matched App Router route.
19
+ *
20
+ * Next.js registers Pages providers before App providers, then sorts all
21
+ * dynamic route pathnames together in DefaultRouteMatcherManager. Vinext keeps
22
+ * separate route tries for each router, so the hybrid boundary needs to apply
23
+ * that same cross-router ordering after both routers have produced their best
24
+ * local match. The decision itself lives in
25
+ * `routing/utils.ts#compareHybridRoutePatterns` so the server and client
26
+ * always reach the same answer.
27
+ */
28
+ function pagesRouteHasPriorityOverAppRoute(pagesRoute, appRoute) {
29
+ if (appRoute === null) return true;
30
+ return compareHybridRoutePatterns(pagesRoute.pattern, pagesRoute.isDynamic, appRoute.pattern, appRoute.isDynamic) === "pages";
31
+ }
32
+ //#endregion
33
+ export { pagesRouteHasPriorityOverAppRoute, validateHybridRouteConflicts };
@@ -33,7 +33,15 @@ declare function isImageOptimizationPath(pathname: string): boolean;
33
33
  * Controls SVG handling and security headers for the image endpoint.
34
34
  */
35
35
  type ImageConfig = {
36
- /** Allow SVG through the image optimization endpoint. Default: false. */dangerouslyAllowSVG?: boolean;
36
+ /** Allowed device widths. Defaults to Next.js device sizes. */deviceSizes?: number[]; /** Allowed fixed-image widths. Defaults to Next.js image sizes. */
37
+ imageSizes?: number[];
38
+ /**
39
+ * Allowed output qualities. When unset, any quality from 1-100 is permitted
40
+ * (matches Next.js: an unset `images.qualities` is not restricted to a single
41
+ * value). When set, only the listed qualities are accepted.
42
+ */
43
+ qualities?: number[]; /** Allow SVG through the image optimization endpoint. Default: false. */
44
+ dangerouslyAllowSVG?: boolean;
37
45
  /**
38
46
  * Allow image optimization for hostnames that resolve to private IP addresses.
39
47
  * Default: false.
@@ -54,18 +62,19 @@ type ImageConfig = {
54
62
  */
55
63
  declare const DEFAULT_DEVICE_SIZES: number[];
56
64
  declare const DEFAULT_IMAGE_SIZES: number[];
65
+ type ParseImageParamsOptions = {
66
+ isDev?: boolean;
67
+ };
68
+ declare function resolveDevImageRedirect(requestUrl: URL, allowedWidths?: number[], allowedQualities?: number[], options?: ParseImageParamsOptions): string | null;
57
69
  /**
58
70
  * Parse and validate image optimization query parameters.
59
71
  * Returns null if the request is malformed.
60
72
  *
61
- * When `allowedWidths` is provided, the width must be 0 (no resize) or
62
- * exactly match one of the allowed values. This matches Next.js behavior
63
- * where only configured deviceSizes and imageSizes are accepted.
64
- *
65
- * When `allowedWidths` is not provided, any width from 0 to ABSOLUTE_MAX_WIDTH
66
- * 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
67
76
  */
68
- declare function parseImageParams(url: URL, allowedWidths?: number[]): {
77
+ declare function parseImageParams(url: URL, allowedWidths?: number[], allowedQualities?: number[], options?: ParseImageParamsOptions): {
69
78
  imageUrl: string;
70
79
  width: number;
71
80
  quality: number;
@@ -113,4 +122,4 @@ type ImageHandlers = {
113
122
  */
114
123
  declare function handleImageOptimization(request: Request, handlers: ImageHandlers, allowedWidths?: number[], imageConfig?: ImageConfig): Promise<Response>;
115
124
  //#endregion
116
- export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, ImageConfig, ImageHandlers, VINEXT_IMAGE_OPTIMIZATION_PATH, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams };
125
+ export { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_CACHE_CONTROL, IMAGE_CONTENT_SECURITY_POLICY, IMAGE_OPTIMIZATION_PATH, ImageConfig, ImageHandlers, ParseImageParamsOptions, VINEXT_IMAGE_OPTIMIZATION_PATH, handleImageOptimization, isImageOptimizationPath, isSafeImageContentType, negotiateImageFormat, parseImageParams, resolveDevImageRedirect };
@@ -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 };
@@ -1,5 +1,5 @@
1
1
  import { removeTrailingSlash } from "../utils/base-path.js";
2
- import { checkHasConditions, requestContextFromRequest, safeRegExp } from "../config/config-matchers.js";
2
+ import { checkHasConditions, isSafeRegex, requestContextFromRequest, safeRegExp } from "../config/config-matchers.js";
3
3
  //#region src/server/middleware-matcher.ts
4
4
  const EMPTY_MIDDLEWARE_REQUEST_CONTEXT = {
5
5
  headers: new Headers(),
@@ -7,6 +7,7 @@ const EMPTY_MIDDLEWARE_REQUEST_CONTEXT = {
7
7
  query: new URLSearchParams(),
8
8
  host: ""
9
9
  };
10
+ const UNSAFE_MATCHER_PATTERN = Symbol("unsafe matcher pattern");
10
11
  const _mwPatternCache = /* @__PURE__ */ new Map();
11
12
  function matchesMiddleware(pathname, matcher, request, i18nConfig) {
12
13
  if (!matcher) return true;
@@ -55,6 +56,7 @@ function matchPattern(pathname, pattern) {
55
56
  cached = compileMatcherPattern(pattern);
56
57
  _mwPatternCache.set(pattern, cached);
57
58
  }
59
+ if (cached === UNSAFE_MATCHER_PATTERN) return true;
58
60
  if (cached === null) return pathname === pattern;
59
61
  return cached.test(pathname);
60
62
  }
@@ -74,7 +76,7 @@ function extractConstraint(str, re) {
74
76
  }
75
77
  function compileMatcherPattern(pattern) {
76
78
  const hasConstraints = /:[\w-]+[*+]?\(/.test(pattern);
77
- if (!hasConstraints && (pattern.includes("(") || pattern.includes("\\"))) return safeRegExp("^" + pattern + "$");
79
+ if (!hasConstraints && (pattern.includes("(") || pattern.includes("\\"))) return compileMatcherRegExp("^" + pattern + "$", pattern);
78
80
  let regexStr = "";
79
81
  const tokenRe = /\/:([\w-]+)\*|\/:([\w-]+)\+|:([\w-]+)|[.]|[^/:.]+|./g;
80
82
  let tok;
@@ -94,7 +96,14 @@ function compileMatcherPattern(pattern) {
94
96
  else regexStr += group;
95
97
  } else if (tok[0] === ".") regexStr += "\\.";
96
98
  else regexStr += tok[0];
97
- return safeRegExp("^" + regexStr + "$");
99
+ return compileMatcherRegExp("^" + regexStr + "$", pattern);
100
+ }
101
+ function compileMatcherRegExp(regexPattern, sourcePattern) {
102
+ if (!isSafeRegex(regexPattern)) {
103
+ console.warn(`[vinext] Rejecting potentially unsafe middleware matcher (ReDoS risk): ${sourcePattern}\n Middleware will run for all paths to avoid bypassing request guards.\n Simplify the matcher to avoid nested repetition.`);
104
+ return UNSAFE_MATCHER_PATTERN;
105
+ }
106
+ return safeRegExp(regexPattern);
98
107
  }
99
108
  //#endregion
100
109
  export { matchPattern, matchesMiddleware };
@@ -35,10 +35,9 @@ type ExecuteMiddlewareOptions = {
35
35
  i18nConfig?: NextI18nConfig | null;
36
36
  includeErrorDetails?: boolean;
37
37
  /**
38
- * Whether the incoming request was a Next.js `_next/data` fetch (carried
39
- * `x-nextjs-data: 1`). The header itself is stripped by `filterInternalHeaders`
40
- * before the middleware request is constructed, so callers must capture this
41
- * flag from the raw incoming headers and forward it explicitly.
38
+ * Whether the incoming request was recognized as a Next.js `_next/data`
39
+ * fetch. Internal headers are stripped before middleware runs, so adapters
40
+ * must derive and forward this from trusted URL normalization.
42
41
  */
43
42
  isDataRequest?: boolean;
44
43
  isProxy: boolean;
@@ -142,6 +142,8 @@ async function executeMiddleware(options) {
142
142
  response: internalServerErrorResponse(options.includeErrorDetails ? "Middleware Error: " + (e instanceof Error ? e.message : String(e)) : "Internal Server Error"),
143
143
  waitUntilPromises
144
144
  };
145
+ } finally {
146
+ if (process.env.NODE_ENV !== "development" && nextRequest.body) nextRequest.body.cancel().catch(() => {});
145
147
  }
146
148
  const waitUntilPromises = drainFetchEvent(fetchEvent);
147
149
  if (!response) return {
@@ -2,46 +2,37 @@ import { RouteManifest } from "../routing/app-route-graph.js";
2
2
  import { CacheEntryReuseDecision, CacheEntryReuseProof } from "./cache-proof.js";
3
3
  import { AppElementsSlotBinding } from "./app-elements-wire.js";
4
4
  import { NavigationTrace, NavigationTraceFields } from "./navigation-trace.js";
5
+ import { OperationLane, OperationToken } from "./operation-token.js";
5
6
 
6
7
  //#region src/server/navigation-planner.d.ts
7
- type OperationLane = "hmr" | "navigation" | "prefetch" | "refresh" | "server-action" | "traverse";
8
- type OperationToken = {
9
- operationId: number;
10
- lane: OperationLane;
11
- baseVisibleCommitVersion: number;
12
- graphVersion: string | null;
13
- deploymentVersion: string | null;
14
- targetSnapshotFingerprint: string;
15
- cacheVariantFingerprint?: string;
16
- };
17
- type RouteSnapshotV0 = {
18
- interception: InterceptionSnapshotV0 | null;
8
+ type RouteSnapshot = {
9
+ interception: InterceptionSnapshot | null;
19
10
  interceptionContext: string | null;
20
11
  routeId: string;
21
12
  layoutIds: readonly string[];
22
- mountedParallelSlots: readonly MountedParallelSlotSnapshotV0[];
13
+ mountedParallelSlots: readonly MountedParallelSlotSnapshot[];
23
14
  rootBoundaryId: string | null;
24
15
  displayUrl: string;
25
16
  matchedUrl: string;
26
- slotBindings: readonly ParallelSlotBindingSnapshotV0[];
17
+ slotBindings: readonly ParallelSlotBindingSnapshot[];
27
18
  };
28
- type InterceptionSnapshotV0 = {
19
+ type InterceptionSnapshot = {
29
20
  sourceMatchedUrl: string;
30
21
  sourceRouteId: string;
31
22
  slotId: string;
32
23
  targetMatchedUrl: string;
33
24
  targetRouteId: string;
34
25
  };
35
- type MountedParallelSlotSnapshotV0 = {
26
+ type MountedParallelSlotSnapshot = {
36
27
  slotId: string;
37
28
  ownerLayoutId: string | null;
38
29
  };
39
- type ParallelSlotBindingSnapshotV0 = AppElementsSlotBinding;
40
- type NavigationPlannerStateV0 = {
30
+ type ParallelSlotBindingSnapshot = AppElementsSlotBinding;
31
+ type NavigationPlannerState = {
41
32
  nextOperationToken: OperationToken;
42
33
  traceFields?: NavigationTraceFields;
43
34
  visibleCommitVersion: number;
44
- visibleSnapshot: RouteSnapshotV0;
35
+ visibleSnapshot: RouteSnapshot;
45
36
  };
46
37
  type RefreshScope = "visible";
47
38
  type TraverseDirection = "back" | "forward" | "unknown";
@@ -62,7 +53,7 @@ type NavigationEvent = {
62
53
  } | {
63
54
  kind: "flightResponseArrived";
64
55
  token: OperationToken;
65
- result: FlightResultV0;
56
+ result: FlightResult;
66
57
  };
67
58
  type RequestedWork = {
68
59
  kind: "flight";
@@ -82,12 +73,12 @@ type CommitProposal = {
82
73
  preserveElementIds: readonly string[];
83
74
  preservePreviousSlotIds: readonly string[];
84
75
  reason: "currentRootBoundary" | "interceptedCurrentRootBoundary" | "unprovenTopologyFallback";
85
- targetSnapshot: RouteSnapshotV0;
76
+ targetSnapshot: RouteSnapshot;
86
77
  };
87
78
  type NoCommitReason = "prefetchOnly";
88
- type HardNavigationReason = "cacheProofRejected" | "interceptionProofRejected" | "rootBoundaryChanged";
79
+ type HardNavigationReason = "cacheProofRejected" | "cacheReuseTokenRejected" | "interceptionProofRejected" | "rootBoundaryChanged";
89
80
  type RootBoundaryTransition = "currentRootBoundary" | "rootBoundaryChanged" | "rootBoundaryUnknown";
90
- type NavigationDecisionV0 = {
81
+ type NavigationDecision = {
91
82
  kind: "requestWork";
92
83
  token: OperationToken;
93
84
  work: RequestedWork;
@@ -109,13 +100,13 @@ type NavigationDecisionV0 = {
109
100
  reason: HardNavigationReason;
110
101
  trace: NavigationTrace;
111
102
  };
112
- type FlightResultV0 = {
103
+ type FlightResult = {
113
104
  cacheEntryReuseProof?: CacheEntryReuseProof;
114
105
  href: string;
115
- targetSnapshot: RouteSnapshotV0;
106
+ targetSnapshot: RouteSnapshot;
116
107
  };
117
108
  type RscFetchResultSource = "cached" | "live";
118
- type RscFetchResultFactsV0 = {
109
+ type RscFetchResultFacts = {
119
110
  source: RscFetchResultSource;
120
111
  currentHref: string;
121
112
  origin: string;
@@ -130,21 +121,21 @@ type RscFetchResultFactsV0 = {
130
121
  responseUrl: string | null;
131
122
  streamedRedirectTarget: string | null;
132
123
  };
133
- type RscRedirectFollowV0 = {
124
+ type RscRedirectFollow = {
134
125
  href: string;
135
126
  historyUpdateMode: "push" | "replace";
136
127
  previousNextUrl: string | null;
137
128
  redirectDepth: number;
138
129
  };
139
130
  type RscFetchResultHardNavReason = "invalidRscPayload" | "rscCompatibilityMismatch" | "externalRedirectTarget" | "redirectDepthExhausted" | "streamedRedirectLoop";
140
- type RscFetchResultDecisionV0 = {
131
+ type RscFetchResultDecision = {
141
132
  kind: "proceedToCommit";
142
133
  discardBody: false;
143
134
  trace: NavigationTrace;
144
135
  } | {
145
136
  kind: "followRedirect";
146
137
  discardBody: boolean;
147
- redirect: RscRedirectFollowV0;
138
+ redirect: RscRedirectFollow;
148
139
  trace: NavigationTrace;
149
140
  } | {
150
141
  kind: "hardNavigate";
@@ -153,14 +144,14 @@ type RscFetchResultDecisionV0 = {
153
144
  reason: RscFetchResultHardNavReason;
154
145
  trace: NavigationTrace;
155
146
  };
156
- type EarlyNavigationIntentFactsV0 = {
147
+ type EarlyNavigationIntentFacts = {
157
148
  basePath: string;
158
149
  currentHref: string;
159
150
  mode: "push" | "replace";
160
151
  scroll: boolean;
161
152
  targetHref: string;
162
153
  };
163
- type EarlyNavigationIntentDecisionV0 = {
154
+ type EarlyNavigationIntentDecision = {
164
155
  kind: "sameDocumentScroll";
165
156
  hash: string;
166
157
  mode: "push" | "replace";
@@ -171,20 +162,86 @@ type EarlyNavigationIntentDecisionV0 = {
171
162
  bypassNavigationCache: boolean;
172
163
  trace: NavigationTrace;
173
164
  };
165
+ type NavigationReuseNavigationKind = "navigate" | "refresh" | "traverse";
166
+ type VisitedResponseCacheCandidateFacts = {
167
+ candidate: "missing";
168
+ navigationKind: NavigationReuseNavigationKind;
169
+ } | {
170
+ candidate: "present";
171
+ fresh: boolean;
172
+ mountedSlotsMatch: boolean;
173
+ navigationKind: NavigationReuseNavigationKind;
174
+ };
175
+ type VisitedResponseCacheCandidateDecision = {
176
+ kind: "miss";
177
+ } | {
178
+ kind: "evict";
179
+ reason: "mountedSlotsMismatch" | "refresh" | "stale";
180
+ } | {
181
+ kind: "reuse";
182
+ };
183
+ type NavigationReuseCandidateAvailability = {
184
+ status: "available";
185
+ } | {
186
+ status: "unavailable";
187
+ };
188
+ type OptimisticRouteShellCandidateAvailability = {
189
+ status: "available";
190
+ } | {
191
+ status: "unavailable";
192
+ reason: "routeManifestMissing";
193
+ };
194
+ type NavigationReuseFacts = {
195
+ bypassNavigationCache: boolean;
196
+ navigationKind: NavigationReuseNavigationKind;
197
+ optimisticRouteShell: OptimisticRouteShellCandidateAvailability;
198
+ prefetch: NavigationReuseCandidateAvailability;
199
+ targetHref: string;
200
+ visitedResponse: NavigationReuseCandidateAvailability;
201
+ };
202
+ type FreshFetchReason = "cacheBypassed" | "cacheMiss" | "refresh" | "routeManifestMissing";
203
+ type NavigationReuseDecision = {
204
+ kind: "reuseVisitedResponse";
205
+ trace: NavigationTrace;
206
+ } | {
207
+ kind: "consumePrefetch";
208
+ trace: NavigationTrace;
209
+ } | {
210
+ kind: "attemptOptimisticRouteShell";
211
+ trace: NavigationTrace;
212
+ } | {
213
+ kind: "fetchFresh";
214
+ reason: FreshFetchReason;
215
+ trace: NavigationTrace;
216
+ };
217
+ type NavigationPrefetchProbeFacts = {
218
+ bypassNavigationCache: boolean;
219
+ navigationKind: NavigationReuseNavigationKind;
220
+ visitedResponse: NavigationReuseCandidateAvailability;
221
+ };
222
+ type NavigationPrefetchProbeDecision = {
223
+ kind: "probe";
224
+ } | {
225
+ kind: "skip";
226
+ reason: "cacheBypassed" | "refresh" | "visitedResponseAvailable";
227
+ };
174
228
  type NavigationPlannerInput = {
175
229
  routeManifest: RouteManifest | null;
176
- state: NavigationPlannerStateV0;
230
+ state: NavigationPlannerState;
177
231
  event: NavigationEvent;
178
232
  };
179
233
  type AcceptedCacheEntryReuseDecision = Extract<CacheEntryReuseDecision, {
180
234
  canReuse: true;
181
235
  }>;
182
- declare function classifyRscFetchResult(facts: RscFetchResultFactsV0): RscFetchResultDecisionV0;
183
- declare function classifyEarlyNavigationIntent(facts: EarlyNavigationIntentFactsV0): EarlyNavigationIntentDecisionV0;
236
+ declare function classifyRscFetchResult(facts: RscFetchResultFacts): RscFetchResultDecision;
237
+ declare function classifyEarlyNavigationIntent(facts: EarlyNavigationIntentFacts): EarlyNavigationIntentDecision;
238
+ declare function classifyVisitedResponseCacheCandidate(facts: VisitedResponseCacheCandidateFacts): VisitedResponseCacheCandidateDecision;
239
+ declare function classifyNavigationReuse(facts: NavigationReuseFacts): NavigationReuseDecision;
240
+ declare function classifyNavigationPrefetchProbe(facts: NavigationPrefetchProbeFacts): NavigationPrefetchProbeDecision;
184
241
  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[];
242
+ declare function resolveSameLayoutAncestorPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
243
+ declare function resolveMountedParallelSlotPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
244
+ declare function resolveCurrentRootBoundaryElementPersistence(currentSnapshot: RouteSnapshot, targetSnapshot: RouteSnapshot): readonly string[];
188
245
  /**
189
246
  * Default/unmatched slot preservation law:
190
247
  *
@@ -196,19 +253,56 @@ declare function resolveCurrentRootBoundaryElementPersistence(currentSnapshot: R
196
253
  * Wire absence and UNMATCHED_SLOT markers are not semantic proof.
197
254
  */
198
255
  declare function resolveDefaultOrUnmatchedSlotPersistenceForLayouts(options: {
199
- currentSlotBindings: readonly ParallelSlotBindingSnapshotV0[];
256
+ currentSlotBindings: readonly ParallelSlotBindingSnapshot[];
200
257
  preservedLayoutIds: readonly string[];
201
- targetSlotBindings: readonly ParallelSlotBindingSnapshotV0[];
258
+ targetSlotBindings: readonly ParallelSlotBindingSnapshot[];
202
259
  }): readonly string[];
203
- declare function planNavigation(input: NavigationPlannerInput): NavigationDecisionV0;
260
+ declare function planNavigation(input: NavigationPlannerInput): NavigationDecision;
261
+ type ServerActionResultFacts = {
262
+ actionRedirectHref: string | null;
263
+ actionRedirectType: "push" | "replace";
264
+ clientCompatibilityId: string | null;
265
+ compatibilityIdHeader: string | null;
266
+ currentHref: string;
267
+ isRscContentType: boolean;
268
+ origin: string;
269
+ responseUrl: string | null;
270
+ };
271
+ type ServerActionResultDecision = {
272
+ kind: "proceed";
273
+ trace: NavigationTrace;
274
+ } | {
275
+ kind: "hardNavigate";
276
+ url: string;
277
+ historyMode?: "assign" | "replace";
278
+ clearClientNavigationCaches: boolean;
279
+ reason: "serverActionRedirectCompatibilityMismatch" | "serverActionRscCompatibilityMismatch";
280
+ trace: NavigationTrace;
281
+ };
282
+ type RscNavigationErrorFacts = {
283
+ currentHref: string;
284
+ };
285
+ type RscNavigationErrorDecision = {
286
+ kind: "hardNavigate";
287
+ url: string;
288
+ reason: "rscNavigationError";
289
+ trace: NavigationTrace;
290
+ };
291
+ declare function classifyServerActionResult(facts: ServerActionResultFacts): ServerActionResultDecision;
292
+ declare function classifyRscNavigationError(facts: RscNavigationErrorFacts): RscNavigationErrorDecision;
204
293
  declare const navigationPlanner: {
205
294
  classifyEarlyNavigationIntent: typeof classifyEarlyNavigationIntent;
295
+ classifyNavigationPrefetchProbe: typeof classifyNavigationPrefetchProbe;
296
+ classifyNavigationReuse: typeof classifyNavigationReuse;
206
297
  classifyRscFetchResult: typeof classifyRscFetchResult;
298
+ classifyRscNavigationError: typeof classifyRscNavigationError;
207
299
  classifyRootBoundaryTransition: typeof classifyRootBoundaryTransition;
300
+ classifyServerActionResult: typeof classifyServerActionResult;
301
+ classifyVisitedResponseCacheCandidate: typeof classifyVisitedResponseCacheCandidate;
208
302
  plan: typeof planNavigation;
209
303
  resolveCurrentRootBoundaryElementPersistence: typeof resolveCurrentRootBoundaryElementPersistence;
210
304
  resolveMountedParallelSlotPersistence: typeof resolveMountedParallelSlotPersistence;
211
305
  resolveSameLayoutAncestorPersistence: typeof resolveSameLayoutAncestorPersistence;
212
306
  };
213
307
  //#endregion
214
- export { EarlyNavigationIntentDecisionV0, EarlyNavigationIntentFactsV0, FlightResultV0, InterceptionSnapshotV0, MountedParallelSlotSnapshotV0, NavigationDecisionV0, NavigationEvent, NavigationPlannerInput, NavigationPlannerStateV0, OperationLane, OperationToken, ParallelSlotBindingSnapshotV0, RefreshScope, RootBoundaryTransition, RouteSnapshotV0, RscFetchResultDecisionV0, RscFetchResultFactsV0, TraverseDirection, navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts };
308
+ export { EarlyNavigationIntentDecision, EarlyNavigationIntentFacts, FlightResult, InterceptionSnapshot, MountedParallelSlotSnapshot, NavigationDecision, NavigationEvent, NavigationPlannerInput, NavigationPlannerState, NavigationReuseDecision, NavigationReuseFacts, type OperationLane, type OperationToken, ParallelSlotBindingSnapshot, RefreshScope, RootBoundaryTransition, RouteSnapshot, RscFetchResultDecision, RscFetchResultFacts, RscNavigationErrorDecision, RscNavigationErrorFacts, ServerActionResultDecision, ServerActionResultFacts, TraverseDirection, VisitedResponseCacheCandidateFacts, navigationPlanner, resolveDefaultOrUnmatchedSlotPersistenceForLayouts };