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
@@ -1,5 +1,5 @@
1
1
  import { ACTION_REVALIDATED_HEADER } from "./headers.js";
2
- import { VINEXT_RSC_CONTENT_TYPE, isRscCompatibilityIdCompatible } from "./app-rsc-cache-busting.js";
2
+ import { VINEXT_RSC_CONTENT_TYPE } from "./app-rsc-cache-busting.js";
3
3
  //#region src/server/app-browser-action-result.ts
4
4
  const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
5
5
  const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
@@ -33,7 +33,7 @@ function parseServerActionRevalidationHeader(headers) {
33
33
  }
34
34
  }
35
35
  function createServerActionHttpFallbackError(status) {
36
- if (status < 400 || status > 599) return null;
36
+ if (status !== 401 && status !== 403 && status !== 404) return null;
37
37
  const digest = status === 404 ? "NEXT_HTTP_ERROR_FALLBACK;404" : `NEXT_HTTP_ERROR_FALLBACK;${status}`;
38
38
  const error = /* @__PURE__ */ new Error(status === 404 ? "NEXT_NOT_FOUND" : `NEXT_HTTP_ERROR_FALLBACK;${status}`);
39
39
  return Object.assign(error, { digest });
@@ -47,14 +47,23 @@ async function readInvalidServerActionResponseError(response, hasRedirectLocatio
47
47
  const message = response.status >= 400 && contentType.toLowerCase().startsWith("text/plain") ? await response.text() : "An unexpected response was received from the server.";
48
48
  return new Error(message || "An unexpected response was received from the server.");
49
49
  }
50
- function shouldCheckRscCompatibilityForServerActionResponse(response) {
51
- return (response.headers.get("content-type") ?? "").startsWith(VINEXT_RSC_CONTENT_TYPE);
52
- }
53
- function resolveServerActionRedirectCompatibilityHardNavigationTarget(options) {
54
- if (!options.actionRedirectHref) return null;
55
- if (!shouldCheckRscCompatibilityForServerActionResponse(options.response)) return null;
56
- if (isRscCompatibilityIdCompatible(options.response.headers.get("X-Vinext-RSC-Compatibility-Id"), options.clientCompatibilityId)) return null;
57
- return options.actionRedirectHref;
50
+ /**
51
+ * Converts raw browser response data into the narrow facts expected by the
52
+ * navigation planner. This is the single place where redirect-type
53
+ * normalisation and RSC content-type detection happen for server-action
54
+ * compatibility checks.
55
+ */
56
+ function createServerActionResultFacts(input) {
57
+ return {
58
+ actionRedirectHref: input.actionRedirectHref,
59
+ actionRedirectType: input.actionRedirectType === "push" ? "push" : "replace",
60
+ clientCompatibilityId: input.clientCompatibilityId,
61
+ compatibilityIdHeader: input.compatibilityIdHeader,
62
+ currentHref: input.currentHref,
63
+ isRscContentType: (input.contentTypeHeader ?? "").startsWith(VINEXT_RSC_CONTENT_TYPE),
64
+ origin: input.origin,
65
+ responseUrl: input.responseUrl
66
+ };
58
67
  }
59
68
  function shouldScheduleRefreshForDiscardedServerAction(revalidation) {
60
69
  return revalidation !== "none";
@@ -99,4 +108,4 @@ function createDiscardedServerActionRefreshScheduler(options) {
99
108
  };
100
109
  }
101
110
  //#endregion
102
- export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionRedirectCompatibilityHardNavigationTarget, shouldCheckRscCompatibilityForServerActionResponse, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
111
+ export { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult, shouldScheduleRefreshForDiscardedServerAction };
@@ -4,40 +4,43 @@ import { AppElementsWire } from "./app-elements-wire.js";
4
4
  import { APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI } from "./app-rsc-render-mode.js";
5
5
  import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
6
6
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
7
- import { installWindowNext } from "../client/window-next.js";
7
+ import { installWindowNext, setWindowNextInternalSourcePage } from "../client/window-next.js";
8
8
  import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
9
9
  import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
10
10
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
11
+ import { clearAppNavigationFailureTarget, installAppNavigationFailureListeners } from "../client/app-nav-failure-handler.js";
11
12
  import { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext } from "./app-browser-interception-context.js";
12
13
  import { readHistoryStatePreviousNextUrl } from "./app-history-state.js";
13
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, resolveRscCompatibilityNavigationDecision } from "./app-rsc-cache-busting.js";
14
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
14
15
  import { AppBrowserMpaNavigationScheduler } from "./app-browser-mpa-navigation.js";
15
16
  import { navigationPlanner } from "./navigation-planner.js";
16
17
  import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
17
- import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, getBfcacheIdMapContext, getClientNavigationRenderContext, getPrefetchCache, invalidatePrefetchCache, isRedirectError, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, useRouter } from "../shims/navigation.js";
18
- import { DevRecoveryBoundary, RedirectBoundary } from "../shims/error-boundary.js";
18
+ import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, decodeRedirectError, getBfcacheIdMapContext, getClientNavigationRenderContext, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, isRedirectError, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, setClientParams, setMountedSlotsHeader, setNavigationContext, setPendingPathname, useRouter } from "../shims/navigation.js";
19
+ import DefaultGlobalError from "../shims/default-global-error.js";
20
+ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../shims/error-boundary.js";
19
21
  import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
