vinext 0.0.47 → 0.0.49
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.
- package/README.md +1 -1
- package/dist/build/layout-classification.js +3 -1
- package/dist/build/layout-classification.js.map +1 -1
- package/dist/build/prerender.js +10 -10
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/report.d.ts +8 -4
- package/dist/build/report.js +17 -7
- package/dist/build/report.js.map +1 -1
- package/dist/build/run-prerender.d.ts +5 -0
- package/dist/build/run-prerender.js +4 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/server-manifest.js +2 -7
- package/dist/build/server-manifest.js.map +1 -1
- package/dist/build/standalone.js +3 -5
- package/dist/build/standalone.js.map +1 -1
- package/dist/check.js +45 -29
- package/dist/check.js.map +1 -1
- package/dist/cli-args.d.ts +3 -1
- package/dist/cli-args.js +18 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +9 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/config-matchers.js +46 -37
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/deploy.d.ts +18 -2
- package/dist/deploy.js +47 -4
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +11 -9
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.js +4 -1
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.js +3 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +21 -62
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +12 -3
- package/dist/entries/runtime-entry-module.js +15 -4
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +12 -7
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +2 -2
- package/dist/init.js.map +1 -1
- package/dist/plugins/og-assets.js +15 -16
- package/dist/plugins/og-assets.js.map +1 -1
- package/dist/plugins/rsc-client-shim-excludes.d.ts +2 -1
- package/dist/plugins/rsc-client-shim-excludes.js +10 -1
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -1
- package/dist/routing/app-route-graph.d.ts +90 -4
- package/dist/routing/app-route-graph.js +210 -7
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +15 -3
- package/dist/routing/app-router.js +20 -23
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +3 -1
- package/dist/routing/file-matcher.js +6 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.js +10 -19
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-matching.d.ts +28 -0
- package/dist/routing/route-matching.js +44 -0
- package/dist/routing/route-matching.js.map +1 -0
- package/dist/routing/route-pattern.js +4 -1
- package/dist/routing/route-pattern.js.map +1 -1
- package/dist/routing/route-trie.d.ts +8 -0
- package/dist/routing/route-trie.js +12 -1
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/route-validation.js +3 -4
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +8 -1
- package/dist/routing/utils.js +25 -2
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +2 -8
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-entry.js +66 -49
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +7 -5
- package/dist/server/app-browser-navigation-controller.js +43 -35
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +33 -15
- package/dist/server/app-browser-state.js +52 -59
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-visible-commit.d.ts +68 -0
- package/dist/server/app-browser-visible-commit.js +182 -0
- package/dist/server/app-browser-visible-commit.js.map +1 -0
- package/dist/server/app-client-reference-preloader.d.ts +15 -0
- package/dist/server/app-client-reference-preloader.js +46 -0
- package/dist/server/app-client-reference-preloader.js.map +1 -0
- package/dist/server/app-elements-wire.d.ts +130 -0
- package/dist/server/app-elements-wire.js +205 -0
- package/dist/server/app-elements-wire.js.map +1 -0
- package/dist/server/app-elements.d.ts +2 -84
- package/dist/server/app-elements.js +3 -102
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +1 -1
- package/dist/server/app-middleware.d.ts +2 -1
- package/dist/server/app-middleware.js +34 -11
- package/dist/server/app-middleware.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -1
- package/dist/server/app-page-boundary-render.js +8 -5
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +1 -0
- package/dist/server/app-page-cache.js +8 -13
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +2 -1
- package/dist/server/app-page-dispatch.js +18 -10
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +1 -1
- package/dist/server/app-page-element-builder.js +8 -5
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +23 -5
- package/dist/server/app-page-execution.js +39 -24
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.js +2 -1
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-method.js +2 -5
- package/dist/server/app-page-method.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +1 -1
- package/dist/server/app-page-probe.js +5 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +38 -3
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +7 -10
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +3 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +5 -2
- package/dist/server/app-page-route-wiring.js +15 -12
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +7 -0
- package/dist/server/app-page-stream.js +9 -2
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-prerender-endpoints.js +3 -2
- package/dist/server/app-prerender-endpoints.js.map +1 -1
- package/dist/server/app-route-handler-cache.js +2 -1
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.js +6 -5
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-policy.js +13 -13
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.js +2 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +9 -1
- package/dist/server/app-route-handler-runtime.js +11 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js +9 -4
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +34 -0
- package/dist/server/app-rsc-cache-busting.js +137 -0
- package/dist/server/app-rsc-cache-busting.js.map +1 -0
- package/dist/server/app-rsc-handler.js +22 -11
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +4 -2
- package/dist/server/app-rsc-request-normalization.js +10 -6
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.js +8 -4
- package/dist/server/app-rsc-route-matching.js.map +1 -1
- package/dist/server/app-segment-config.js +4 -0
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.js +43 -51
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.js +21 -20
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/artifact-compatibility.d.ts +44 -0
- package/dist/server/artifact-compatibility.js +82 -0
- package/dist/server/artifact-compatibility.js.map +1 -0
- package/dist/server/cache-proof.d.ts +200 -0
- package/dist/server/cache-proof.js +342 -0
- package/dist/server/cache-proof.js.map +1 -0
- package/dist/server/dev-origin-check.js +8 -4
- package/dist/server/dev-origin-check.js.map +1 -1
- package/dist/server/dev-server.js +6 -16
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/http-error-responses.d.ts +67 -0
- package/dist/server/http-error-responses.js +77 -0
- package/dist/server/http-error-responses.js.map +1 -0
- package/dist/server/image-optimization.js +2 -1
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/metadata-route-response.js +6 -5
- package/dist/server/metadata-route-response.js.map +1 -1
- package/dist/server/metadata-routes.d.ts +1 -0
- package/dist/server/metadata-routes.js +6 -0
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.js +2 -2
- package/dist/server/middleware-matcher.js.map +1 -1
- package/dist/server/middleware-response-headers.js +21 -0
- package/dist/server/middleware-response-headers.js.map +1 -1
- package/dist/server/middleware-runtime.js +3 -3
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/navigation-trace.d.ts +33 -0
- package/dist/server/navigation-trace.js +35 -0
- package/dist/server/navigation-trace.js.map +1 -0
- package/dist/server/next-error-digest.d.ts +44 -0
- package/dist/server/next-error-digest.js +40 -0
- package/dist/server/next-error-digest.js.map +1 -0
- package/dist/server/pages-api-route.js +4 -7
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-node-compat.js +4 -16
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +2 -8
- package/dist/server/pages-page-response.js +44 -14
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.d.ts +6 -0
- package/dist/server/prod-server.js +28 -21
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +42 -1
- package/dist/server/request-pipeline.js +97 -17
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +2 -2
- package/dist/shims/cache-runtime.js +3 -6
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.js +3 -5
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/fetch-cache.js +2 -3
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.js +2 -3
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/headers.js +4 -44
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-state.js +2 -3
- package/dist/shims/i18n-state.js.map +1 -1
- package/dist/shims/internal/als-registry.d.ts +15 -0
- package/dist/shims/internal/als-registry.js +55 -0
- package/dist/shims/internal/als-registry.js.map +1 -0
- package/dist/shims/internal/cookie-serialize.d.ts +46 -0
- package/dist/shims/internal/cookie-serialize.js +51 -0
- package/dist/shims/internal/cookie-serialize.js.map +1 -0
- package/dist/shims/link.js +31 -26
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +26 -1
- package/dist/shims/metadata.js +94 -4
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.js +2 -3
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +2 -7
- package/dist/shims/navigation.js +44 -36
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.js +2 -4
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/router-state.js +2 -3
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.js +2 -2
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.js +5 -30
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/slot.d.ts +1 -1
- package/dist/shims/slot.js +5 -4
- package/dist/shims/slot.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -2
- package/dist/shims/thenable-params.js +26 -6
- package/dist/shims/thenable-params.js.map +1 -1
- package/dist/shims/unified-request-context.js +2 -14
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/utils/base-path.d.ts +7 -1
- package/dist/utils/base-path.js +12 -1
- package/dist/utils/base-path.js.map +1 -1
- package/dist/utils/query.d.ts +8 -1
- package/dist/utils/query.js +12 -1
- package/dist/utils/query.js.map +1 -1
- package/dist/utils/safe-json-file.d.ts +18 -0
- package/dist/utils/safe-json-file.js +25 -0
- package/dist/utils/safe-json-file.js.map +1 -0
- package/dist/utils/text-stream.d.ts +29 -0
- package/dist/utils/text-stream.js +66 -0
- package/dist/utils/text-stream.js.map +1 -0
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientNavigationRenderSnapshot, commitClientNavigationState } from "../shims/navigation.js";
|
|
2
|
-
import { AppElements } from "./app-elements.js";
|
|
3
|
-
import { AppRouterState } from "./app-browser-state.js";
|
|
2
|
+
import { AppElements } from "./app-elements-wire.js";
|
|
3
|
+
import { AppRouterState, OperationLane } from "./app-browser-state.js";
|
|
4
4
|
import { Dispatch, ReactNode } from "react";
|
|
5
5
|
|
|
6
6
|
//#region src/server/app-browser-navigation-controller.d.ts
|
|
@@ -10,6 +10,7 @@ type PendingBrowserRouterState = {
|
|
|
10
10
|
resolve: (state: AppRouterState) => void;
|
|
11
11
|
settled: boolean;
|
|
12
12
|
};
|
|
13
|
+
type NavigationPayloadOutcome = "committed" | "no-commit" | "hard-navigate";
|
|
13
14
|
type BrowserNavigationCommitEffectFactory = (options: {
|
|
14
15
|
href: string;
|
|
15
16
|
historyUpdateMode: HistoryUpdateMode | undefined;
|
|
@@ -38,17 +39,18 @@ type BrowserNavigationController = {
|
|
|
38
39
|
historyUpdateMode: HistoryUpdateMode | undefined;
|
|
39
40
|
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
40
41
|
nextElements: Promise<AppElements>;
|
|
42
|
+
operationLane: OperationLane;
|
|
41
43
|
params: Record<string, string | string[]>;
|
|
42
44
|
pendingRouterState: PendingBrowserRouterState | null;
|
|
43
45
|
previousNextUrl: string | null;
|
|
44
46
|
targetHref: string;
|
|
45
47
|
navId: number;
|
|
46
48
|
useTransition?: boolean;
|
|
47
|
-
}): Promise<
|
|
49
|
+
}): Promise<NavigationPayloadOutcome>;
|
|
48
50
|
commitSameUrlNavigatePayload(nextElements: Promise<AppElements>, navigationSnapshot: ClientNavigationRenderSnapshot, returnValue?: {
|
|
49
51
|
ok: boolean;
|
|
50
52
|
data: unknown;
|
|
51
|
-
}): Promise<unknown>;
|
|
53
|
+
}, actionInitiationState?: AppRouterState): Promise<unknown>;
|
|
52
54
|
hmrReplaceTree(nextElements: Promise<AppElements>, navigationSnapshot: ClientNavigationRenderSnapshot): Promise<void>;
|
|
53
55
|
/**
|
|
54
56
|
* Force-drain the queued pre-paint effect for the given renderId without
|
|
@@ -69,5 +71,5 @@ type BrowserNavigationController = {
|
|
|
69
71
|
};
|
|
70
72
|
declare function createAppBrowserNavigationController(deps?: BrowserNavigationControllerDeps): BrowserNavigationController;
|
|
71
73
|
//#endregion
|
|
72
|
-
export { HistoryUpdateMode, PendingBrowserRouterState, createAppBrowserNavigationController };
|
|
74
|
+
export { HistoryUpdateMode, NavigationPayloadOutcome, PendingBrowserRouterState, createAppBrowserNavigationController };
|
|
73
75
|
//# sourceMappingURL=app-browser-navigation-controller.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState } from "../shims/navigation.js";
|
|
2
|
-
import { createPendingNavigationCommit
|
|
2
|
+
import { createPendingNavigationCommit } from "./app-browser-state.js";
|
|
3
|
+
import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
|
|
3
4
|
import { startTransition, useLayoutEffect } from "react";
|
|
4
5
|
//#region src/server/app-browser-navigation-controller.ts
|
|
5
6
|
function createAppBrowserNavigationController(deps = {}) {
|
|
@@ -80,10 +81,10 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
80
81
|
settlePendingBrowserRouterState(pending);
|
|
81
82
|
if (isCurrentNavigation(navId)) clearPendingPathname(navId);
|
|
82
83
|
}
|
|
83
|
-
function resolvePendingBrowserRouterState(pending,
|
|
84
|
+
function resolvePendingBrowserRouterState(pending, commit) {
|
|
84
85
|
if (!pending || pending.settled) return;
|
|
85
86
|
pending.settled = true;
|
|
86
|
-
pending.resolve(
|
|
87
|
+
pending.resolve(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
|
|
87
88
|
if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
|
|
88
89
|
}
|
|
89
90
|
function queuePrePaintNavigationEffect(renderId, effect) {
|
|
@@ -128,11 +129,12 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
128
129
|
currentState: getBrowserRouterState(),
|
|
129
130
|
nextElements,
|
|
130
131
|
navigationSnapshot,
|
|
132
|
+
operationLane: "hmr",
|
|
131
133
|
renderId: allocateRenderId(),
|
|
132
134
|
type: "replace"
|
|
133
135
|
});
|
|
134
136
|
if (!hasBrowserRouterState()) return;
|
|
135
|
-
|
|
137
|
+
dispatchApprovedVisibleCommit(approveHmrVisibleCommit(pending), null, false);
|
|
136
138
|
}
|
|
137
139
|
function NavigationCommitSignal({ renderId, children }) {
|
|
138
140
|
useLayoutEffect(() => {
|
|
@@ -147,25 +149,14 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
147
149
|
}, [renderId]);
|
|
148
150
|
return children;
|
|
149
151
|
}
|
|
150
|
-
function
|
|
152
|
+
function dispatchApprovedVisibleCommit(commit, pendingRouterState, useTransitionMode) {
|
|
151
153
|
const setter = getBrowserRouterStateSetter();
|
|
152
|
-
const action = {
|
|
153
|
-
elements,
|
|
154
|
-
interceptionContext,
|
|
155
|
-
layoutFlags,
|
|
156
|
-
navigationSnapshot,
|
|
157
|
-
previousNextUrl,
|
|
158
|
-
renderId,
|
|
159
|
-
rootLayoutTreePath,
|
|
160
|
-
routeId,
|
|
161
|
-
type: actionType
|
|
162
|
-
};
|
|
163
154
|
const applyAction = () => {
|
|
164
155
|
if (pendingRouterState) {
|
|
165
|
-
resolvePendingBrowserRouterState(pendingRouterState,
|
|
156
|
+
resolvePendingBrowserRouterState(pendingRouterState, commit);
|
|
166
157
|
return;
|
|
167
158
|
}
|
|
168
|
-
setter(
|
|
159
|
+
setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
|
|
169
160
|
};
|
|
170
161
|
if (useTransitionMode) startTransition(applyAction);
|
|
171
162
|
else applyAction();
|
|
@@ -179,43 +170,45 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
179
170
|
});
|
|
180
171
|
let snapshotActivated = false;
|
|
181
172
|
try {
|
|
182
|
-
const currentState = getBrowserRouterState();
|
|
183
173
|
const pending = await createPendingNavigationCommit({
|
|
184
|
-
currentState,
|
|
174
|
+
currentState: getBrowserRouterState(),
|
|
185
175
|
nextElements: options.nextElements,
|
|
186
176
|
navigationSnapshot: options.navigationSnapshot,
|
|
177
|
+
operationLane: options.operationLane,
|
|
187
178
|
previousNextUrl: options.previousNextUrl,
|
|
188
179
|
renderId,
|
|
189
180
|
type: options.actionType
|
|
190
181
|
});
|
|
191
|
-
const
|
|
182
|
+
const approval = approvePendingNavigationCommit({
|
|
192
183
|
activeNavigationId,
|
|
193
|
-
|
|
194
|
-
|
|
184
|
+
currentState: getBrowserRouterState(),
|
|
185
|
+
pending,
|
|
195
186
|
startedNavigationId: options.navId
|
|
196
187
|
});
|
|
197
|
-
if (disposition === "
|
|
188
|
+
if (approval.decision.disposition === "no-commit") {
|
|
198
189
|
settlePendingBrowserRouterState(options.pendingRouterState);
|
|
199
190
|
pendingNavigationCommits.delete(renderId);
|
|
200
191
|
resolveCommitted?.();
|
|
201
|
-
return;
|
|
192
|
+
return "no-commit";
|
|
202
193
|
}
|
|
203
|
-
if (disposition === "hard-navigate") {
|
|
194
|
+
if (approval.decision.disposition === "hard-navigate") {
|
|
204
195
|
settlePendingBrowserRouterState(options.pendingRouterState);
|
|
205
196
|
pendingNavigationCommits.delete(renderId);
|
|
206
197
|
window.location.assign(options.targetHref);
|
|
207
|
-
return;
|
|
198
|
+
return "hard-navigate";
|
|
208
199
|
}
|
|
200
|
+
const approvedCommit = approval.approvedCommit;
|
|
201
|
+
if (approvedCommit === null) throw new Error("[vinext] Commit decision did not approve a visible commit");
|
|
209
202
|
queuePrePaintNavigationEffect(renderId, options.createNavigationCommitEffect({
|
|
210
203
|
href: options.targetHref,
|
|
211
204
|
historyUpdateMode: options.historyUpdateMode,
|
|
212
205
|
navId: options.navId,
|
|
213
206
|
params: options.params,
|
|
214
|
-
previousNextUrl:
|
|
207
|
+
previousNextUrl: approvedCommit.previousNextUrl
|
|
215
208
|
}));
|
|
216
209
|
activateNavigationSnapshot();
|
|
217
210
|
snapshotActivated = true;
|
|
218
|
-
|
|
211
|
+
dispatchApprovedVisibleCommit(approvedCommit, options.pendingRouterState, options.useTransition ?? true);
|
|
219
212
|
} catch (error) {
|
|
220
213
|
pendingNavigationPrePaintEffects.delete(renderId);
|
|
221
214
|
pendingNavigationCommits.delete(renderId);
|
|
@@ -224,25 +217,40 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
224
217
|
resolveCommitted?.();
|
|
225
218
|
throw error;
|
|
226
219
|
}
|
|
227
|
-
return committed;
|
|
220
|
+
return committed.then(() => "committed");
|
|
228
221
|
}
|
|
229
|
-
async function commitSameUrlNavigatePayload(nextElements, navigationSnapshot, returnValue) {
|
|
230
|
-
const currentState = getBrowserRouterState();
|
|
222
|
+
async function commitSameUrlNavigatePayload(nextElements, navigationSnapshot, returnValue, actionInitiationState) {
|
|
223
|
+
const currentState = actionInitiationState ?? getBrowserRouterState();
|
|
231
224
|
const startedNavigationId = activeNavigationId;
|
|
232
|
-
const {
|
|
225
|
+
const { approvedCommit, decision, pending, trace: _navigationTrace } = await resolveAndClassifyNavigationCommit({
|
|
233
226
|
activeNavigationId,
|
|
234
227
|
currentState,
|
|
228
|
+
getActiveNavigationId: () => activeNavigationId,
|
|
229
|
+
getCurrentStateForApproval: getBrowserRouterState,
|
|
235
230
|
navigationSnapshot,
|
|
236
231
|
nextElements,
|
|
237
232
|
renderId: allocateRenderId(),
|
|
233
|
+
operationLane: "server-action",
|
|
238
234
|
startedNavigationId,
|
|
239
235
|
type: "navigate"
|
|
240
236
|
});
|
|
241
|
-
if (disposition === "hard-navigate") {
|
|
237
|
+
if (decision.disposition === "hard-navigate") {
|
|
242
238
|
window.location.assign(window.location.href);
|
|
243
239
|
return;
|
|
244
240
|
}
|
|
245
|
-
if (
|
|
241
|
+
if (approvedCommit) {
|
|
242
|
+
const latestApproval = approvePendingNavigationCommit({
|
|
243
|
+
activeNavigationId,
|
|
244
|
+
currentState: getBrowserRouterState(),
|
|
245
|
+
pending,
|
|
246
|
+
startedNavigationId
|
|
247
|
+
});
|
|
248
|
+
if (latestApproval.decision.disposition === "hard-navigate") {
|
|
249
|
+
window.location.assign(window.location.href);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (latestApproval.approvedCommit) dispatchApprovedVisibleCommit(latestApproval.approvedCommit, null, false);
|
|
253
|
+
}
|
|
246
254
|
if (returnValue) {
|
|
247
255
|
if (!returnValue.ok) throw returnValue.data;
|
|
248
256
|
return returnValue.data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-browser-navigation-controller.js","names":[],"sources":["../../src/server/app-browser-navigation-controller.ts"],"sourcesContent":["import { startTransition, useLayoutEffect, type Dispatch, type ReactNode } from \"react\";\nimport {\n activateNavigationSnapshot,\n clearPendingPathname,\n commitClientNavigationState,\n} from \"vinext/shims/navigation\";\nimport type { ClientNavigationRenderSnapshot } from \"vinext/shims/navigation\";\nimport {\n createPendingNavigationCommit,\n resolveAndClassifyNavigationCommit,\n resolvePendingNavigationCommitDisposition,\n routerReducer,\n type AppRouterAction,\n type AppRouterState,\n} from \"./app-browser-state.js\";\nimport type { AppElements, LayoutFlags } from \"./app-elements.js\";\n\nexport type HistoryUpdateMode = \"push\" | \"replace\";\n\nexport type PendingBrowserRouterState = {\n promise: Promise<AppRouterState>;\n resolve: (state: AppRouterState) => void;\n settled: boolean;\n};\n\ntype BrowserNavigationCommitEffectFactory = (options: {\n href: string;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navId: number;\n params: Record<string, string | string[]>;\n previousNextUrl: string | null;\n}) => () => void;\n\ntype BrowserRouterStateRef = {\n current: AppRouterState;\n};\n\ntype BrowserNavigationControllerDeps = {\n commitClientNavigationState?: typeof commitClientNavigationState;\n};\n\ntype BrowserNavigationController = {\n beginNavigation(): number;\n hasBrowserRouterState(): boolean;\n getBrowserRouterState(): AppRouterState;\n isCurrentNavigation(navId: number): boolean;\n waitForBrowserRouterStateReady(): Promise<void>;\n attachBrowserRouterState(\n setter: Dispatch<AppRouterState | Promise<AppRouterState>>,\n stateRef: BrowserRouterStateRef,\n ): () => void;\n beginPendingBrowserRouterState(): PendingBrowserRouterState;\n finalizeNavigation(navId: number, pending: PendingBrowserRouterState | null | undefined): void;\n renderNavigationPayload(options: {\n actionType: \"navigate\" | \"replace\" | \"traverse\";\n createNavigationCommitEffect: BrowserNavigationCommitEffectFactory;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navigationSnapshot: ClientNavigationRenderSnapshot;\n nextElements: Promise<AppElements>;\n params: Record<string, string | string[]>;\n pendingRouterState: PendingBrowserRouterState | null;\n previousNextUrl: string | null;\n targetHref: string;\n navId: number;\n useTransition?: boolean;\n }): Promise<void>;\n commitSameUrlNavigatePayload(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n returnValue?: { ok: boolean; data: unknown },\n ): Promise<unknown>;\n hmrReplaceTree(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n ): Promise<void>;\n /**\n * Force-drain the queued pre-paint effect for the given renderId without\n * waiting for NavigationCommitSignal to commit. Used by the dev recovery\n * boundary in app-browser-entry.ts: when a render error replaces\n * NavigationCommitSignal with the boundary's null fallback, its\n * useLayoutEffect never fires, so the URL update for the in-flight\n * navigation would otherwise be lost.\n */\n drainPrePaintEffects(renderId: number): void;\n NavigationCommitSignal(\n this: void,\n {\n renderId,\n children,\n }: {\n renderId: number;\n children?: ReactNode;\n },\n ): ReactNode;\n};\n\nexport function createAppBrowserNavigationController(\n deps: BrowserNavigationControllerDeps = {},\n): BrowserNavigationController {\n const commitClientNavigationStateImpl =\n deps.commitClientNavigationState ?? commitClientNavigationState;\n\n // These are plain module-level variables (inside the controller closure),\n // unlike ClientNavigationState which uses Symbol.for to survive multiple\n // Vite module instances. The browser entry is loaded exactly once (via the\n // RSC plugin's generated bootstrap), so the controller running in a single\n // module instance is safe. If that assumption ever changes, these should be\n // migrated to a Symbol.for-backed global.\n //\n // The most severe consequence of multiple instances would be Map fragmentation:\n // pendingNavigationCommits and pendingNavigationPrePaintEffects would split\n // across instances, so drainPrePaintEffects in one instance could never drain\n // effects queued by the other, permanently leaking navigationSnapshotActiveCount\n // and causing hooks to prefer stale snapshot values indefinitely.\n let nextNavigationRenderId = 0;\n let activeNavigationId = 0;\n const pendingNavigationCommits = new Map<number, () => void>();\n const pendingNavigationPrePaintEffects = new Map<number, () => void>();\n\n let setBrowserRouterState: Dispatch<AppRouterState | Promise<AppRouterState>> | null = null;\n let browserRouterStateRef: BrowserRouterStateRef | null = null;\n let activePendingBrowserRouterState: PendingBrowserRouterState | null = null;\n let resolveBrowserRouterStateReady: (() => void) | null = null;\n let browserRouterStateReadyPromise: Promise<void> | null = null;\n let browserRouterStateHasCommitted = false;\n\n function getBrowserRouterStateSetter(): Dispatch<AppRouterState | Promise<AppRouterState>> {\n if (!setBrowserRouterState) {\n throw new Error(\"[vinext] Browser router state setter is not initialized\");\n }\n return setBrowserRouterState;\n }\n\n function getBrowserRouterState(): AppRouterState {\n if (!browserRouterStateRef) {\n throw new Error(\"[vinext] Browser router state is not initialized\");\n }\n return browserRouterStateRef.current;\n }\n\n function waitForBrowserRouterStateReady(): Promise<void> {\n if (browserRouterStateRef || browserRouterStateHasCommitted) {\n return Promise.resolve();\n }\n\n if (!browserRouterStateReadyPromise) {\n browserRouterStateReadyPromise = new Promise((resolve) => {\n resolveBrowserRouterStateReady = resolve;\n });\n }\n\n return browserRouterStateReadyPromise;\n }\n\n function markBrowserRouterStateReady(): void {\n browserRouterStateHasCommitted = true;\n const resolveReady = resolveBrowserRouterStateReady;\n resolveBrowserRouterStateReady = null;\n browserRouterStateReadyPromise = null;\n resolveReady?.();\n }\n\n function beginNavigation(): number {\n activeNavigationId += 1;\n return activeNavigationId;\n }\n\n function allocateRenderId(): number {\n nextNavigationRenderId += 1;\n return nextNavigationRenderId;\n }\n\n function hasBrowserRouterState(): boolean {\n return browserRouterStateRef !== null;\n }\n\n function isCurrentNavigation(navId: number): boolean {\n return navId === activeNavigationId;\n }\n\n function beginPendingBrowserRouterState(): PendingBrowserRouterState {\n const setter = getBrowserRouterStateSetter();\n\n if (activePendingBrowserRouterState && !activePendingBrowserRouterState.settled) {\n activePendingBrowserRouterState.settled = true;\n activePendingBrowserRouterState.resolve(getBrowserRouterState());\n }\n\n let resolvePending: ((state: AppRouterState) => void) | undefined;\n const promise = new Promise<AppRouterState>((resolve) => {\n resolvePending = resolve;\n });\n\n if (!resolvePending) {\n throw new Error(\"[vinext] Failed to initialize browser router promise\");\n }\n\n const pending: PendingBrowserRouterState = {\n promise,\n resolve: resolvePending,\n settled: false,\n };\n\n activePendingBrowserRouterState = pending;\n setter(promise);\n\n return pending;\n }\n\n function settlePendingBrowserRouterState(\n pending: PendingBrowserRouterState | null | undefined,\n ): void {\n if (!pending || pending.settled) return;\n\n pending.settled = true;\n pending.resolve(getBrowserRouterState());\n\n if (activePendingBrowserRouterState === pending) {\n activePendingBrowserRouterState = null;\n }\n }\n\n function finalizeNavigation(\n navId: number,\n pending: PendingBrowserRouterState | null | undefined,\n ): void {\n settlePendingBrowserRouterState(pending);\n\n if (isCurrentNavigation(navId)) {\n clearPendingPathname(navId);\n }\n }\n\n function resolvePendingBrowserRouterState(\n pending: PendingBrowserRouterState | null | undefined,\n action: AppRouterAction,\n ): void {\n if (!pending || pending.settled) return;\n\n pending.settled = true;\n pending.resolve(routerReducer(getBrowserRouterState(), action));\n\n if (activePendingBrowserRouterState === pending) {\n activePendingBrowserRouterState = null;\n }\n }\n\n function queuePrePaintNavigationEffect(renderId: number, effect: (() => void) | null): void {\n if (!effect) {\n return;\n }\n pendingNavigationPrePaintEffects.set(renderId, effect);\n }\n\n /**\n * Run all queued pre-paint effects for renderIds up to and including the\n * given renderId. When React supersedes a startTransition update (rapid\n * clicks on same-route links), the superseded NavigationCommitSignal never\n * mounts, so its pre-paint effect never fires. By draining all effects\n * <= the committed renderId here, the winning transition cleans up after\n * any superseded ones, keeping the counter balanced.\n *\n * Invariant: each superseded navigation gets a commitClientNavigationState()\n * to balance the activateNavigationSnapshot() from its renderNavigationPayload call.\n */\n function drainPrePaintEffects(upToRenderId: number): void {\n for (const [id, effect] of pendingNavigationPrePaintEffects) {\n if (id > upToRenderId) {\n continue;\n }\n\n pendingNavigationPrePaintEffects.delete(id);\n if (id === upToRenderId) {\n effect();\n } else {\n // Superseded navigations still need to balance the snapshot counter.\n commitClientNavigationStateImpl(undefined, { releaseSnapshot: true });\n }\n }\n }\n\n /**\n * Resolve all pending navigation commits with renderId <= the committed renderId.\n * Note: Map iteration handles concurrent deletion safely — entries are visited in\n * insertion order and deletion doesn't affect the iterator's view of remaining entries.\n * This pattern is also used in drainPrePaintEffects with the same semantics.\n */\n function resolveCommittedNavigations(renderId: number): void {\n for (const [pendingId, resolve] of pendingNavigationCommits) {\n if (pendingId > renderId) {\n continue;\n }\n\n pendingNavigationCommits.delete(pendingId);\n resolve();\n }\n }\n\n async function hmrReplaceTree(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n ): Promise<void> {\n if (!hasBrowserRouterState()) return;\n\n const currentState = getBrowserRouterState();\n const renderId = allocateRenderId();\n const pending = await createPendingNavigationCommit({\n currentState,\n nextElements,\n navigationSnapshot,\n renderId,\n type: \"replace\",\n });\n\n // createPendingNavigationCommit awaits the new RSC payload. While\n // suspended, the prior broken render can unmount BrowserRoot. Re-check\n // before dispatching so a racing unmount doesn't surface as an\n // initialized-setter error.\n if (!hasBrowserRouterState()) return;\n\n dispatchBrowserTree(\n pending.action.elements,\n navigationSnapshot,\n pending.action.renderId,\n \"replace\",\n pending.interceptionContext,\n pending.action.layoutFlags,\n pending.previousNextUrl,\n pending.routeId,\n pending.rootLayoutTreePath,\n null,\n false,\n );\n }\n\n function NavigationCommitSignal(\n this: void,\n {\n renderId,\n children,\n }: {\n renderId: number;\n children?: ReactNode;\n },\n ): ReactNode {\n useLayoutEffect(() => {\n drainPrePaintEffects(renderId);\n\n const frame = requestAnimationFrame(() => {\n resolveCommittedNavigations(renderId);\n });\n\n return () => {\n cancelAnimationFrame(frame);\n // Resolve pending commits to prevent callers from hanging if React\n // unmounts this component without committing (e.g., error boundary).\n resolveCommittedNavigations(renderId);\n };\n }, [renderId]);\n\n return children;\n }\n\n function dispatchBrowserTree(\n elements: AppElements,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n renderId: number,\n actionType: \"navigate\" | \"replace\" | \"traverse\",\n interceptionContext: string | null,\n layoutFlags: LayoutFlags,\n previousNextUrl: string | null,\n routeId: string,\n rootLayoutTreePath: string | null,\n pendingRouterState: PendingBrowserRouterState | null,\n useTransitionMode: boolean,\n ): void {\n const setter = getBrowserRouterStateSetter();\n const action: AppRouterAction = {\n elements,\n interceptionContext,\n layoutFlags,\n navigationSnapshot,\n previousNextUrl,\n renderId,\n rootLayoutTreePath,\n routeId,\n type: actionType,\n };\n\n const applyAction = () => {\n if (pendingRouterState) {\n // The programmatic navigation is already running inside React.startTransition\n // (from router.push/replace/refresh), so resolving the deferred promise is\n // sufficient — no additional startTransition wrapper is needed below.\n resolvePendingBrowserRouterState(pendingRouterState, action);\n return;\n }\n\n setter(routerReducer(getBrowserRouterState(), action));\n };\n\n if (useTransitionMode) {\n startTransition(applyAction);\n } else {\n applyAction();\n }\n }\n\n async function renderNavigationPayload(options: {\n actionType: \"navigate\" | \"replace\" | \"traverse\";\n createNavigationCommitEffect: BrowserNavigationCommitEffectFactory;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navigationSnapshot: ClientNavigationRenderSnapshot;\n nextElements: Promise<AppElements>;\n params: Record<string, string | string[]>;\n pendingRouterState: PendingBrowserRouterState | null;\n previousNextUrl: string | null;\n targetHref: string;\n navId: number;\n useTransition?: boolean;\n }): Promise<void> {\n const renderId = allocateRenderId();\n let resolveCommitted: (() => void) | undefined;\n const committed = new Promise<void>((resolve) => {\n resolveCommitted = resolve;\n pendingNavigationCommits.set(renderId, resolve);\n });\n\n let snapshotActivated = false;\n try {\n const currentState = getBrowserRouterState();\n const pending = await createPendingNavigationCommit({\n currentState,\n nextElements: options.nextElements,\n navigationSnapshot: options.navigationSnapshot,\n previousNextUrl: options.previousNextUrl,\n renderId,\n type: options.actionType,\n });\n\n const disposition = resolvePendingNavigationCommitDisposition({\n activeNavigationId,\n currentRootLayoutTreePath: currentState.rootLayoutTreePath,\n nextRootLayoutTreePath: pending.rootLayoutTreePath,\n startedNavigationId: options.navId,\n });\n\n if (disposition === \"skip\") {\n settlePendingBrowserRouterState(options.pendingRouterState);\n pendingNavigationCommits.delete(renderId);\n resolveCommitted?.();\n return;\n }\n\n if (disposition === \"hard-navigate\") {\n settlePendingBrowserRouterState(options.pendingRouterState);\n pendingNavigationCommits.delete(renderId);\n window.location.assign(options.targetHref);\n return;\n }\n\n queuePrePaintNavigationEffect(\n renderId,\n options.createNavigationCommitEffect({\n href: options.targetHref,\n historyUpdateMode: options.historyUpdateMode,\n navId: options.navId,\n params: options.params,\n previousNextUrl: pending.previousNextUrl,\n }),\n );\n activateNavigationSnapshot();\n snapshotActivated = true;\n dispatchBrowserTree(\n pending.action.elements,\n options.navigationSnapshot,\n renderId,\n options.actionType,\n pending.interceptionContext,\n pending.action.layoutFlags,\n pending.previousNextUrl,\n pending.routeId,\n pending.rootLayoutTreePath,\n options.pendingRouterState,\n options.useTransition ?? true,\n );\n } catch (error) {\n pendingNavigationPrePaintEffects.delete(renderId);\n pendingNavigationCommits.delete(renderId);\n if (snapshotActivated) {\n commitClientNavigationStateImpl(options.navId);\n }\n settlePendingBrowserRouterState(options.pendingRouterState);\n resolveCommitted?.();\n throw error;\n }\n\n return committed;\n }\n\n async function commitSameUrlNavigatePayload(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n returnValue?: { ok: boolean; data: unknown },\n ): Promise<unknown> {\n const currentState = getBrowserRouterState();\n const startedNavigationId = activeNavigationId;\n // Known limitation: if a same-URL navigation fully commits while this\n // server action is awaiting resolveAndClassifyNavigationCommit(), the action\n // can still dispatch its older payload afterward. The old pre-2c code had\n // the same race, and Next.js has similar behavior. Tightening this would\n // need a stronger commit-version gate than activeNavigationId alone.\n const { disposition, pending } = await resolveAndClassifyNavigationCommit({\n activeNavigationId,\n currentState,\n navigationSnapshot,\n nextElements,\n renderId: allocateRenderId(),\n startedNavigationId,\n type: \"navigate\",\n });\n\n if (disposition === \"hard-navigate\") {\n window.location.assign(window.location.href);\n return undefined;\n }\n\n if (disposition === \"dispatch\") {\n dispatchBrowserTree(\n pending.action.elements,\n navigationSnapshot,\n pending.action.renderId,\n \"navigate\",\n pending.interceptionContext,\n pending.action.layoutFlags,\n pending.previousNextUrl,\n pending.routeId,\n pending.rootLayoutTreePath,\n null,\n false,\n );\n }\n\n // Same-URL server actions still return their action value even if the UI\n // update was skipped due to a superseding navigation. That preserves the\n // existing caller contract; a future Phase 2 router state model could make\n // skipped UI updates observable to the caller without conflating them here.\n if (returnValue) {\n if (!returnValue.ok) {\n throw returnValue.data;\n }\n return returnValue.data;\n }\n\n return undefined;\n }\n\n function attachBrowserRouterState(\n setter: Dispatch<AppRouterState | Promise<AppRouterState>>,\n stateRef: BrowserRouterStateRef,\n ): () => void {\n setBrowserRouterState = setter;\n browserRouterStateRef = stateRef;\n markBrowserRouterStateReady();\n\n return () => {\n if (setBrowserRouterState === setter) {\n setBrowserRouterState = null;\n }\n if (browserRouterStateRef === stateRef) {\n browserRouterStateRef = null;\n browserRouterStateHasCommitted = false;\n }\n };\n }\n\n return {\n beginNavigation,\n hasBrowserRouterState,\n getBrowserRouterState,\n isCurrentNavigation,\n waitForBrowserRouterStateReady,\n attachBrowserRouterState,\n beginPendingBrowserRouterState,\n finalizeNavigation,\n renderNavigationPayload,\n commitSameUrlNavigatePayload,\n hmrReplaceTree,\n drainPrePaintEffects,\n NavigationCommitSignal,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-browser-navigation-controller.js","names":[],"sources":["../../src/server/app-browser-navigation-controller.ts"],"sourcesContent":["import { startTransition, useLayoutEffect, type Dispatch, type ReactNode } from \"react\";\nimport {\n activateNavigationSnapshot,\n clearPendingPathname,\n commitClientNavigationState,\n} from \"vinext/shims/navigation\";\nimport type { ClientNavigationRenderSnapshot } from \"vinext/shims/navigation\";\nimport {\n createPendingNavigationCommit,\n type AppRouterState,\n type OperationLane,\n} from \"./app-browser-state.js\";\nimport {\n applyApprovedVisibleCommit,\n approveHmrVisibleCommit,\n approvePendingNavigationCommit,\n resolveAndClassifyNavigationCommit,\n type ApprovedVisibleCommit,\n} from \"./app-browser-visible-commit.js\";\nimport type { AppElements } from \"./app-elements.js\";\n\nexport type HistoryUpdateMode = \"push\" | \"replace\";\n\nexport type PendingBrowserRouterState = {\n promise: Promise<AppRouterState>;\n resolve: (state: AppRouterState) => void;\n settled: boolean;\n};\nexport type NavigationPayloadOutcome = \"committed\" | \"no-commit\" | \"hard-navigate\";\n\ntype BrowserNavigationCommitEffectFactory = (options: {\n href: string;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navId: number;\n params: Record<string, string | string[]>;\n previousNextUrl: string | null;\n}) => () => void;\n\ntype BrowserRouterStateRef = {\n current: AppRouterState;\n};\n\ntype BrowserNavigationControllerDeps = {\n commitClientNavigationState?: typeof commitClientNavigationState;\n};\n\ntype BrowserNavigationController = {\n beginNavigation(): number;\n hasBrowserRouterState(): boolean;\n getBrowserRouterState(): AppRouterState;\n isCurrentNavigation(navId: number): boolean;\n waitForBrowserRouterStateReady(): Promise<void>;\n attachBrowserRouterState(\n setter: Dispatch<AppRouterState | Promise<AppRouterState>>,\n stateRef: BrowserRouterStateRef,\n ): () => void;\n beginPendingBrowserRouterState(): PendingBrowserRouterState;\n finalizeNavigation(navId: number, pending: PendingBrowserRouterState | null | undefined): void;\n renderNavigationPayload(options: {\n actionType: \"navigate\" | \"replace\" | \"traverse\";\n createNavigationCommitEffect: BrowserNavigationCommitEffectFactory;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navigationSnapshot: ClientNavigationRenderSnapshot;\n nextElements: Promise<AppElements>;\n operationLane: OperationLane;\n params: Record<string, string | string[]>;\n pendingRouterState: PendingBrowserRouterState | null;\n previousNextUrl: string | null;\n targetHref: string;\n navId: number;\n useTransition?: boolean;\n }): Promise<NavigationPayloadOutcome>;\n commitSameUrlNavigatePayload(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n returnValue?: { ok: boolean; data: unknown },\n actionInitiationState?: AppRouterState,\n ): Promise<unknown>;\n hmrReplaceTree(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n ): Promise<void>;\n /**\n * Force-drain the queued pre-paint effect for the given renderId without\n * waiting for NavigationCommitSignal to commit. Used by the dev recovery\n * boundary in app-browser-entry.ts: when a render error replaces\n * NavigationCommitSignal with the boundary's null fallback, its\n * useLayoutEffect never fires, so the URL update for the in-flight\n * navigation would otherwise be lost.\n */\n drainPrePaintEffects(renderId: number): void;\n NavigationCommitSignal(\n this: void,\n {\n renderId,\n children,\n }: {\n renderId: number;\n children?: ReactNode;\n },\n ): ReactNode;\n};\n\nexport function createAppBrowserNavigationController(\n deps: BrowserNavigationControllerDeps = {},\n): BrowserNavigationController {\n const commitClientNavigationStateImpl =\n deps.commitClientNavigationState ?? commitClientNavigationState;\n\n // These are plain module-level variables (inside the controller closure),\n // unlike ClientNavigationState which uses Symbol.for to survive multiple\n // Vite module instances. The browser entry is loaded exactly once (via the\n // RSC plugin's generated bootstrap), so the controller running in a single\n // module instance is safe. If that assumption ever changes, these should be\n // migrated to a Symbol.for-backed global.\n //\n // The most severe consequence of multiple instances would be Map fragmentation:\n // pendingNavigationCommits and pendingNavigationPrePaintEffects would split\n // across instances, so drainPrePaintEffects in one instance could never drain\n // effects queued by the other, permanently leaking navigationSnapshotActiveCount\n // and causing hooks to prefer stale snapshot values indefinitely.\n let nextNavigationRenderId = 0;\n let activeNavigationId = 0;\n const pendingNavigationCommits = new Map<number, () => void>();\n const pendingNavigationPrePaintEffects = new Map<number, () => void>();\n\n let setBrowserRouterState: Dispatch<AppRouterState | Promise<AppRouterState>> | null = null;\n let browserRouterStateRef: BrowserRouterStateRef | null = null;\n let activePendingBrowserRouterState: PendingBrowserRouterState | null = null;\n let resolveBrowserRouterStateReady: (() => void) | null = null;\n let browserRouterStateReadyPromise: Promise<void> | null = null;\n let browserRouterStateHasCommitted = false;\n\n function getBrowserRouterStateSetter(): Dispatch<AppRouterState | Promise<AppRouterState>> {\n if (!setBrowserRouterState) {\n throw new Error(\"[vinext] Browser router state setter is not initialized\");\n }\n return setBrowserRouterState;\n }\n\n function getBrowserRouterState(): AppRouterState {\n if (!browserRouterStateRef) {\n throw new Error(\"[vinext] Browser router state is not initialized\");\n }\n return browserRouterStateRef.current;\n }\n\n function waitForBrowserRouterStateReady(): Promise<void> {\n if (browserRouterStateRef || browserRouterStateHasCommitted) {\n return Promise.resolve();\n }\n\n if (!browserRouterStateReadyPromise) {\n browserRouterStateReadyPromise = new Promise((resolve) => {\n resolveBrowserRouterStateReady = resolve;\n });\n }\n\n return browserRouterStateReadyPromise;\n }\n\n function markBrowserRouterStateReady(): void {\n browserRouterStateHasCommitted = true;\n const resolveReady = resolveBrowserRouterStateReady;\n resolveBrowserRouterStateReady = null;\n browserRouterStateReadyPromise = null;\n resolveReady?.();\n }\n\n function beginNavigation(): number {\n activeNavigationId += 1;\n return activeNavigationId;\n }\n\n function allocateRenderId(): number {\n nextNavigationRenderId += 1;\n return nextNavigationRenderId;\n }\n\n function hasBrowserRouterState(): boolean {\n return browserRouterStateRef !== null;\n }\n\n function isCurrentNavigation(navId: number): boolean {\n return navId === activeNavigationId;\n }\n\n function beginPendingBrowserRouterState(): PendingBrowserRouterState {\n const setter = getBrowserRouterStateSetter();\n\n if (activePendingBrowserRouterState && !activePendingBrowserRouterState.settled) {\n activePendingBrowserRouterState.settled = true;\n activePendingBrowserRouterState.resolve(getBrowserRouterState());\n }\n\n let resolvePending: ((state: AppRouterState) => void) | undefined;\n const promise = new Promise<AppRouterState>((resolve) => {\n resolvePending = resolve;\n });\n\n if (!resolvePending) {\n throw new Error(\"[vinext] Failed to initialize browser router promise\");\n }\n\n const pending: PendingBrowserRouterState = {\n promise,\n resolve: resolvePending,\n settled: false,\n };\n\n activePendingBrowserRouterState = pending;\n setter(promise);\n\n return pending;\n }\n\n function settlePendingBrowserRouterState(\n pending: PendingBrowserRouterState | null | undefined,\n ): void {\n if (!pending || pending.settled) return;\n\n pending.settled = true;\n pending.resolve(getBrowserRouterState());\n\n if (activePendingBrowserRouterState === pending) {\n activePendingBrowserRouterState = null;\n }\n }\n\n function finalizeNavigation(\n navId: number,\n pending: PendingBrowserRouterState | null | undefined,\n ): void {\n settlePendingBrowserRouterState(pending);\n\n if (isCurrentNavigation(navId)) {\n clearPendingPathname(navId);\n }\n }\n\n function resolvePendingBrowserRouterState(\n pending: PendingBrowserRouterState | null | undefined,\n commit: ApprovedVisibleCommit,\n ): void {\n if (!pending || pending.settled) return;\n\n pending.settled = true;\n pending.resolve(applyApprovedVisibleCommit(getBrowserRouterState(), commit));\n\n if (activePendingBrowserRouterState === pending) {\n activePendingBrowserRouterState = null;\n }\n }\n\n function queuePrePaintNavigationEffect(renderId: number, effect: (() => void) | null): void {\n if (!effect) {\n return;\n }\n pendingNavigationPrePaintEffects.set(renderId, effect);\n }\n\n /**\n * Run all queued pre-paint effects for renderIds up to and including the\n * given renderId. When React supersedes a startTransition update (rapid\n * clicks on same-route links), the superseded NavigationCommitSignal never\n * mounts, so its pre-paint effect never fires. By draining all effects\n * <= the committed renderId here, the winning transition cleans up after\n * any superseded ones, keeping the counter balanced.\n *\n * Invariant: each superseded navigation gets a commitClientNavigationState()\n * to balance the activateNavigationSnapshot() from its renderNavigationPayload call.\n */\n function drainPrePaintEffects(upToRenderId: number): void {\n for (const [id, effect] of pendingNavigationPrePaintEffects) {\n if (id > upToRenderId) {\n continue;\n }\n\n pendingNavigationPrePaintEffects.delete(id);\n if (id === upToRenderId) {\n effect();\n } else {\n // Superseded navigations still need to balance the snapshot counter.\n commitClientNavigationStateImpl(undefined, { releaseSnapshot: true });\n }\n }\n }\n\n /**\n * Resolve all pending navigation commits with renderId <= the committed renderId.\n * Note: Map iteration handles concurrent deletion safely — entries are visited in\n * insertion order and deletion doesn't affect the iterator's view of remaining entries.\n * This pattern is also used in drainPrePaintEffects with the same semantics.\n */\n function resolveCommittedNavigations(renderId: number): void {\n for (const [pendingId, resolve] of pendingNavigationCommits) {\n if (pendingId > renderId) {\n continue;\n }\n\n pendingNavigationCommits.delete(pendingId);\n resolve();\n }\n }\n\n async function hmrReplaceTree(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n ): Promise<void> {\n if (!hasBrowserRouterState()) return;\n\n const currentState = getBrowserRouterState();\n const renderId = allocateRenderId();\n const pending = await createPendingNavigationCommit({\n currentState,\n nextElements,\n navigationSnapshot,\n operationLane: \"hmr\",\n renderId,\n type: \"replace\",\n });\n\n // createPendingNavigationCommit awaits the new RSC payload. While\n // suspended, the prior broken render can unmount BrowserRoot. Re-check\n // before dispatching so a racing unmount doesn't surface as an\n // initialized-setter error.\n if (!hasBrowserRouterState()) return;\n\n dispatchApprovedVisibleCommit(approveHmrVisibleCommit(pending), null, false);\n }\n\n function NavigationCommitSignal(\n this: void,\n {\n renderId,\n children,\n }: {\n renderId: number;\n children?: ReactNode;\n },\n ): ReactNode {\n useLayoutEffect(() => {\n drainPrePaintEffects(renderId);\n\n const frame = requestAnimationFrame(() => {\n resolveCommittedNavigations(renderId);\n });\n\n return () => {\n cancelAnimationFrame(frame);\n // Resolve pending commits to prevent callers from hanging if React\n // unmounts this component without committing (e.g., error boundary).\n resolveCommittedNavigations(renderId);\n };\n }, [renderId]);\n\n return children;\n }\n\n function dispatchApprovedVisibleCommit(\n commit: ApprovedVisibleCommit,\n pendingRouterState: PendingBrowserRouterState | null,\n useTransitionMode: boolean,\n ): void {\n const setter = getBrowserRouterStateSetter();\n\n const applyAction = () => {\n if (pendingRouterState) {\n // The programmatic navigation is already running inside React.startTransition\n // (from router.push/replace/refresh), so resolving the deferred promise is\n // sufficient — no additional startTransition wrapper is needed below.\n resolvePendingBrowserRouterState(pendingRouterState, commit);\n return;\n }\n\n setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));\n };\n\n if (useTransitionMode) {\n startTransition(applyAction);\n } else {\n applyAction();\n }\n }\n\n async function renderNavigationPayload(options: {\n actionType: \"navigate\" | \"replace\" | \"traverse\";\n createNavigationCommitEffect: BrowserNavigationCommitEffectFactory;\n historyUpdateMode: HistoryUpdateMode | undefined;\n navigationSnapshot: ClientNavigationRenderSnapshot;\n nextElements: Promise<AppElements>;\n operationLane: OperationLane;\n params: Record<string, string | string[]>;\n pendingRouterState: PendingBrowserRouterState | null;\n previousNextUrl: string | null;\n targetHref: string;\n navId: number;\n useTransition?: boolean;\n }): Promise<NavigationPayloadOutcome> {\n const renderId = allocateRenderId();\n let resolveCommitted: (() => void) | undefined;\n const committed = new Promise<void>((resolve) => {\n resolveCommitted = resolve;\n pendingNavigationCommits.set(renderId, resolve);\n });\n\n let snapshotActivated = false;\n try {\n const startedState = getBrowserRouterState();\n const pending = await createPendingNavigationCommit({\n currentState: startedState,\n nextElements: options.nextElements,\n navigationSnapshot: options.navigationSnapshot,\n operationLane: options.operationLane,\n previousNextUrl: options.previousNextUrl,\n renderId,\n type: options.actionType,\n });\n\n const approval = approvePendingNavigationCommit({\n activeNavigationId,\n currentState: getBrowserRouterState(),\n pending,\n startedNavigationId: options.navId,\n });\n\n if (approval.decision.disposition === \"no-commit\") {\n settlePendingBrowserRouterState(options.pendingRouterState);\n pendingNavigationCommits.delete(renderId);\n resolveCommitted?.();\n return \"no-commit\";\n }\n\n if (approval.decision.disposition === \"hard-navigate\") {\n settlePendingBrowserRouterState(options.pendingRouterState);\n pendingNavigationCommits.delete(renderId);\n window.location.assign(options.targetHref);\n return \"hard-navigate\";\n }\n\n const approvedCommit = approval.approvedCommit;\n if (approvedCommit === null) {\n throw new Error(\"[vinext] Commit decision did not approve a visible commit\");\n }\n\n queuePrePaintNavigationEffect(\n renderId,\n options.createNavigationCommitEffect({\n href: options.targetHref,\n historyUpdateMode: options.historyUpdateMode,\n navId: options.navId,\n params: options.params,\n previousNextUrl: approvedCommit.previousNextUrl,\n }),\n );\n activateNavigationSnapshot();\n snapshotActivated = true;\n dispatchApprovedVisibleCommit(\n approvedCommit,\n options.pendingRouterState,\n options.useTransition ?? true,\n );\n } catch (error) {\n pendingNavigationPrePaintEffects.delete(renderId);\n pendingNavigationCommits.delete(renderId);\n if (snapshotActivated) {\n commitClientNavigationStateImpl(options.navId);\n }\n settlePendingBrowserRouterState(options.pendingRouterState);\n resolveCommitted?.();\n throw error;\n }\n\n return committed.then(() => \"committed\");\n }\n\n async function commitSameUrlNavigatePayload(\n nextElements: Promise<AppElements>,\n navigationSnapshot: ClientNavigationRenderSnapshot,\n returnValue?: { ok: boolean; data: unknown },\n actionInitiationState?: AppRouterState,\n ): Promise<unknown> {\n const currentState = actionInitiationState ?? getBrowserRouterState();\n const startedNavigationId = activeNavigationId;\n const {\n approvedCommit,\n decision,\n pending,\n // Intentionally retained as #726-OPS-01 trace-shell scaffolding. The\n // same-URL action path can consume this trace once later lifecycle gates\n // need an observable commit explanation.\n trace: _navigationTrace,\n } = await resolveAndClassifyNavigationCommit({\n activeNavigationId,\n currentState,\n getActiveNavigationId: () => activeNavigationId,\n getCurrentStateForApproval: getBrowserRouterState,\n navigationSnapshot,\n nextElements,\n renderId: allocateRenderId(),\n operationLane: \"server-action\",\n startedNavigationId,\n type: \"navigate\",\n });\n\n if (decision.disposition === \"hard-navigate\") {\n window.location.assign(window.location.href);\n return undefined;\n }\n\n if (approvedCommit) {\n // The helper approval and this continuation are separated by a microtask\n // boundary, so re-check lifecycle authority before mutating visible UI.\n const latestApproval = approvePendingNavigationCommit({\n activeNavigationId,\n currentState: getBrowserRouterState(),\n pending,\n startedNavigationId,\n });\n\n if (latestApproval.decision.disposition === \"hard-navigate\") {\n window.location.assign(window.location.href);\n return undefined;\n }\n\n if (latestApproval.approvedCommit) {\n dispatchApprovedVisibleCommit(latestApproval.approvedCommit, null, false);\n }\n }\n\n // Same-URL server actions still return their action value even if the UI\n // update was skipped due to a superseding navigation. That preserves the\n // existing caller contract; a future Phase 2 router state model could make\n // skipped UI updates observable to the caller without conflating them here.\n if (returnValue) {\n if (!returnValue.ok) {\n throw returnValue.data;\n }\n return returnValue.data;\n }\n\n return undefined;\n }\n\n function attachBrowserRouterState(\n setter: Dispatch<AppRouterState | Promise<AppRouterState>>,\n stateRef: BrowserRouterStateRef,\n ): () => void {\n setBrowserRouterState = setter;\n browserRouterStateRef = stateRef;\n markBrowserRouterStateReady();\n\n return () => {\n if (setBrowserRouterState === setter) {\n setBrowserRouterState = null;\n }\n if (browserRouterStateRef === stateRef) {\n browserRouterStateRef = null;\n browserRouterStateHasCommitted = false;\n }\n };\n }\n\n return {\n beginNavigation,\n hasBrowserRouterState,\n getBrowserRouterState,\n isCurrentNavigation,\n waitForBrowserRouterStateReady,\n attachBrowserRouterState,\n beginPendingBrowserRouterState,\n finalizeNavigation,\n renderNavigationPayload,\n commitSameUrlNavigatePayload,\n hmrReplaceTree,\n drainPrePaintEffects,\n NavigationCommitSignal,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { ClientNavigationRenderSnapshot } from "../shims/navigation.js";
|
|
2
|
-
import { AppElements, LayoutFlags } from "./app-elements.js";
|
|
2
|
+
import { AppElements, LayoutFlags } from "./app-elements-wire.js";
|
|
3
|
+
import { NavigationTrace } from "./navigation-trace.js";
|
|
3
4
|
|
|
4
5
|
//#region src/server/app-browser-state.d.ts
|
|
5
6
|
type HistoryStateRecord = {
|
|
6
7
|
[key: string]: unknown;
|
|
7
8
|
};
|
|
9
|
+
type OperationLane = "navigation" | "refresh" | "traverse" | "server-action" | "hmr";
|
|
10
|
+
type OperationRecordBase = {
|
|
11
|
+
id: number;
|
|
12
|
+
lane: OperationLane;
|
|
13
|
+
startedVisibleCommitVersion: number;
|
|
14
|
+
};
|
|
15
|
+
type PendingOperationRecord = OperationRecordBase & {
|
|
16
|
+
state: "pending";
|
|
17
|
+
};
|
|
18
|
+
type CommittedOperationRecord = OperationRecordBase & {
|
|
19
|
+
state: "committed";
|
|
20
|
+
visibleCommitVersion: number;
|
|
21
|
+
};
|
|
22
|
+
type OperationRecord = PendingOperationRecord | CommittedOperationRecord;
|
|
8
23
|
type AppRouterState = {
|
|
24
|
+
activeOperation: OperationRecord | null;
|
|
9
25
|
elements: AppElements;
|
|
10
26
|
interceptionContext: string | null;
|
|
11
27
|
layoutFlags: LayoutFlags;
|
|
@@ -14,12 +30,14 @@ type AppRouterState = {
|
|
|
14
30
|
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
15
31
|
rootLayoutTreePath: string | null;
|
|
16
32
|
routeId: string;
|
|
33
|
+
visibleCommitVersion: number;
|
|
17
34
|
};
|
|
18
35
|
type AppRouterAction = {
|
|
19
36
|
elements: AppElements;
|
|
20
37
|
interceptionContext: string | null;
|
|
21
38
|
layoutFlags: LayoutFlags;
|
|
22
39
|
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
40
|
+
operation: PendingOperationRecord;
|
|
23
41
|
previousNextUrl: string | null;
|
|
24
42
|
renderId: number;
|
|
25
43
|
rootLayoutTreePath: string | null;
|
|
@@ -34,9 +52,9 @@ type PendingNavigationCommit = {
|
|
|
34
52
|
routeId: string;
|
|
35
53
|
};
|
|
36
54
|
type PendingNavigationCommitDisposition = "dispatch" | "hard-navigate" | "skip";
|
|
37
|
-
type
|
|
55
|
+
type PendingNavigationCommitDispositionDecision = {
|
|
38
56
|
disposition: PendingNavigationCommitDisposition;
|
|
39
|
-
|
|
57
|
+
trace: NavigationTrace;
|
|
40
58
|
};
|
|
41
59
|
declare function createHistoryStateWithPreviousNextUrl(state: unknown, previousNextUrl: string | null): HistoryStateRecord | null;
|
|
42
60
|
declare function readHistoryStatePreviousNextUrl(state: unknown): string | null;
|
|
@@ -62,32 +80,32 @@ type ResolveServerActionRequestStateResult = {
|
|
|
62
80
|
* `findIntercept` lookup.
|
|
63
81
|
*/
|
|
64
82
|
declare function resolveServerActionRequestState(options: ResolveServerActionRequestStateOptions): ResolveServerActionRequestStateResult;
|
|
65
|
-
declare function routerReducer(state: AppRouterState, action: AppRouterAction): AppRouterState;
|
|
66
83
|
declare function shouldHardNavigate(currentRootLayoutTreePath: string | null, nextRootLayoutTreePath: string | null): boolean;
|
|
67
84
|
declare function resolvePendingNavigationCommitDisposition(options: {
|
|
68
85
|
activeNavigationId: number;
|
|
86
|
+
currentVisibleCommitVersion: number;
|
|
69
87
|
currentRootLayoutTreePath: string | null;
|
|
70
88
|
nextRootLayoutTreePath: string | null;
|
|
71
89
|
startedNavigationId: number;
|
|
90
|
+
startedVisibleCommitVersion: number;
|
|
72
91
|
}): PendingNavigationCommitDisposition;
|
|
92
|
+
declare function resolvePendingNavigationCommitDispositionDecision(options: {
|
|
93
|
+
activeNavigationId: number;
|
|
94
|
+
currentVisibleCommitVersion: number;
|
|
95
|
+
currentRootLayoutTreePath: string | null;
|
|
96
|
+
nextRootLayoutTreePath: string | null;
|
|
97
|
+
startedNavigationId: number;
|
|
98
|
+
startedVisibleCommitVersion: number;
|
|
99
|
+
}): PendingNavigationCommitDispositionDecision;
|
|
73
100
|
declare function createPendingNavigationCommit(options: {
|
|
74
101
|
currentState: AppRouterState;
|
|
75
102
|
nextElements: Promise<AppElements>;
|
|
76
103
|
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
104
|
+
operationLane: OperationLane;
|
|
77
105
|
previousNextUrl?: string | null;
|
|
78
106
|
renderId: number;
|
|
79
107
|
type: "navigate" | "replace" | "traverse";
|
|
80
108
|
}): Promise<PendingNavigationCommit>;
|
|
81
|
-
declare function resolveAndClassifyNavigationCommit(options: {
|
|
82
|
-
activeNavigationId: number;
|
|
83
|
-
currentState: AppRouterState;
|
|
84
|
-
navigationSnapshot: ClientNavigationRenderSnapshot;
|
|
85
|
-
nextElements: Promise<AppElements>;
|
|
86
|
-
previousNextUrl?: string | null;
|
|
87
|
-
renderId: number;
|
|
88
|
-
startedNavigationId: number;
|
|
89
|
-
type: "navigate" | "replace" | "traverse";
|
|
90
|
-
}): Promise<ClassifiedPendingNavigationCommit>;
|
|
91
109
|
//#endregion
|
|
92
|
-
export { AppRouterAction, AppRouterState, createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl,
|
|
110
|
+
export { AppRouterAction, AppRouterState, CommittedOperationRecord, OperationLane, OperationRecord, PendingNavigationCommit, PendingOperationRecord, createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDisposition, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState, shouldHardNavigate };
|
|
93
111
|
//# sourceMappingURL=app-browser-state.d.ts.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { AppElementsWire } from "./app-elements-wire.js";
|
|
3
|
+
import { getMountedSlotIdsHeader } from "./app-elements.js";
|
|
4
|
+
import { createRscRequestHeaders } from "./app-rsc-cache-busting.js";
|
|
5
|
+
import { NavigationTraceReasonCodes, createNavigationTrace } from "./navigation-trace.js";
|
|
4
6
|
//#region src/server/app-browser-state.ts
|
|
5
7
|
const VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY = "__vinext_previousNextUrl";
|
|
6
8
|
function cloneHistoryState(state) {
|
|
@@ -19,6 +21,14 @@ function readHistoryStatePreviousNextUrl(state) {
|
|
|
19
21
|
const value = cloneHistoryState(state)[VINEXT_PREVIOUS_NEXT_URL_HISTORY_STATE_KEY];
|
|
20
22
|
return typeof value === "string" ? value : null;
|
|
21
23
|
}
|
|
24
|
+
function createOperationRecord(options) {
|
|
25
|
+
return {
|
|
26
|
+
id: options.id,
|
|
27
|
+
lane: options.lane,
|
|
28
|
+
startedVisibleCommitVersion: options.startedVisibleCommitVersion,
|
|
29
|
+
state: "pending"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
22
32
|
function resolveInterceptionContextFromPreviousNextUrl(previousNextUrl, basePath = "") {
|
|
23
33
|
if (previousNextUrl === null) return null;
|
|
24
34
|
return stripBasePath(new URL(previousNextUrl, "http://localhost").pathname, basePath);
|
|
@@ -35,59 +45,56 @@ function resolveInterceptionContextFromPreviousNextUrl(previousNextUrl, basePath
|
|
|
35
45
|
* `findIntercept` lookup.
|
|
36
46
|
*/
|
|
37
47
|
function resolveServerActionRequestState(options) {
|
|
38
|
-
const headers =
|
|
39
|
-
|
|
40
|
-
"x-rsc-action": options.actionId
|
|
41
|
-
});
|
|
48
|
+
const headers = createRscRequestHeaders();
|
|
49
|
+
headers.set("x-rsc-action", options.actionId);
|
|
42
50
|
const interceptionContext = resolveInterceptionContextFromPreviousNextUrl(options.previousNextUrl, options.basePath);
|
|
43
51
|
if (interceptionContext !== null) headers.set("X-Vinext-Interception-Context", interceptionContext);
|
|
44
52
|
const mountedSlotsHeader = getMountedSlotIdsHeader(options.elements);
|
|
45
53
|
if (mountedSlotsHeader !== null) headers.set("X-Vinext-Mounted-Slots", mountedSlotsHeader);
|
|
46
54
|
return { headers };
|
|
47
55
|
}
|
|
48
|
-
function routerReducer(state, action) {
|
|
49
|
-
switch (action.type) {
|
|
50
|
-
case "traverse":
|
|
51
|
-
case "navigate": return {
|
|
52
|
-
elements: mergeElements(state.elements, action.elements, action.type === "traverse"),
|
|
53
|
-
interceptionContext: action.interceptionContext,
|
|
54
|
-
layoutFlags: {
|
|
55
|
-
...state.layoutFlags,
|
|
56
|
-
...action.layoutFlags
|
|
57
|
-
},
|
|
58
|
-
navigationSnapshot: action.navigationSnapshot,
|
|
59
|
-
previousNextUrl: action.previousNextUrl,
|
|
60
|
-
renderId: action.renderId,
|
|
61
|
-
rootLayoutTreePath: action.rootLayoutTreePath,
|
|
62
|
-
routeId: action.routeId
|
|
63
|
-
};
|
|
64
|
-
case "replace": return {
|
|
65
|
-
elements: action.elements,
|
|
66
|
-
interceptionContext: action.interceptionContext,
|
|
67
|
-
layoutFlags: action.layoutFlags,
|
|
68
|
-
navigationSnapshot: action.navigationSnapshot,
|
|
69
|
-
previousNextUrl: action.previousNextUrl,
|
|
70
|
-
renderId: action.renderId,
|
|
71
|
-
rootLayoutTreePath: action.rootLayoutTreePath,
|
|
72
|
-
routeId: action.routeId
|
|
73
|
-
};
|
|
74
|
-
default: {
|
|
75
|
-
const _exhaustive = action.type;
|
|
76
|
-
throw new Error("[vinext] Unknown router action: " + String(_exhaustive));
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
56
|
function shouldHardNavigate(currentRootLayoutTreePath, nextRootLayoutTreePath) {
|
|
81
57
|
return currentRootLayoutTreePath !== null && nextRootLayoutTreePath !== null && currentRootLayoutTreePath !== nextRootLayoutTreePath;
|
|
82
58
|
}
|
|
83
59
|
function resolvePendingNavigationCommitDisposition(options) {
|
|
84
60
|
if (options.startedNavigationId !== options.activeNavigationId) return "skip";
|
|
61
|
+
if (options.startedVisibleCommitVersion !== options.currentVisibleCommitVersion) return "skip";
|
|
85
62
|
if (shouldHardNavigate(options.currentRootLayoutTreePath, options.nextRootLayoutTreePath)) return "hard-navigate";
|
|
86
63
|
return "dispatch";
|
|
87
64
|
}
|
|
65
|
+
function resolvePendingNavigationCommitDispositionDecision(options) {
|
|
66
|
+
const disposition = resolvePendingNavigationCommitDisposition(options);
|
|
67
|
+
const traceFields = {
|
|
68
|
+
activeNavigationId: options.activeNavigationId,
|
|
69
|
+
currentRootLayoutTreePath: options.currentRootLayoutTreePath,
|
|
70
|
+
currentVisibleCommitVersion: options.currentVisibleCommitVersion,
|
|
71
|
+
nextRootLayoutTreePath: options.nextRootLayoutTreePath,
|
|
72
|
+
startedNavigationId: options.startedNavigationId,
|
|
73
|
+
startedVisibleCommitVersion: options.startedVisibleCommitVersion
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
disposition,
|
|
77
|
+
trace: createNavigationTrace(getPendingNavigationCommitDispositionTraceCode({
|
|
78
|
+
currentRootLayoutTreePath: options.currentRootLayoutTreePath,
|
|
79
|
+
disposition,
|
|
80
|
+
nextRootLayoutTreePath: options.nextRootLayoutTreePath
|
|
81
|
+
}), traceFields)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function getPendingNavigationCommitDispositionTraceCode(options) {
|
|
85
|
+
switch (options.disposition) {
|
|
86
|
+
case "skip": return NavigationTraceReasonCodes.staleOperation;
|
|
87
|
+
case "hard-navigate": return NavigationTraceReasonCodes.rootBoundaryChanged;
|
|
88
|
+
case "dispatch": return options.currentRootLayoutTreePath === null || options.nextRootLayoutTreePath === null ? NavigationTraceReasonCodes.rootBoundaryUnknown : NavigationTraceReasonCodes.commitCurrent;
|
|
89
|
+
default: {
|
|
90
|
+
const _exhaustive = options.disposition;
|
|
91
|
+
throw new Error("[vinext] Unknown navigation commit disposition: " + String(_exhaustive));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
88
95
|
async function createPendingNavigationCommit(options) {
|
|
89
96
|
const elements = await options.nextElements;
|
|
90
|
-
const metadata =
|
|
97
|
+
const metadata = AppElementsWire.readMetadata(elements);
|
|
91
98
|
const previousNextUrl = options.previousNextUrl !== void 0 ? options.previousNextUrl : options.currentState.previousNextUrl;
|
|
92
99
|
return {
|
|
93
100
|
action: {
|
|
@@ -95,6 +102,11 @@ async function createPendingNavigationCommit(options) {
|
|
|
95
102
|
interceptionContext: metadata.interceptionContext,
|
|
96
103
|
layoutFlags: metadata.layoutFlags,
|
|
97
104
|
navigationSnapshot: options.navigationSnapshot,
|
|
105
|
+
operation: createOperationRecord({
|
|
106
|
+
id: options.renderId,
|
|
107
|
+
lane: options.operationLane,
|
|
108
|
+
startedVisibleCommitVersion: options.currentState.visibleCommitVersion
|
|
109
|
+
}),
|
|
98
110
|
previousNextUrl,
|
|
99
111
|
renderId: options.renderId,
|
|
100
112
|
rootLayoutTreePath: metadata.rootLayoutTreePath,
|
|
@@ -107,26 +119,7 @@ async function createPendingNavigationCommit(options) {
|
|
|
107
119
|
routeId: metadata.routeId
|
|
108
120
|
};
|
|
109
121
|
}
|
|
110
|
-
async function resolveAndClassifyNavigationCommit(options) {
|
|
111
|
-
const pending = await createPendingNavigationCommit({
|
|
112
|
-
currentState: options.currentState,
|
|
113
|
-
nextElements: options.nextElements,
|
|
114
|
-
navigationSnapshot: options.navigationSnapshot,
|
|
115
|
-
previousNextUrl: options.previousNextUrl,
|
|
116
|
-
renderId: options.renderId,
|
|
117
|
-
type: options.type
|
|
118
|
-
});
|
|
119
|
-
return {
|
|
120
|
-
disposition: resolvePendingNavigationCommitDisposition({
|
|
121
|
-
activeNavigationId: options.activeNavigationId,
|
|
122
|
-
currentRootLayoutTreePath: options.currentState.rootLayoutTreePath,
|
|
123
|
-
nextRootLayoutTreePath: pending.rootLayoutTreePath,
|
|
124
|
-
startedNavigationId: options.startedNavigationId
|
|
125
|
-
}),
|
|
126
|
-
pending
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
122
|
//#endregion
|
|
130
|
-
export { createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl,
|
|
123
|
+
export { createHistoryStateWithPreviousNextUrl, createPendingNavigationCommit, readHistoryStatePreviousNextUrl, resolveInterceptionContextFromPreviousNextUrl, resolvePendingNavigationCommitDisposition, resolvePendingNavigationCommitDispositionDecision, resolveServerActionRequestState, shouldHardNavigate };
|
|
131
124
|
|
|
132
125
|
//# sourceMappingURL=app-browser-state.js.map
|