vinext 0.1.6 → 0.1.8

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 (114) hide show
  1. package/dist/build/client-build-config.d.ts +4 -6
  2. package/dist/build/client-build-config.js +27 -7
  3. package/dist/build/prerender.js +1 -2
  4. package/dist/check.d.ts +18 -0
  5. package/dist/check.js +37 -17
  6. package/dist/cli.js +2 -2
  7. package/dist/config/next-config.d.ts +2 -1
  8. package/dist/config/next-config.js +3 -0
  9. package/dist/config/server-external-packages.d.ts +4 -0
  10. package/dist/config/server-external-packages.js +91 -0
  11. package/dist/deploy.d.ts +7 -0
  12. package/dist/deploy.js +25 -18
  13. package/dist/entries/app-rsc-entry.d.ts +2 -1
  14. package/dist/entries/app-rsc-entry.js +89 -20
  15. package/dist/entries/app-rsc-manifest.js +8 -0
  16. package/dist/entries/pages-client-entry.js +1 -0
  17. package/dist/entries/pages-server-entry.js +1 -0
  18. package/dist/index.js +87 -34
  19. package/dist/init.js +2 -1
  20. package/dist/plugins/middleware-server-only.d.ts +8 -6
  21. package/dist/plugins/middleware-server-only.js +8 -7
  22. package/dist/plugins/og-assets.js +6 -6
  23. package/dist/plugins/optimize-imports.js +1 -1
  24. package/dist/plugins/remove-console.js +1 -1
  25. package/dist/plugins/strip-server-exports.js +2 -1
  26. package/dist/routing/app-route-graph.d.ts +6 -2
  27. package/dist/routing/app-route-graph.js +61 -13
  28. package/dist/routing/app-router.d.ts +5 -0
  29. package/dist/routing/app-router.js +5 -0
  30. package/dist/routing/file-matcher.d.ts +5 -0
  31. package/dist/routing/file-matcher.js +7 -1
  32. package/dist/server/app-action-request.d.ts +4 -0
  33. package/dist/server/app-action-request.js +9 -0
  34. package/dist/server/app-bfcache-identity.d.ts +12 -2
  35. package/dist/server/app-bfcache-identity.js +52 -23
  36. package/dist/server/app-browser-entry.js +42 -147
  37. package/dist/server/app-browser-history-controller.d.ts +2 -1
  38. package/dist/server/app-browser-history-controller.js +6 -2
  39. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  40. package/dist/server/app-browser-server-action-client.js +128 -0
  41. package/dist/server/app-fallback-renderer.d.ts +3 -1
  42. package/dist/server/app-fallback-renderer.js +6 -2
  43. package/dist/server/app-history-state.d.ts +1 -2
  44. package/dist/server/app-history-state.js +1 -1
  45. package/dist/server/app-page-boundary-render.d.ts +3 -0
  46. package/dist/server/app-page-boundary-render.js +14 -3
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +8 -2
  49. package/dist/server/app-page-dispatch.d.ts +33 -4
  50. package/dist/server/app-page-dispatch.js +62 -90
  51. package/dist/server/app-page-element-builder.d.ts +7 -1
  52. package/dist/server/app-page-element-builder.js +56 -19
  53. package/dist/server/app-page-head.d.ts +16 -1
  54. package/dist/server/app-page-head.js +44 -22
  55. package/dist/server/app-page-method.js +1 -1
  56. package/dist/server/app-page-params.d.ts +2 -1
  57. package/dist/server/app-page-params.js +8 -1
  58. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  59. package/dist/server/app-page-ppr-runtime.js +70 -0
  60. package/dist/server/app-page-probe.d.ts +1 -0
  61. package/dist/server/app-page-probe.js +1 -1
  62. package/dist/server/app-page-render.d.ts +4 -1
  63. package/dist/server/app-page-render.js +8 -3
  64. package/dist/server/app-page-request.d.ts +8 -1
  65. package/dist/server/app-page-request.js +23 -11
  66. package/dist/server/app-page-route-wiring.d.ts +6 -1
  67. package/dist/server/app-page-route-wiring.js +30 -8
  68. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  69. package/dist/server/app-page-search-params-observation.js +11 -7
  70. package/dist/server/app-page-stream.js +2 -1
  71. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  72. package/dist/server/app-route-handler-cache.js +1 -1
  73. package/dist/server/app-route-handler-dispatch.js +3 -2
  74. package/dist/server/app-route-handler-execution.js +5 -3
  75. package/dist/server/app-route-handler-policy.d.ts +1 -1
  76. package/dist/server/app-route-handler-policy.js +1 -6
  77. package/dist/server/app-route-module-loader.d.ts +2 -0
  78. package/dist/server/app-route-module-loader.js +1 -0
  79. package/dist/server/app-router-entry.js +7 -6
  80. package/dist/server/app-rsc-errors.d.ts +12 -1
  81. package/dist/server/app-rsc-errors.js +29 -3
  82. package/dist/server/app-rsc-handler.d.ts +15 -13
  83. package/dist/server/app-rsc-handler.js +28 -33
  84. package/dist/server/app-rsc-response-finalizer.js +5 -1
  85. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  86. package/dist/server/app-rsc-route-matching.js +36 -3
  87. package/dist/server/app-segment-config.d.ts +1 -0
  88. package/dist/server/app-segment-config.js +32 -2
  89. package/dist/server/app-server-action-execution.d.ts +4 -0
  90. package/dist/server/app-server-action-execution.js +42 -11
  91. package/dist/server/app-ssr-entry.js +11 -6
  92. package/dist/server/app-static-generation.d.ts +1 -0
  93. package/dist/server/app-static-generation.js +1 -0
  94. package/dist/server/headers.d.ts +3 -1
  95. package/dist/server/headers.js +3 -1
  96. package/dist/server/metadata-route-response.d.ts +1 -1
  97. package/dist/server/prod-server.js +15 -6
  98. package/dist/server/worker-utils.d.ts +2 -1
  99. package/dist/server/worker-utils.js +7 -1
  100. package/dist/shims/dynamic.js +1 -1
  101. package/dist/shims/error-boundary.d.ts +19 -1
  102. package/dist/shims/error-boundary.js +11 -1
  103. package/dist/shims/headers.d.ts +3 -1
  104. package/dist/shims/headers.js +16 -5
  105. package/dist/shims/link.js +16 -12
  106. package/dist/shims/metadata.d.ts +3 -2
  107. package/dist/shims/metadata.js +8 -4
  108. package/dist/shims/router.js +13 -2
  109. package/dist/typegen.js +6 -5
  110. package/dist/utils/path.d.ts +2 -1
  111. package/dist/utils/path.js +1 -1
  112. package/dist/utils/project.d.ts +4 -0
  113. package/dist/utils/project.js +5 -1
  114. package/package.json +7 -3