20
22
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
21
23
  import "../client/instrumentation-client.js";
22
- import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, resolveServerActionRedirectCompatibilityHardNavigationTarget, shouldCheckRscCompatibilityForServerActionResponse, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
24
+ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
23
25
  import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
24
26
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
25
27
  import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
26
28
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch } from "./app-browser-navigation-controller.js";
29
+ import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
27
30
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition } from "./app-browser-hydration.js";
28
31
  import { AppBrowserHistoryController } from "./app-browser-history-controller.js";
29
32
  import { createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
30
33
  import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition } from "./app-browser-popstate.js";
31
- import { createOnUncaughtError, prodOnCaughtError } from "./app-browser-error.js";
34
+ import { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnRecoverableError } from "./app-browser-error.js";
32
35
  import { dismissOverlay } from "./dev-error-overlay-store.js";
33
- import { devOnCaughtError, devOnUncaughtError, installDevErrorOverlay, installViteHmrErrorHandler, reportInitialDevServerErrors } from "./dev-error-overlay.js";
36
+ import { devOnCaughtError, installDevErrorOverlay, installViteHmrErrorHandler, reportInitialDevServerErrors } from "./dev-error-overlay.js";
34
37
  import { throwOnServerActionNotFound } from "./server-action-not-found.js";
35
38
  import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
36
39
  import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
37
40
  import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
38
41
  import { flushSync } from "react-dom";
39
42
  import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
40
- import { hydrateRoot } from "react-dom/client";
43
+ import { createRoot, hydrateRoot } from "react-dom/client";
41
44
  //#region src/server/app-browser-entry.ts
42
45
  function toActionType(kind) {
43
46
  return kind === "traverse" ? "traverse" : "navigate";
@@ -55,6 +58,14 @@ const CLIENT_RSC_COMPATIBILITY_ID = getVinextRscCompatibilityId();
55
58
  const optimisticRouteTemplates = /* @__PURE__ */ new Map();
56
59
  const optimisticRouteTemplateSources = /* @__PURE__ */ new Set();
57
60
  const optimisticRouteTemplateLearning = /* @__PURE__ */ new Map();
61
+ function claimInitialAppRouterBootstrap() {
62
+ if (window.__VINEXT_RSC_ROOT__ || window.__VINEXT_RSC_BOOTSTRAP_STATE__) return false;
63
+ window.__VINEXT_RSC_BOOTSTRAP_STATE__ = "starting";
64
+ return true;
65
+ }
66
+ function markInitialAppRouterBootstrapHydrated() {
67
+ window.__VINEXT_RSC_BOOTSTRAP_STATE__ = "hydrated";
68
+ }
58
69
  function getBrowserRouteManifest() {
59
70
  return getNavigationRuntime()?.bootstrap.routeManifest ?? null;
60
71
  }
@@ -109,10 +120,10 @@ function isRouterStatePromise(value) {
109
120
  let latestClientParams = {};
110
121
  const visitedResponseCache = /* @__PURE__ */ new Map();
111
122
  let browserRouterStateHasEverCommitted = false;
112
- let pendingNavigationRecoveryHref = null;
113
123
  const mpaNavigationScheduler = new AppBrowserMpaNavigationScheduler();
114
124
  const unresolvedMpaNavigation = new Promise(() => {});
115
125
  const RSC_HMR_SETTLE_DELAY_MS = 150;
126
+ const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
116
127
  let latestRscHmrUpdateId = 0;
117
128
  let synchronousPopstateScrollRestoreNavigationId = null;
118
129
  function waitForRscHmrSettle(delayMs = RSC_HMR_SETTLE_DELAY_MS) {
@@ -262,39 +273,31 @@ function createNavigationCommitEffect(options) {
262
273
  stageClientParams: () => stageClientParams(params),
263
274
  targetHistoryIndex
264
275
  });
265
- pendingNavigationRecoveryHref = null;
276
+ clearAppNavigationFailureTarget(href);
266
277
  commitClientNavigationState(navId);
267
278
  };
268
279
  }