@@ -1,5 +1,4 @@
1
- import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RSC_REDIRECT_HEADER } from "./headers.js";
2
- import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
1
+ import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RSC_REDIRECT_HEADER } from "./headers.js";
3
2
  import { AppElementsWire } from "./app-elements-wire.js";
4
3
  import { APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI } from "./app-rsc-render-mode.js";
5
4
  import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
@@ -14,7 +13,7 @@ import { DevRecoveryBoundary, GlobalErrorBoundary, RedirectBoundary } from "../s
14
13
  import { beginAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
15
14
  import { AppRouterScrollCommitProvider } from "../shims/app-router-scroll.js";
16
15
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
17
- import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
16
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, createRscRequestHeaders, createRscRequestUrl, getVinextRscCompatibilityId } from "./app-rsc-cache-busting.js";
18
17
  import { getNavigationRuntime, registerNavigationRuntimeBootstrap, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
19
18
  import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
20
19
  import "../client/instrumentation-client.js";
@@ -25,26 +24,23 @@ import { blockDangerousStreamedRscRedirect } from "./app-browser-rsc-redirect.js
25
24
  import { navigationPlanner } from "./navigation-planner.js";
26
25
  import { __basePath, appRouterInstance, commitClientNavigationState, consumePrefetchResponseForNavigation, createCachedRscResponseSnapshot, createClientNavigationRenderSnapshot, createSnapshotPathAndSearch, getClientNavigationRenderContext, getPrefetchCache, hasPrefetchCacheEntryForNavigation, invalidatePrefetchCache, pushHistoryStateWithoutNotify, replaceClientParamsWithoutNotify, replaceHistoryStateWithoutNotify, resolvePrefetchCacheEntryMountedSlotsHeader, restoreRscResponse, saveScrollPosition, setClientParams, setMountedSlotsHeader, setPendingPathname, useRouter } from "../shims/navigation.js";
27
26
  import { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap } from "./app-bfcache-identity.js";
28
- import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot, createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
27
+ import { createDiscardedServerActionRefreshScheduler, createServerActionInitiationSnapshot } from "./app-browser-action-result.js";
29
28
  import { createClientReuseManifestHeaderFromVisibleAppState } from "./app-browser-client-reuse-manifest.js";
30
29
  import { chunksToReadableStream, createProgressiveRscStream, getVinextBrowserGlobal } from "./app-browser-stream.js";
31
- import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl, resolveServerActionRequestState } from "./app-browser-state.js";
30
+ import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, VISITED_CACHE_APP_NAVIGATION_PAYLOAD_ORIGIN, isCacheRestorableAppPayloadMetadata, resolveInterceptionContextFromPreviousNextUrl } from "./app-browser-state.js";
32
31
  import { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch } from "./app-browser-navigation-controller.js";
33
- import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
34
32
  import { consumeInitialFormState, createVinextHydrateRootOptions, hydrateRootInTransition } from "./app-browser-hydration.js";
35
33
  import { AppBrowserHistoryController } from "./app-browser-history-controller.js";
36
34
  import { createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh } from "./app-visited-response-cache.js";
37
35
  import { createPopstateRestoreHandler, restoreSynchronousPopstateScrollPosition } from "./app-browser-popstate.js";
38
36
  import { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnRecoverableError } from "./app-browser-error.js";
39
- import { dismissOverlay } from "./dev-error-overlay-store.js";
40
- import { devOnCaughtError, installDevErrorOverlay, installViteHmrErrorHandler, reportInitialDevServerErrors } from "./dev-error-overlay.js";
41
- import { throwOnServerActionNotFound } from "./server-action-not-found.js";
42
37
  import { createOptimisticRouteTemplate, getOptimisticPrefetchSourceKey, getOptimisticRouteTemplateKey, resolveOptimisticNavigationPayload } from "./app-optimistic-routing.js";
43
38
  import { removeStylesheetLinksCoveredByInlineCss } from "./app-inline-css-client.js";