269
280
  async function renderNavigationPayload(payload, navigationSnapshot, targetHref, navId, historyUpdateMode, params, previousNextUrl, pendingRouterState, payloadOrigin, actionType = "navigate", operationLane = "navigation", traversalIntent = null, scrollIntent = null, restoredBfcacheIds = null, reuseCurrentBfcacheIds = true, visibleCommitMode = "transition") {
270
281
  syncServerActionHttpFallbackHead(null);
271
- try {
272
- return await browserNavigationController.renderNavigationPayload({
273
- actionType,
274
- createNavigationCommitEffect: (options) => {
275
- pendingNavigationRecoveryHref = options.href;
276
- return createNavigationCommitEffect(options);
277
- },
278
- historyUpdateMode,
279
- navigationSnapshot,
280
- nextElements: payload,
281
- operationLane,
282
- payloadOrigin,
283
- params,
284
- pendingRouterState,
285
- previousNextUrl,
286
- scrollIntent,
287
- restoredBfcacheIds,
288
- reuseCurrentBfcacheIds,
289
- targetHistoryIndex: traversalIntent === null ? void 0 : traversalIntent.targetHistoryIndex,
290
- targetHref,
291
- navId,
292
- visibleCommitMode
293
- });
294
- } catch (error) {
295
- pendingNavigationRecoveryHref = null;
296
- throw error;
297
- }
282
+ return browserNavigationController.renderNavigationPayload({
283
+ actionType,
284
+ createNavigationCommitEffect,
285
+ historyUpdateMode,
286
+ navigationSnapshot,
287
+ nextElements: payload,
288
+ operationLane,
289
+ payloadOrigin,
290
+ params,
291
+ pendingRouterState,
292
+ previousNextUrl,
293
+ scrollIntent,
294
+ restoredBfcacheIds,
295
+ reuseCurrentBfcacheIds,
296
+ targetHistoryIndex: traversalIntent === null ? void 0 : traversalIntent.targetHistoryIndex,
297
+ targetHref,
298
+ navId,
299
+ visibleCommitMode
300
+ });
298
301
  }
299
302
  function resolveActionRedirectTarget(response) {
300
303
  const actionRedirect = response.headers.get(ACTION_REDIRECT_HEADER);
@@ -360,23 +363,39 @@ function evictVisitedResponseCacheIfNeeded() {
360
363
  visitedResponseCache.delete(oldest);
361
364
  }
362
365
  }
363
- function getVisitedResponse(rscUrl, interceptionContext, mountedSlotsHeader, navigationKind) {
366
+ function readVisitedResponseCacheCandidate(rscUrl, interceptionContext, mountedSlotsHeader, navigationKind) {
364
367
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
365
368
  const cached = visitedResponseCache.get(cacheKey);
366
- if (!cached) return null;
367
- if ((cached.response.mountedSlotsHeader ?? null) !== mountedSlotsHeader) {
368
- visitedResponseCache.delete(cacheKey);
369
- return null;
370
- }
371
- if (isVisitedResponseCacheEntryFresh(cached, {
372
- navigationKind,
373
- now: Date.now()
374
- })) {
375
- visitedResponseCache.delete(cacheKey);
376
- visitedResponseCache.set(cacheKey, cached);
377
- return cached;
369
+ if (!cached) return {
370
+ cacheKey,
371
+ entry: null,
372
+ facts: {
373
+ candidate: "missing",
374
+ navigationKind
375
+ }
376
+ };
377
+ return {
378
+ cacheKey,
379
+ entry: cached,
380
+ facts: {
381
+ candidate: "present",
382
+ fresh: isVisitedResponseCacheEntryFresh(cached, {
383
+ navigationKind,
384
+ now: Date.now()
385
+ }),
386
+ mountedSlotsMatch: (cached.response.mountedSlotsHeader ?? null) === mountedSlotsHeader,
387
+ navigationKind
388
+ }
389
+ };
390
+ }
391
+ function applyVisitedResponseCacheCandidateDecision(candidate, decision) {
392
+ if (candidate.entry === null) return null;
393
+ if (decision.kind === "reuse") {
394
+ visitedResponseCache.delete(candidate.cacheKey);
395
+ visitedResponseCache.set(candidate.cacheKey, candidate.entry);
396
+ return candidate.entry;
378
397
  }
379
- visitedResponseCache.delete(cacheKey);
398
+ visitedResponseCache.delete(candidate.cacheKey);
380
399
  return null;
381
400
  }
382
401
  function deleteVisitedResponse(rscUrl, interceptionContext) {
@@ -525,20 +544,25 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
525
544
  return new Promise(() => {});
526
545
  } });