44
39
  import { createElement, startTransition, use, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
45
40
  import { flushSync } from "react-dom";
46
- import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "@vitejs/plugin-rsc/browser";
41
+ import { createFromFetch, createFromReadableStream, setServerCallback } from "@vitejs/plugin-rsc/browser";
47
42
  import { createRoot, hydrateRoot } from "react-dom/client";
43
+ import { hasServerActions, loadServerActionClient } from "virtual:vinext-app-capabilities";
48
44
  //#region src/server/app-browser-entry.ts
49
45
  function toActionType(kind) {
50
46
  return kind === "traverse" ? "traverse" : "navigate";
@@ -94,10 +90,14 @@ const browserNavigationController = createAppBrowserNavigationController({
94
90
  getRouteManifest: getBrowserRouteManifest,
95
91
  syncHistoryStatePreviousNextUrl: (previousNextUrl, bfcacheIds) => historyController.syncCurrentHistoryStatePreviousNextUrl(previousNextUrl, bfcacheIds)
96
92
  });
97
- const discardedServerActionRefreshScheduler = createDiscardedServerActionRefreshScheduler({ runRefresh() {
93
+ const discardedServerActionRefreshScheduler = hasServerActions ? createDiscardedServerActionRefreshScheduler({ runRefresh() {
98
94
  clearClientNavigationCaches();
99
95
  getNavigationRuntime()?.functions.navigate?.(window.location.href, 0, "refresh", void 0, void 0, true);
100
- } });
96
+ } }) : {
97
+ markNavigationSettled() {},
98
+ markNavigationStart() {},
99
+ schedule() {}
100
+ };
101
101
  const NavigationCommitSignal = browserNavigationController.NavigationCommitSignal;
102
102
  const ACTION_HTTP_FALLBACK_ROBOTS_META_ATTR = "data-vinext-action-http-fallback";
103
103
  function syncServerActionHttpFallbackHead(status) {
@@ -303,52 +303,6 @@ async function renderNavigationPayload(payload, navigationSnapshot, targetHref,
303
303
  visibleCommitMode
304
304
  });
305
305
  }
306
- function resolveActionRedirectTarget(response) {
307
- const actionRedirect = response.headers.get(ACTION_REDIRECT_HEADER);
308
- if (!actionRedirect) return null;
309
- if (isDangerousScheme(actionRedirect)) {
310
- console.error(DANGEROUS_URL_BLOCK_MESSAGE);
311
- return null;
312
- }
313
- try {
314
- let redirectUrl;
315
- if (actionRedirect.startsWith("/") || /^[a-z]+:/i.test(actionRedirect)) redirectUrl = new URL(actionRedirect, window.location.href);
316
- else {
317
- const baseParsed = new URL(window.location.href);
318
- let baseDir = baseParsed.pathname;
319
- if (!baseDir.endsWith("/")) baseDir = baseDir + "/";
320
- redirectUrl = new URL(actionRedirect, `${baseParsed.origin}${baseDir}${baseParsed.search}`);
321
- }
322
- if (redirectUrl.origin !== window.location.origin) {
323
- browserNavigationController.performHardNavigation(actionRedirect);
324
- return null;
325
- }
326
- const statusHeader = response.headers.get(ACTION_REDIRECT_STATUS_HEADER);
327
- const status = statusHeader ? parseInt(statusHeader, 10) : 307;
328
- return {
329
- href: redirectUrl.href,
330
- type: response.headers.get("x-action-redirect-type") ?? "push",
331
- status
332
- };
333
- } catch {
334
- browserNavigationController.performHardNavigation(actionRedirect);
335
- return null;
336
- }
337
- }
338
- var ServerActionRedirectError = class extends Error {
339
- digest;
340
- handled = true;
341
- constructor(target) {
342
- super("NEXT_REDIRECT");
343
- const redirectUrl = new URL(target.href, window.location.href);
344
- const redirectHref = redirectUrl.pathname + redirectUrl.search + redirectUrl.hash;
345
- const redirectType = target.type === "push" ? "push" : "replace";
346
- this.digest = `NEXT_REDIRECT;${redirectType};${encodeURIComponent(redirectHref)};${target.status};`;
347
- }
348
- };
349
- function createServerActionRedirectError(target) {
350
- return new ServerActionRedirectError(target);
351
- }
352
306
  async function commitSameUrlNavigatePayload(nextElements, actionInitiation, returnValue, revalidation = "none") {
353
307
  const navigationSnapshot = createClientNavigationRenderSnapshot(actionInitiation.href, actionInitiation.routerState.navigationSnapshot.params);
354
308
  return browserNavigationController.commitSameUrlNavigatePayload(nextElements, navigationSnapshot, returnValue, actionInitiation.routerState, {
@@ -709,112 +663,53 @@ function applyRuntimeRscBootstrap(rsc) {
709
663
  if (rsc.nav) restoreHydrationNavigationContext(rsc.nav.pathname, rsc.nav.searchParams, params);
710
664
  }
711
665
  function registerServerActionCallback() {
712
- const serverActionCallback = async (id, args) => {
713
- syncServerActionHttpFallbackHead(null);
714
- const temporaryReferences = createTemporaryReferenceSet();
666
+ setServerCallback((id, args) => {
667
+ const releaseCacheInvalidationGuard = historyController.beginCacheInvalidationGuard();
715
668
  const actionInitiation = createActionInitiationSnapshot();
716
- historyController.syncCurrentHistoryStatePreviousNextUrl(actionInitiation.routerState.previousNextUrl, actionInitiation.routerState.bfcacheIds);
717
- const body = await encodeReply(args, { temporaryReferences });
718
- const { headers } = resolveServerActionRequestState({
719
- actionId: id,
669
+ return loadServerActionClient().then(({ invokeClientServerAction }) => invokeClientServerAction(id, args, actionInitiation, {
720
670
  basePath: __basePath,
721
- elements: actionInitiation.routerState.elements,
722
- previousNextUrl: actionInitiation.routerState.previousNextUrl
723
- });
724
- const fetchResponse = await fetch(createServerActionRequestUrl(actionInitiation.path), {
725
- method: "POST",
726
- headers,
727
- body
728
- });
729
- throwOnServerActionNotFound(fetchResponse, id);
730
- const hasActionRedirect = fetchResponse.headers.has(ACTION_REDIRECT_HEADER);
731
- const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse);
732
- if (hasActionRedirect && !actionRedirectTarget) return;
733
- const actionResultFacts = createServerActionResultFacts({
734
- actionRedirectHref: actionRedirectTarget?.href ?? null,
735
- actionRedirectType: actionRedirectTarget?.type ?? null,
736
- clientCompatibilityId: CLIENT_RSC_COMPATIBILITY_ID,
737
- compatibilityIdHeader: fetchResponse.headers.get(VINEXT_RSC_COMPATIBILITY_ID_HEADER),
738
- contentTypeHeader: fetchResponse.headers.get("content-type"),
739
- currentHref: actionInitiation.href,
740
- origin: window.location.origin,
741
- responseUrl: fetchResponse.url
742
- });
743
- const fetchResponseIsRsc = actionResultFacts.isRscContentType;
744
- if (applyServerActionResultDecision(navigationPlanner.classifyServerActionResult(actionResultFacts), clearClientNavigationCaches, (url, historyMode) => browserNavigationController.performHardNavigation(url, historyMode))) return;
745
- const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
746
- if (revalidation !== "none") clearClientNavigationCaches();
747
- const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
748
- if (invalidResponseError) throw invalidResponseError;
749
- if (actionRedirectTarget && !fetchResponseIsRsc) {
750
- browserNavigationController.performHardNavigation(actionRedirectTarget.href);
751
- return;
752
- }
753
- const flightResponse = fetchResponse.status === 303 ? new Response(fetchResponse.body, {
754
- headers: fetchResponse.headers,
755
- status: 200,
756
- statusText: "OK"
757
- }) : fetchResponse;
758
- const result = await createFromFetch(Promise.resolve(flightResponse), { temporaryReferences });
759
- if (revalidation === "none" && shouldClearClientNavigationCachesForServerActionResult(result, revalidation)) clearClientNavigationCaches();
760
- if (actionRedirectTarget) {
761
- if (isServerActionResult(result) && result.root !== void 0) {
762
- const decoded = AppElementsWire.decode(result.root);
763
- const hashIdx = actionRedirectTarget.href.indexOf("#");
764
- const actionScrollIntent = beginAppRouterScrollIntent((hashIdx !== -1 ? actionRedirectTarget.href.slice(hashIdx) : "") || null);
765
- if (actionRedirectTarget.type === "push") saveScrollPosition();
766
- renderNavigationPayload(Promise.resolve(decoded), createClientNavigationRenderSnapshot(actionRedirectTarget.href, actionInitiation.routerState.navigationSnapshot.params), actionRedirectTarget.href, actionInitiation.navigationId, actionRedirectTarget.type === "push" ? "push" : "replace", {}, null, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, actionRedirectTarget.type === "push" ? "navigate" : "replace", "server-action", null, actionScrollIntent).catch(() => {
767
- browserNavigationController.performHardNavigation(actionRedirectTarget.href);
671
+ clearClientNavigationCaches,
672
+ clientRscCompatibilityId: CLIENT_RSC_COMPATIBILITY_ID,
673
+ commitSameUrlNavigatePayload,
674
+ navigationPlanner,
675
+ performHardNavigation: (url, historyMode) => browserNavigationController.performHardNavigation(url, historyMode),
676
+ renderRedirectPayload(elements, target, actionInitiation) {
677
+ const hashIdx = target.href.indexOf("#");
678
+ const actionScrollIntent = beginAppRouterScrollIntent((hashIdx !== -1 ? target.href.slice(hashIdx) : "") || null);
679
+ if (target.type === "push") saveScrollPosition();
680
+ renderNavigationPayload(Promise.resolve(elements), createClientNavigationRenderSnapshot(target.href, actionInitiation.routerState.navigationSnapshot.params), target.href, actionInitiation.navigationId, target.type === "push" ? "push" : "replace", {}, null, null, FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, target.type === "push" ? "navigate" : "replace", "server-action", null, actionScrollIntent).catch(() => {
681
+ browserNavigationController.performHardNavigation(target.href);
768
682
  });
769
- throw createServerActionRedirectError(actionRedirectTarget);
770
- }
771
- browserNavigationController.performHardNavigation(actionRedirectTarget.href);
772
- return;
773
- }
774
- syncServerActionHttpFallbackHead(isServerActionResult(result) && result.root !== void 0 ? null : fetchResponse.status);
775
- if (isServerActionResult(result)) {
776
- if (result.root !== void 0) {
777
- const returnValue = result.returnValue && !result.returnValue.ok ? {
778
- ok: false,
779
- data: normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status)
780
- } : result.returnValue;
781
- return commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result.root)), actionInitiation, returnValue, revalidation);
782
- }
783
- if (result.returnValue) {
784
- if (!result.returnValue.ok) throw normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status);
785
- return result.returnValue.data;
786
- }
787
- return;
788
- }
789
- return commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result)), actionInitiation, void 0, revalidation);
790
- };
791
- setServerCallback((id, args) => {
792
- const releaseCacheInvalidationGuard = historyController.beginCacheInvalidationGuard();
793
- return Promise.resolve().then(() => serverActionCallback(id, args)).finally(releaseCacheInvalidationGuard);
683
+ },
684
+ syncCurrentHistoryState: (previousNextUrl, bfcacheIds) => historyController.syncCurrentHistoryStatePreviousNextUrl(previousNextUrl, bfcacheIds),
685
+ syncServerActionHttpFallbackHead
686
+ })).finally(releaseCacheInvalidationGuard);
794
687
  });
795
688
  }
796
689
  async function main() {
797
690
  if (!claimInitialAppRouterBootstrap()) return;
798
- registerServerActionCallback();
691
+ if (hasServerActions) registerServerActionCallback();
799
692
  installAppNavigationFailureListeners();
693
+ let devErrorOverlay = null;
800
694
  if (import.meta.env.DEV) {
801
- installDevErrorOverlay();
802
- installViteHmrErrorHandler(import.meta.hot);
803
- reportInitialDevServerErrors();
695
+ devErrorOverlay = await import("./dev-error-overlay.js");
696
+ devErrorOverlay.installDevErrorOverlay();
697
+ devErrorOverlay.installViteHmrErrorHandler(import.meta.hot);
698
+ devErrorOverlay.reportInitialDevServerErrors();
804
699
  }
805
700
  const rscStream = await readInitialRscStream();
806
701
  if (rscStream === null) return;
807
- bootstrapHydration(rscStream);
702
+ bootstrapHydration(rscStream, devErrorOverlay);
808
703
  }
809
- function bootstrapHydration(rscStream) {
704
+ function bootstrapHydration(rscStream, devErrorOverlay) {
810
705
  const root = decodeAppElementsPromise(createFromReadableStream(rscStream));
811
706
  const initialNavigationSnapshot = createClientNavigationRenderSnapshot(window.location.href, latestClientParams);
812
707
  historyController.writeBootstrapHistoryMetadata();
813
708
  const onUncaughtError = createOnUncaughtError();
814
709
  const formState = consumeInitialFormState(getVinextBrowserGlobal());
815
- const hydrateRootOptions = import.meta.env.DEV ? createVinextHydrateRootOptions({
710
+ const hydrateRootOptions = import.meta.env.DEV && devErrorOverlay ? createVinextHydrateRootOptions({
816
711
  formState,
817
- onCaughtError: createDevOnCaughtError(devOnCaughtError, onUncaughtError),
712
+ onCaughtError: createDevOnCaughtError(devErrorOverlay.devOnCaughtError, onUncaughtError),
818
713
  onUncaughtError
819
714
  }) : createVinextHydrateRootOptions({
820
715
  formState,
@@ -1141,7 +1036,7 @@ function bootstrapHydration(rscStream) {
1141
1036
  restorePopstateScrollPosition
1142
1037
  }, event.state);
1143
1038
  });
1144
- if (import.meta.hot) {
1039
+ if (import.meta.env.DEV && import.meta.hot) {
1145
1040
  const applyRscHmrUpdate = async (updateId) => {
1146
1041
  if (updateId !== latestRscHmrUpdateId) return;
1147
1042
  if (document.documentElement.id === "__next_error__") {
@@ -1157,7 +1052,7 @@ function bootstrapHydration(rscStream) {
1157
1052
  if (!browserNavigationController.hasBrowserRouterState()) return;
1158
1053
  clearClientNavigationCaches();
1159
1054
  const navigationSnapshot = createClientNavigationRenderSnapshot(window.location.href, latestClientParams);
1160
- dismissOverlay();
1055
+ devErrorOverlay?.dismissOverlay();
1161
1056
  const hmrHeaders = createRscRequestHeaders();
1162
1057
  await browserNavigationController.hmrReplaceTree(decodeAppElementsPromise(createFromFetch(fetch(await createRscRequestUrl(window.location.pathname + window.location.search, hmrHeaders), { headers: hmrHeaders }))), navigationSnapshot);
1163
1058
  };
@@ -45,6 +45,7 @@ type CommitNavigationHistoryOptions = {
45
45
  targetHistoryIndex?: number | null;
46
46
  stageClientParams: () => void;
47
47
  };
48
+ declare function createCanonicalBrowserHistoryHref(href: string): string;
48
49
  /**
49
50
  * Owns App Router browser-history metadata and traversal bookkeeping behind a
50
51
  * typed seam: traversal index allocation/commit, push/replace/traverse/hash-only
@@ -101,4 +102,4 @@ declare class AppBrowserHistoryController {
101
102
  restoreHistorySnapshot(options: RestoreHistorySnapshotOptions): boolean;
102
103
  }
103
104
  //#endregion
104
- export { AppBrowserHistoryController, RestorableSnapshotCandidate };
105
+ export { AppBrowserHistoryController, RestorableSnapshotCandidate, createCanonicalBrowserHistoryHref };
@@ -1,5 +1,9 @@
1
1
  import { RestorableClientStateController, createHistoryStateWithNavigationMetadata, readHistoryStateBfcacheIds, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
2
2
  //#region src/server/app-browser-history-controller.ts
3
+ function createCanonicalBrowserHistoryHref(href) {
4
+ const url = new URL(href);
5
+ return `${url.pathname}${url.search}${url.hash}`;
6
+ }
3
7
  function stripVinextScrollState(state) {
4
8
  if (!state || typeof state !== "object") return state;
5
9
  const nextState = {};
@@ -166,7 +170,7 @@ var AppBrowserHistoryController = class {
166
170
  this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
167
171
  previousNextUrl: null,
168
172
  traversalIndex: this.#currentHistoryTraversalIndex
169
- }), this.#readCurrentHref());
173
+ }), createCanonicalBrowserHistoryHref(this.#readCurrentHref()));
170
174
  }
171
175
  /** History write performed on the first committed (hydrated) render. */
172
176
  writeHydratedHistoryMetadata(options) {
@@ -207,4 +211,4 @@ function areBfcacheIdMapsEqual(a, b) {
207
211
  return aEntries.every(([key, value]) => b[key] === value);
208
212
  }
209
213
  //#endregion
210
- export { AppBrowserHistoryController };
214
+ export { AppBrowserHistoryController, createCanonicalBrowserHistoryHref };
@@ -0,0 +1,32 @@
1
+ import { AppElements, AppWireElements } from "./app-elements-wire.js";
2
+ import { navigationPlanner } from "./navigation-planner.js";
3
+ import { AppBrowserServerActionResult, ServerActionRevalidationKind } from "./app-browser-action-result.js";
4
+ import { AppRouterState } from "./app-browser-state.js";
5
+
6
+ //#region src/server/app-browser-server-action-client.d.ts
7
+ type ServerActionResult = AppBrowserServerActionResult<AppWireElements>;
8
+ type ClientServerActionInitiation = {
9
+ href: string;
10
+ navigationId: number;
11
+ path: string;
12
+ routerState: AppRouterState;
13
+ };
14
+ type ActionRedirectTarget = {
15
+ href: string;
16
+ type: string;
17
+ status: number;
18
+ };
19
+ type ClientServerActionDeps = {
20
+ basePath: string;
21
+ clearClientNavigationCaches(): void;
22
+ clientRscCompatibilityId: string | null;
23
+ commitSameUrlNavigatePayload(elements: Promise<AppElements>, actionInitiation: ClientServerActionInitiation, returnValue: ServerActionResult["returnValue"] | undefined, revalidation: ServerActionRevalidationKind): Promise<unknown>;
24
+ navigationPlanner: typeof navigationPlanner;
25
+ performHardNavigation(url: string, historyMode?: "assign" | "replace"): void;
26
+ renderRedirectPayload(elements: AppElements, target: ActionRedirectTarget, actionInitiation: ClientServerActionInitiation): void;
27
+ syncCurrentHistoryState(previousNextUrl: string | null, bfcacheIds: Readonly<Record<string, string>>): void;
28
+ syncServerActionHttpFallbackHead(status: number | null): void;
29
+ };
30
+ declare function invokeClientServerAction(id: string, args: unknown[], actionInitiation: ClientServerActionInitiation, deps: ClientServerActionDeps): Promise<unknown>;
31
+ //#endregion
32
+ export { ClientServerActionDeps, ClientServerActionInitiation, invokeClientServerAction };
@@ -0,0 +1,128 @@
1
+ import { ACTION_REDIRECT_HEADER, ACTION_REDIRECT_STATUS_HEADER } from "./headers.js";
2
+ import { DANGEROUS_URL_BLOCK_MESSAGE, isDangerousScheme } from "../shims/url-safety.js";
3
+ import { AppElementsWire } from "./app-elements-wire.js";
4
+ import "./app-elements.js";
5
+ import { VINEXT_RSC_COMPATIBILITY_ID_HEADER, createServerActionRequestUrl } from "./app-rsc-cache-busting.js";
6
+ import { createServerActionResultFacts, isServerActionResult, normalizeServerActionThrownValue, parseServerActionRevalidationHeader, readInvalidServerActionResponseError, shouldClearClientNavigationCachesForServerActionResult } from "./app-browser-action-result.js";
7
+ import { resolveServerActionRequestState } from "./app-browser-state.js";
8
+ import { applyServerActionResultDecision } from "./app-browser-server-action-navigation.js";
9
+ import { throwOnServerActionNotFound } from "./server-action-not-found.js";
10
+ import { createFromFetch, createTemporaryReferenceSet, encodeReply } from "@vitejs/plugin-rsc/browser";
11
+ //#region src/server/app-browser-server-action-client.ts
12
+ function resolveActionRedirectTarget(response, performHardNavigation) {
13
+ const actionRedirect = response.headers.get(ACTION_REDIRECT_HEADER);
14
+ if (!actionRedirect) return null;
15
+ if (isDangerousScheme(actionRedirect)) {
16
+ console.error(DANGEROUS_URL_BLOCK_MESSAGE);
17
+ return null;
18
+ }
19
+ try {
20
+ let redirectUrl;
21
+ if (actionRedirect.startsWith("/") || /^[a-z]+:/i.test(actionRedirect)) redirectUrl = new URL(actionRedirect, window.location.href);
22
+ else {
23
+ const baseParsed = new URL(window.location.href);
24
+ let baseDir = baseParsed.pathname;
25
+ if (!baseDir.endsWith("/")) baseDir += "/";
26
+ redirectUrl = new URL(actionRedirect, `${baseParsed.origin}${baseDir}${baseParsed.search}`);
27
+ }
28
+ if (redirectUrl.origin !== window.location.origin) {
29
+ performHardNavigation(actionRedirect);
30
+ return null;
31
+ }
32
+ const statusHeader = response.headers.get(ACTION_REDIRECT_STATUS_HEADER);
33
+ return {
34
+ href: redirectUrl.href,
35
+ type: response.headers.get("x-action-redirect-type") ?? "push",
36
+ status: statusHeader ? parseInt(statusHeader, 10) : 307
37
+ };
38
+ } catch {
39
+ performHardNavigation(actionRedirect);
40
+ return null;
41
+ }
42
+ }
43
+ var ServerActionRedirectError = class extends Error {
44
+ digest;
45
+ handled = true;
46
+ constructor(target) {
47
+ super("NEXT_REDIRECT");
48
+ const redirectUrl = new URL(target.href, window.location.href);
49
+ const redirectHref = redirectUrl.pathname + redirectUrl.search + redirectUrl.hash;
50
+ const redirectType = target.type === "push" ? "push" : "replace";
51
+ this.digest = `NEXT_REDIRECT;${redirectType};${encodeURIComponent(redirectHref)};${target.status};`;
52
+ }
53
+ };
54
+ async function invokeClientServerAction(id, args, actionInitiation, deps) {
55
+ deps.syncServerActionHttpFallbackHead(null);
56
+ const temporaryReferences = createTemporaryReferenceSet();
57
+ deps.syncCurrentHistoryState(actionInitiation.routerState.previousNextUrl, actionInitiation.routerState.bfcacheIds);
58
+ const body = await encodeReply(args, { temporaryReferences });
59
+ const headers = resolveServerActionRequestState({
60
+ actionId: id,
61
+ basePath: deps.basePath,
62
+ elements: actionInitiation.routerState.elements,
63
+ previousNextUrl: actionInitiation.routerState.previousNextUrl
64
+ }).headers;
65
+ const fetchResponse = await fetch(createServerActionRequestUrl(actionInitiation.path), {
66
+ method: "POST",
67
+ headers,
68
+ body
69
+ });
70
+ throwOnServerActionNotFound(fetchResponse, id);
71
+ const hasActionRedirect = fetchResponse.headers.has(ACTION_REDIRECT_HEADER);
72
+ const actionRedirectTarget = resolveActionRedirectTarget(fetchResponse, (url, historyMode) => deps.performHardNavigation(url, historyMode));
73
+ if (hasActionRedirect && !actionRedirectTarget) return void 0;
74
+ const actionResultFacts = createServerActionResultFacts({
75
+ actionRedirectHref: actionRedirectTarget?.href ?? null,
76
+ actionRedirectType: actionRedirectTarget?.type ?? null,
77
+ clientCompatibilityId: deps.clientRscCompatibilityId,
78
+ compatibilityIdHeader: fetchResponse.headers.get(VINEXT_RSC_COMPATIBILITY_ID_HEADER),
79
+ contentTypeHeader: fetchResponse.headers.get("content-type"),
80
+ currentHref: actionInitiation.href,
81
+ origin: window.location.origin,
82
+ responseUrl: fetchResponse.url
83
+ });
84
+ const fetchResponseIsRsc = actionResultFacts.isRscContentType;
85
+ if (applyServerActionResultDecision(deps.navigationPlanner.classifyServerActionResult(actionResultFacts), () => deps.clearClientNavigationCaches(), (url, historyMode) => deps.performHardNavigation(url, historyMode))) return;
86
+ const revalidation = parseServerActionRevalidationHeader(fetchResponse.headers);
87
+ if (revalidation !== "none") deps.clearClientNavigationCaches();
88
+ const invalidResponseError = await readInvalidServerActionResponseError(fetchResponse.clone(), actionRedirectTarget !== null);
89
+ if (invalidResponseError) throw invalidResponseError;
90
+ if (actionRedirectTarget && !fetchResponseIsRsc) {
91
+ deps.performHardNavigation(actionRedirectTarget.href);
92
+ return;
93
+ }
94
+ const flightResponse = fetchResponse.status === 303 ? new Response(fetchResponse.body, {
95
+ headers: fetchResponse.headers,
96
+ status: 200,
97
+ statusText: "OK"
98
+ }) : fetchResponse;
99
+ const result = await createFromFetch(Promise.resolve(flightResponse), { temporaryReferences });
100
+ if (revalidation === "none" && shouldClearClientNavigationCachesForServerActionResult(result, revalidation)) deps.clearClientNavigationCaches();
101
+ if (actionRedirectTarget) {
102
+ if (isServerActionResult(result) && result.root !== void 0) {
103
+ deps.renderRedirectPayload(AppElementsWire.decode(result.root), actionRedirectTarget, actionInitiation);
104
+ throw new ServerActionRedirectError(actionRedirectTarget);
105
+ }
106
+ deps.performHardNavigation(actionRedirectTarget.href);
107
+ return;
108
+ }
109
+ const hasSameUrlRerenderPayload = isServerActionResult(result) && result.root !== void 0;
110
+ deps.syncServerActionHttpFallbackHead(hasSameUrlRerenderPayload ? null : fetchResponse.status);
111
+ if (isServerActionResult(result)) {
112
+ if (result.root !== void 0) {
113
+ const returnValue = result.returnValue && !result.returnValue.ok ? {
114
+ ok: false,
115
+ data: normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status)
116
+ } : result.returnValue;
117
+ return deps.commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result.root)), actionInitiation, returnValue, revalidation);
118
+ }
119
+ if (result.returnValue) {
120
+ if (!result.returnValue.ok) throw normalizeServerActionThrownValue(result.returnValue.data, fetchResponse.status);
121
+ return result.returnValue.data;
122
+ }
123
+ return;
124
+ }
125
+ return deps.commitSameUrlNavigatePayload(Promise.resolve(AppElementsWire.decode(result)), actionInitiation, void 0, revalidation);
126
+ }
127
+ //#endregion
128
+ export { invokeClientServerAction };
@@ -4,6 +4,7 @@ import { NavigationContext } from "../shims/navigation-context-state.js";
4
4
  import { AppPageParams } from "./app-page-boundary.js";
5
5
  import { AppPageFontPreload } from "./app-page-execution.js";
6
6
  import { AppPageMiddlewareContext } from "./app-page-response.js";
7
+ import { ApplyAppPageFileBasedMetadata } from "./app-page-head.js";
7
8
  import { AppPageSsrHandler } from "./app-page-stream.js";
8
9
  import { AppPageBoundaryRoute } from "./app-page-boundary-render.js";
9
10
  import { ReactNode } from "react";
@@ -27,6 +28,7 @@ type AppFallbackRendererFontProviders = {
27
28
  getFontStyles: () => string[];
28
29
  };
29
30
  type AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> = {
31
+ applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
30
32
  clearRequestContext: () => void;
31
33
  createRscOnErrorHandler: (request: Request, pathname: string, routePath: string) => AppPageBoundaryOnError;
32
34
  fontProviders: AppFallbackRendererFontProviders;
@@ -73,7 +75,7 @@ type AppFallbackRendererCallContext = {
73
75
  sourcePageSegments?: readonly string[] | null;
74
76
  };
75
77
  type AppFallbackRenderer<TModule extends AppPageModule = AppPageModule> = {
76
- renderErrorBoundary: (route: AppPageBoundaryRoute<TModule> | null, error: unknown, isRscRequest: boolean, request: Request, matchedParams: AppPageParams | undefined, scriptNonce: string | undefined, middlewareContext: AppPageMiddlewareContext, callContext?: AppFallbackRendererCallContext) => Promise<Response | null>;
78
+ renderErrorBoundary: (route: AppPageBoundaryRoute<TModule> | null, error: unknown, isRscRequest: boolean, request: Request, matchedParams: AppPageParams | undefined, scriptNonce: string | undefined, middlewareContext: AppPageMiddlewareContext, callContext?: AppFallbackRendererCallContext, errorOrigin?: "rsc" | "ssr") => Promise<Response | null>;
77
79
  renderHttpAccessFallback: (route: AppPageBoundaryRoute<TModule> | null, statusCode: number, isRscRequest: boolean, request: Request, opts: {
78
80
  boundaryComponent?: AppPageComponent | null;
79
81
  boundaryModule?: TModule | null;
@@ -7,7 +7,7 @@ const EMPTY_MW_CTX = {
7
7
  status: null
8
8
  };
9
9
  function createAppFallbackRenderer(options) {
10
- const { basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader, trailingSlash } = options;
10
+ const { applyFileBasedMetadata, basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader, trailingSlash } = options;
11
11
  const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } = rootBoundaries;
12
12
  const effectiveGlobalErrorModule = globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE;
13
13
  const effectiveRootNotFoundModule = rootNotFoundModule ?? DEFAULT_NOT_FOUND_MODULE;
@@ -23,6 +23,7 @@ function createAppFallbackRenderer(options) {
23
23
  const globalNotFoundModule = await resolveGlobalNotFoundModule();
24
24
  const globalNotFoundComponent = globalNotFoundModule?.default ?? null;
25
25
  if (globalNotFoundComponent) return renderAppPageHttpAccessFallback({
26
+ applyFileBasedMetadata,
26
27
  boundaryComponent: globalNotFoundComponent,
27
28
  boundaryModule: globalNotFoundModule ?? null,
28
29
  buildFontLinkHeader: fontProviders.buildFontLinkHeader,
@@ -57,6 +58,7 @@ function createAppFallbackRenderer(options) {
57
58
  });
58
59
  }
59
60
  return renderAppPageHttpAccessFallback({
61
+ applyFileBasedMetadata,
60
62
  basePath,
61
63
  trailingSlash,
62
64
  boundaryComponent: opts?.boundaryComponent ?? null,
@@ -95,8 +97,9 @@ function createAppFallbackRenderer(options) {
95
97
  renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext) {
96
98
  return this.renderHttpAccessFallback(route, 404, isRscRequest, request, { matchedParams }, scriptNonce, middlewareContext, callContext);
97
99
  },
98
- renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext) {
100
+ renderErrorBoundary(route, error, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, callContext, errorOrigin = "rsc") {
99
101
  return renderAppPageErrorBoundary({
102
+ applyFileBasedMetadata,
100
103
  basePath,
101
104
  trailingSlash,
102
105
  buildFontLinkHeader: fontProviders.buildFontLinkHeader,
@@ -105,6 +108,7 @@ function createAppFallbackRenderer(options) {
105
108
  return buildRscOnErrorHandler(request, pathname, routePath);
106
109
  },
107
110
  error,
111
+ errorOrigin,
108
112
  getFontLinks: fontProviders.getFontLinks,
109
113
  getFontPreloads: fontProviders.getFontPreloads,
110
114
  getFontStyles: fontProviders.getFontStyles,
@@ -63,7 +63,6 @@ declare function createHistoryStateWithNavigationMetadata(state: unknown, metada
63
63
  }): HistoryStateRecord | null;
64
64
  declare function createExternalHistoryStatePreservingMetadata(callerState: unknown, currentHistoryState: unknown): unknown;
65
65
  declare function readHistoryStatePreviousNextUrl(state: unknown): string | null;
66
- declare function isBfcacheSegmentId(id: string): boolean;
67
66
  declare function readHistoryStateBfcacheIds(state: unknown): BfcacheIdMap | null;
68
67
  declare function readHistoryStateBfcacheVersion(state: unknown): number | null;
69
68
  /**
@@ -83,4 +82,4 @@ declare function resolveHistoryTraversalIntent(options: {
83
82
  historyState: unknown;
84
83
  }): HistoryTraversalIntent;
85
84
  //#endregion
86
- export { BfcacheIdMap, HistoryStateSnapshotCache, HistoryTraversalIntent, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
85
+ export { BfcacheIdMap, HistoryStateSnapshotCache, HistoryTraversalIntent, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
@@ -220,4 +220,4 @@ function resolveHistoryTraversalIntent(options) {
220
220
  };
221
221
  }
222
222
  //#endregion
223
- export { HistoryStateSnapshotCache, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isBfcacheSegmentId, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
223
+ export { HistoryStateSnapshotCache, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
@@ -4,6 +4,7 @@ import { NavigationContext } from "../shims/navigation-context-state.js";
4
4
  import { AppPageParams } from "./app-page-boundary.js";
5
5
  import { AppPageFontPreload } from "./app-page-execution.js";
6
6
  import { AppPageMiddlewareContext } from "./app-page-response.js";
7
+ import { ApplyAppPageFileBasedMetadata } from "./app-page-head.js";
7
8
  import { AppPageSsrHandler } from "./app-page-stream.js";
8
9
  import { ComponentType, ReactNode } from "react";
9
10
 
@@ -27,6 +28,7 @@ type AppPageBoundaryRoute<TModule extends AppPageModule = AppPageModule> = {
27
28
  unauthorized?: TModule | null;
28
29
  };
29
30
  type AppPageBoundaryRenderCommonOptions<TModule extends AppPageModule = AppPageModule> = {
31
+ applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
30
32
  buildFontLinkHeader: (preloads: readonly AppPageFontPreload[] | null | undefined) => string;
31
33
  clearRequestContext: () => void;
32
34
  createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;
@@ -73,6 +75,7 @@ type RenderAppPageHttpAccessFallbackOptions<TModule extends AppPageModule = AppP
73
75
  } & AppPageBoundaryRenderCommonOptions<TModule>;
74
76
  type RenderAppPageErrorBoundaryOptions<TModule extends AppPageModule = AppPageModule> = {
75
77
  error: unknown;
78
+ errorOrigin?: "rsc" | "ssr";
76
79
  matchedParams?: AppPageParams | null;
77
80
  route?: AppPageBoundaryRoute<TModule> | null;
78
81
  sanitizeErrorForClient: (error: Error) => Error;