527
546
  browserRouterStateHasEverCommitted = true;
528
- const hydratedAt = performance.now();
529
- window.__VINEXT_HYDRATED_AT = hydratedAt;
530
- window.__NEXT_HYDRATED = true;
531
- window.__NEXT_HYDRATED_AT = hydratedAt;
532
- window.__NEXT_HYDRATED_CB?.();
533
547
  return () => {
534
548
  registerNavigationRuntimeFunctions({ navigateExternal: void 0 });
535
549
  detach();
536
550
  setMountedSlotsHeader(null);
537
551
  };
538
552
  }, [setTreeStateValue]);
553
+ useEffect(() => {
554
+ const hydratedAt = performance.now();
555
+ window.__VINEXT_HYDRATED_AT = hydratedAt;
556
+ window.__NEXT_HYDRATED = true;
557
+ window.__NEXT_HYDRATED_AT = hydratedAt;
558
+ window.__NEXT_HYDRATED_CB?.();
559
+ }, []);
539
560
  useLayoutEffect(() => {
540
561
  historyController.rememberHistoryStateSnapshot(treeState);
541
562
  }, [treeState]);
563
+ useEffect(() => {
564
+ setWindowNextInternalSourcePage(AppElementsWire.readMetadata(treeState.elements).sourcePage);
565
+ }, [treeState.elements]);
542
566
  useLayoutEffect(() => {
543
567
  setMountedSlotsHeader(getMountedSlotIdsHeader(stateRef.current.elements));
544
568
  removeStylesheetLinksCoveredByInlineCss();
@@ -564,13 +588,17 @@ function BrowserRoot({ initialElements, initialNavigationSnapshot }) {
564
588
  const redirectedTree = createElement(AppRouterRedirectBridge, null, BfcacheIdMapContext ? createElement(BfcacheIdMapContext.Provider, { value: treeState.bfcacheIds }, stateKeyTree) : stateKeyTree);
565
589
  const innerTree = AppRouterContext ? createElement(AppRouterContext.Provider, { value: appRouterInstance }, redirectedTree) : redirectedTree;
566
590
  const committedTree = import.meta.env.DEV ? createElement(DevRecoveryBoundary, {
591
+ isImplicitRootErrorBoundary: true,
567
592
  resetKey: treeState.renderId,
568
593
  onCatch: handleDevRecoveryBoundaryCatch
569
594
  }, innerTree) : innerTree;
570
- const scrollScopedTree = createElement(AppRouterScrollCommitProvider, { commitId: treeState.renderId }, committedTree);
595
+ const rootErrorTree = createElement(GlobalErrorBoundary, {
596
+ fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
597
+ children: createElement(AppRouterScrollCommitProvider, { commitId: treeState.renderId }, committedTree)
598
+ });
571
599
  const ClientNavigationRenderContext = getClientNavigationRenderContext();
572
- if (!ClientNavigationRenderContext) return scrollScopedTree;
573
- return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, scrollScopedTree);
600
+ if (!ClientNavigationRenderContext) return rootErrorTree;
601
+ return createElement(ClientNavigationRenderContext.Provider, { value: treeState.navigationSnapshot }, rootErrorTree);
574
602
  }
575
603
  function restoreHydrationNavigationContext(pathname, searchParams, params) {
576
604
  setNavigationContext({
@@ -698,31 +726,23 @@ function registerServerActionCallback() {
698
726
  const hasActionRedirect = fetchResponse.headers.has(ACTION_REDIRECT_HEADER);
699
727
  const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse);
700
728
  if (hasActionRedirect && !actionRedirectTarget) return;
701
- const actionRedirectCompatibilityHardNavigationTarget = resolveServerActionRedirectCompatibilityHardNavigationTarget({
729
+ const actionResultFacts = createServerActionResultFacts({
702
730
  actionRedirectHref: actionRedirectTarget?.href ?? null,
731
+ actionRedirectType: actionRedirectTarget?.type ?? null,
703
732
  clientCompatibilityId: CLIENT_RSC_COMPATIBILITY_ID,
704
- response: fetchResponse
705
- });
706
- if (actionRedirectCompatibilityHardNavigationTarget) {
707
- clearClientNavigationCaches();
708
- browserNavigationController.performHardNavigation(actionRedirectCompatibilityHardNavigationTarget, actionRedirectTarget?.type === "push" ? "assign" : "replace");
709
- return;
710
- }
711
- if (!actionRedirectTarget && shouldCheckRscCompatibilityForServerActionResponse(fetchResponse) && resolveRscCompatibilityNavigationDecision({
712
- clientCompatibilityId: CLIENT_RSC_COMPATIBILITY_ID,
733
+ compatibilityIdHeader: fetchResponse.headers.get(VINEXT_RSC_COMPATIBILITY_ID_HEADER),
734
+ contentTypeHeader: fetchResponse.headers.get("content-type"),
713
735
  currentHref: actionInitiation.href,
714
736
  origin: window.location.origin,
715
- responseCompatibilityId: fetchResponse.headers.get("X-Vinext-RSC-Compatibility-Id"),
716
737
  responseUrl: fetchResponse.url
717
- }).kind === "hard-navigate") {
718
- browserNavigationController.performHardNavigation(actionInitiation.href);
719
- return;
720
- }
738
+ });
739
+ const fetchResponseIsRsc = actionResultFacts.isRscContentType;
740
+ if (applyServerActionResultDecision(navigationPlanner.classifyServerActionResult(actionResultFacts), clearClientNavigationCaches, (url, historyMode) => browserNavigationController.performHardNavigation(url, historyMode))) return;
721
741
  const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
722
742
  if (revalidation !== "none") clearClientNavigationCaches();
723
743
  const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
724
744
  if (invalidResponseError) throw invalidResponseError;
725
- if (actionRedirectTarget && !shouldCheckRscCompatibilityForServerActionResponse(fetchResponse)) {
745
+ if (actionRedirectTarget && !fetchResponseIsRsc) {
726
746
  browserNavigationController.performHardNavigation(actionRedirectTarget.href);
727
747
  return;
728
748
  }
@@ -770,7 +790,9 @@ function registerServerActionCallback() {
770
790
  });
771
791
  }
772
792
  async function main() {
793
+ if (!claimInitialAppRouterBootstrap()) return;
773
794
  registerServerActionCallback();
795
+ installAppNavigationFailureListeners();
774
796
  if (import.meta.env.DEV) {
775
797
  installDevErrorOverlay();
776
798
  installViteHmrErrorHandler(import.meta.hot);
@@ -784,31 +806,47 @@ function bootstrapHydration(rscStream) {
784
806
  const root = decodeAppElementsPromise(createFromReadableStream(rscStream));
785
807
  const initialNavigationSnapshot = createClientNavigationRenderSnapshot(window.location.href, latestClientParams);
786
808
  historyController.writeBootstrapHistoryMetadata();
787
- const onUncaughtError = import.meta.env.DEV ? devOnUncaughtError : createOnUncaughtError(() => pendingNavigationRecoveryHref);
809
+ const onUncaughtError = createOnUncaughtError();
788
810
  const formState = consumeInitialFormState(getVinextBrowserGlobal());
789
811
  const hydrateRootOptions = import.meta.env.DEV ? createVinextHydrateRootOptions({
790
812
  formState,
791
- onCaughtError: devOnCaughtError,
813
+ onCaughtError: createDevOnCaughtError(devOnCaughtError, onUncaughtError),
792
814
  onUncaughtError
793
815
  }) : createVinextHydrateRootOptions({
794
816
  formState,
795
- onCaughtError: prodOnCaughtError,
817
+ onCaughtError: createProdOnCaughtError(onUncaughtError),
818
+ onRecoverableError: prodOnRecoverableError,
796
819
  onUncaughtError
797
820
  });
798
- window.__VINEXT_RSC_ROOT__ = hydrateRootInTransition({
799
- children: createElement(BrowserRoot, {
800
- initialElements: root,
801
- initialNavigationSnapshot
802
- }),
821
+ const children = createElement(BrowserRoot, {
822
+ initialElements: root,
823
+ initialNavigationSnapshot
824
+ });
825
+ const errorShellStyles = document.querySelectorAll("style[data-vinext-error-shell-style]");
826
+ if (document.documentElement.id === "__next_error__") {
827
+ const { formState: _inertFormState, ...createRootOptions } = hydrateRootOptions;
828
+ for (const style of errorShellStyles) style.remove();
829
+ startTransition(() => {
830
+ const clientRoot = createRoot(document, createRootOptions);
831
+ clientRoot.render(children);
832
+ window.__VINEXT_RSC_ROOT__ = clientRoot;
833
+ });
834
+ } else window.__VINEXT_RSC_ROOT__ = hydrateRootInTransition({
835
+ children,
803
836
  container: document,
804
837
  hydrateRoot,
805
838
  options: hydrateRootOptions,
806
839
  startTransition
807
840
  });
841
+ markInitialAppRouterBootstrapHydrated();
842
+ let activeNavigationAbortController = null;
808
843
  registerNavigationRuntimeFunctions({
809
844
  clearNavigationCaches: clearClientNavigationCaches,
810
845
  commitHashNavigation: (href, historyUpdateMode, scroll) => historyController.commitHashOnlyNavigation(href, historyUpdateMode, scroll),
811
846
  navigate: async function navigateRsc(href, redirectDepth = 0, navigationKind = "navigate", historyUpdateMode, previousNextUrlOverride, programmaticTransition = false, traversalIntent, scrollIntent, visibleCommitMode = "transition") {
847
+ activeNavigationAbortController?.abort();
848
+ const navigationAbortController = new AbortController();
849
+ activeNavigationAbortController = navigationAbortController;
812
850
  let pendingRouterState = null;
813
851
  const navId = browserNavigationController.beginNavigation();
814
852
  discardedServerActionRefreshScheduler.markNavigationStart();
@@ -820,7 +858,9 @@ function bootstrapHydration(rscStream) {
820
858
  const activeTraversalIntent = navigationKind === "traverse" ? traversalIntent ?? historyController.resolveTraversalIntent(window.history.state) : null;
821
859
  const performHardNavigationForScrollIntent = (targetHref) => {
822
860
  consumeAppRouterScrollIntent(scrollIntent ?? null);
823
- return browserNavigationController.performHardNavigation(targetHref);
861
+ const didNavigate = browserNavigationController.performHardNavigation(targetHref);
862
+ if (!didNavigate) clearAppNavigationFailureTarget(targetHref);
863
+ return didNavigate;
824
864
  };
825
865
  let restoredBfcacheIds = navigationKind === "traverse" ? historyController.readCurrentBfcacheVersionHistoryIds(activeTraversalIntent?.historyState ?? window.history.state) : null;
826
866
  const reuseCurrentBfcacheIds = navigationKind !== "traverse" || !historyController.isCacheInvalidationGuarded() && historyController.isCurrentBfcacheVersion(activeTraversalIntent?.historyState ?? window.history.state);
@@ -856,8 +896,35 @@ function bootstrapHydration(rscStream) {
856
896
  renderMode: navigationKind === "refresh" ? APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI : void 0
857
897
  });
858
898
  const rscUrl = await createRscRequestUrl(url.pathname + url.search, requestHeaders);
859
- const cachedRoute = shouldBypassNavigationCache ? null : getVisitedResponse(rscUrl, requestInterceptionContext, mountedSlotsHeader, navigationKind);
860
- if (cachedRoute) {
899
+ const visitedResponseCandidate = shouldBypassNavigationCache ? {
900
+ cacheKey: AppElementsWire.encodeCacheKey(rscUrl, requestInterceptionContext),
901
+ entry: null,
902
+ facts: {
903
+ candidate: "missing",
904
+ navigationKind
905
+ }
906
+ } : readVisitedResponseCacheCandidate(rscUrl, requestInterceptionContext, mountedSlotsHeader, navigationKind);
907
+ const cachedRoute = applyVisitedResponseCacheCandidateDecision(visitedResponseCandidate, navigationPlanner.classifyVisitedResponseCacheCandidate(visitedResponseCandidate.facts));
908
+ const visitedResponse = cachedRoute === null ? { status: "unavailable" } : { status: "available" };
909
+ const prefetchProbeDecision = navigationPlanner.classifyNavigationPrefetchProbe({
910
+ bypassNavigationCache: shouldBypassNavigationCache,
911
+ navigationKind,
912
+ visitedResponse
913
+ });
914
+ let routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
915
+ const hasPrefetchCandidate = prefetchProbeDecision.kind === "probe" && hasPrefetchCacheEntryForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, { notifyInvalidation: false });
916
+ const reuseDecision = navigationPlanner.classifyNavigationReuse({
917
+ bypassNavigationCache: shouldBypassNavigationCache,
918
+ navigationKind,
919
+ optimisticRouteShell: routeManifest === null ? {
920
+ reason: "routeManifestMissing",
921
+ status: "unavailable"
922
+ } : { status: "available" },
923
+ prefetch: hasPrefetchCandidate ? { status: "available" } : { status: "unavailable" },
924
+ targetHref: currentHref,
925
+ visitedResponse
926
+ });
927
+ if (reuseDecision.kind === "reuseVisitedResponse" && cachedRoute) {
861
928
  const cachedFetchDecision = navigationPlanner.classifyRscFetchResult({
862
929
  clientCompatibilityId: CLIENT_RSC_COMPATIBILITY_ID,
863
930
  compatibilityIdHeader: cachedRoute.response.compatibilityIdHeader ?? null,
@@ -900,7 +967,8 @@ function bootstrapHydration(rscStream) {
900
967
  let navResponse;
901
968
  let navResponseExpiresAt;
902
969
  let navResponseUrl = null;
903
- if (navigationKind !== "refresh" && !shouldBypassNavigationCache) {
970
+ let fallbackReuseDecision = reuseDecision;
971
+ if (reuseDecision.kind === "consumePrefetch") {
904
972
  const prefetchedResponse = await consumePrefetchResponseForNavigation(rscUrl, requestInterceptionContext, mountedSlotsHeader, { shouldConsume: () => browserNavigationController.isCurrentNavigation(navId) });
905
973
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
906
974
  if (prefetchedResponse) {
@@ -908,9 +976,22 @@ function bootstrapHydration(rscStream) {
908
976
  navResponseExpiresAt = prefetchedResponse.expiresAt;
909
977
  navResponseUrl = prefetchedResponse.url;
910
978
  }
979
+ if (!navResponse) {
980
+ routeManifest = navigationKind === "navigate" ? getBrowserRouteManifest() : null;
981
+ fallbackReuseDecision = navigationPlanner.classifyNavigationReuse({
982
+ bypassNavigationCache: shouldBypassNavigationCache,
983
+ navigationKind,
984
+ optimisticRouteShell: routeManifest === null ? {
985
+ reason: "routeManifestMissing",
986
+ status: "unavailable"
987
+ } : { status: "available" },
988
+ prefetch: { status: "unavailable" },
989
+ targetHref: currentHref,
990
+ visitedResponse: { status: "unavailable" }
991
+ });
992
+ }
911
993
  }
912
- if (!navResponse && navigationKind === "navigate") {
913
- const routeManifest = getBrowserRouteManifest();
994
+ if (!navResponse && fallbackReuseDecision.kind === "attemptOptimisticRouteShell") {
914
995
  await learnOptimisticRouteTemplatesFromPrefetchCache({
915
996
  interceptionContext: requestInterceptionContext,
916
997
  mountedSlotsHeader,
@@ -942,7 +1023,8 @@ function bootstrapHydration(rscStream) {
942
1023
  }
943
1024
  navResponse = await fetch(rscUrl, {
944
1025
  headers: requestHeaders,
945
- credentials: "include"
1026
+ credentials: "include",
1027
+ signal: navigationAbortController.signal
946
1028
  });
947
1029
  }
948
1030
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
@@ -988,6 +1070,7 @@ function bootstrapHydration(rscStream) {
988
1070
  headers: navResponse.headers
989
1071
  });
990
1072
  const cacheBufferPromise = new Response(cacheBranch).arrayBuffer();
1073
+ cacheBufferPromise.catch(() => {});
991
1074
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
992
1075
  const rscPayload = decodeAppElementsPromise(createFromFetch(Promise.resolve(reactResponse)));
993
1076
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
@@ -1012,8 +1095,9 @@ function bootstrapHydration(rscStream) {
1012
1095
  } catch (error) {
1013
1096
  if (!browserNavigationController.isCurrentNavigation(navId)) return;
1014
1097
  if (!isPageUnloading) console.error("[vinext] RSC navigation error:", error);
1015
- performHardNavigationForScrollIntent(currentHref);
1098
+ performHardNavigationForScrollIntent(navigationPlanner.classifyRscNavigationError({ currentHref }).url);
1016
1099
  } finally {
1100
+ if (activeNavigationAbortController === navigationAbortController) activeNavigationAbortController = null;
1017
1101
  browserNavigationController.finalizeNavigation(navId, pendingRouterState);
1018
1102
  discardedServerActionRefreshScheduler.markNavigationSettled();
1019
1103
  }
@@ -1,9 +1,13 @@
1
1
  //#region src/server/app-browser-error.d.ts
2
- declare function createOnUncaughtError(getRecoveryHref: () => string | null): (error: unknown, errorInfo: {
2
+ type VinextHydrateRootErrorInfo = {
3
3
  componentStack?: string;
4
- }) => void;
5
- declare function prodOnCaughtError(error: unknown, errorInfo: {
6
- componentStack?: string;
7
- }): void;
4
+ errorBoundary?: unknown;
5
+ };
6
+ type HydrateRootErrorHandler = (error: unknown, errorInfo: VinextHydrateRootErrorInfo) => void;
7
+ declare function createOnUncaughtError(): HydrateRootErrorHandler;
8
+ declare function createProdOnCaughtError(onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
9
+ declare function createDevOnCaughtError(onCaughtError: HydrateRootErrorHandler, onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
10
+ declare function prodOnCaughtError(error: unknown, errorInfo: VinextHydrateRootErrorInfo): void;
11
+ declare function prodOnRecoverableError(error: unknown): void;
8
12
  //#endregion
9
- export { createOnUncaughtError, prodOnCaughtError };
13
+ export { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnCaughtError, prodOnRecoverableError };
@@ -1,17 +1,52 @@
1
+ import { isUnknownRecord } from "../utils/record.js";
1
2
  import { isNavigationSignalError } from "../utils/navigation-signal.js";
2
3
  //#region src/server/app-browser-error.ts
3
- function createOnUncaughtError(getRecoveryHref) {
4
+ function isImplicitRootErrorBoundary(errorInfo) {
5
+ if (!isUnknownRecord(errorInfo.errorBoundary)) return false;
6
+ const props = errorInfo.errorBoundary.props;
7
+ return isUnknownRecord(props) && props.isImplicitRootErrorBoundary === true;
8
+ }
9
+ function logCaughtError(error, errorInfo) {
10
+ console.error(error);
11
+ if (errorInfo?.componentStack) console.error("The above error occurred in a React component:\n" + errorInfo.componentStack);
12
+ }
13
+ function reportGlobalError(error) {
14
+ if (typeof globalThis.reportError === "function") {
15
+ globalThis.reportError(error);
16
+ return;
17
+ }
18
+ console.error(error);
19
+ }
20
+ function createOnUncaughtError() {
21
+ return (error) => {
22
+ reportGlobalError(error);
23
+ };
24
+ }
25
+ function createProdOnCaughtError(onImplicitRootError) {
26
+ return (error, errorInfo) => {
27
+ if (isNavigationSignalError(error)) return;
28
+ if (isImplicitRootErrorBoundary(errorInfo)) {
29
+ onImplicitRootError(error, errorInfo);
30
+ return;
31
+ }
32
+ logCaughtError(error, errorInfo);
33
+ };
34
+ }
35
+ function createDevOnCaughtError(onCaughtError, onImplicitRootError) {
4
36
  return (error, errorInfo) => {
5
- console.error(error);
6
- if (errorInfo?.componentStack) console.error("The above error occurred in a React component:\n" + errorInfo.componentStack);
7
- const recoveryHref = getRecoveryHref();
8
- if (recoveryHref !== null) window.location.assign(recoveryHref);
37
+ if (isImplicitRootErrorBoundary(errorInfo)) {
38
+ onImplicitRootError(error, errorInfo);
39
+ return;
40
+ }
41
+ onCaughtError(error, errorInfo);
9
42
  };
10
43
  }
11
44
  function prodOnCaughtError(error, errorInfo) {
12
45
  if (isNavigationSignalError(error)) return;
13
- console.error(error);
14
- if (errorInfo?.componentStack) console.error("The above error occurred in a React component:\n" + errorInfo.componentStack);
46
+ logCaughtError(error, errorInfo);
47
+ }
48
+ function prodOnRecoverableError(error) {
49
+ reportGlobalError(error instanceof Error && error.cause !== void 0 ? error.cause : error);
15
50
  }
16
51
  //#endregion
17
- export { createOnUncaughtError, prodOnCaughtError };
52
+ export { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnCaughtError, prodOnRecoverableError };
@@ -8,6 +8,7 @@ type HydrateRootChildren = Parameters<HydrateRoot>[1];
8
8
  type HydrateRootReturn = ReturnType<HydrateRoot>;
9
9
  type HydrateRootCaughtErrorHandler = NonNullable<HydrateRootOptions["onCaughtError"]>;
10
10
  type HydrateRootUncaughtErrorHandler = NonNullable<HydrateRootOptions["onUncaughtError"]>;
11
+ type HydrateRootRecoverableErrorHandler = NonNullable<HydrateRootOptions["onRecoverableError"]>;
11
12
  type StartTransition = (action: () => void) => void;
12
13
  declare const RSC_FORM_STATE_GLOBAL = "__VINEXT_RSC_FORM_STATE__";
13
14
  type FormStateGlobal = {
@@ -17,6 +18,7 @@ declare function consumeInitialFormState(global: FormStateGlobal): ReactFormStat
17
18
  declare function createVinextHydrateRootOptions(options: {
18
19
  formState: ReactFormState | null;
19
20
  onCaughtError?: HydrateRootCaughtErrorHandler;
21
+ onRecoverableError?: HydrateRootRecoverableErrorHandler;
20
22
  onUncaughtError: HydrateRootUncaughtErrorHandler;
21
23
  }): HydrateRootOptions;
22
24
  declare function hydrateRootInTransition(options: {
@@ -8,6 +8,7 @@ function consumeInitialFormState(global) {
8
8
  function createVinextHydrateRootOptions(options) {
9
9
  const hydrateOptions = {
10
10
  formState: options.formState,
11
+ ...options.onRecoverableError ? { onRecoverableError: options.onRecoverableError } : {},
11
12
  onUncaughtError: options.onUncaughtError
12
13
  };
13
14
  if (options.onCaughtError) return {