vinext 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -5
- package/dist/build/client-build-config.d.ts +7 -1
- package/dist/build/client-build-config.js +9 -1
- package/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/check.js +4 -3
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/navigation-runtime.d.ts +3 -2
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +8 -5
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.d.ts +11 -4
- package/dist/config/config-matchers.js +88 -16
- package/dist/config/next-config.d.ts +59 -4
- package/dist/config/next-config.js +149 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +189 -101
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +71 -6
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +54 -9
- package/dist/entries/pages-server-entry.js +48 -11
- package/dist/index.d.ts +0 -2
- package/dist/index.js +285 -139
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +10 -5
- package/dist/plugins/optimize-imports.js +27 -21
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +25 -2
- package/dist/routing/app-route-graph.js +91 -22
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +23 -2
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +269 -297
- package/dist/server/app-browser-error.d.ts +10 -3
- package/dist/server/app-browser-error.js +47 -6
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +7 -4
- package/dist/server/app-browser-navigation-controller.js +33 -9
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-state.js +4 -7
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +3 -1
- package/dist/server/app-fallback-renderer.js +6 -2
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +24 -3
- package/dist/server/app-page-boundary-render.d.ts +3 -1
- package/dist/server/app-page-boundary-render.js +31 -16
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +71 -8
- package/dist/server/app-page-dispatch.d.ts +34 -0
- package/dist/server/app-page-dispatch.js +167 -97
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +42 -10
- package/dist/server/app-page-execution.d.ts +7 -2
- package/dist/server/app-page-execution.js +53 -18
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +13 -2
- package/dist/server/app-page-render.js +48 -17
- package/dist/server/app-page-request.d.ts +3 -0
- package/dist/server/app-page-request.js +5 -3
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +5 -1
- package/dist/server/app-page-route-wiring.js +21 -11
- package/dist/server/app-page-stream.d.ts +16 -9
- package/dist/server/app-page-stream.js +12 -9
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.js +12 -1
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +153 -53
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +12 -0
- package/dist/server/app-server-action-execution.js +47 -15
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +81 -8
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +287 -63
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +186 -22
- package/dist/server/navigation-planner.js +302 -0
- package/dist/server/navigation-trace.d.ts +18 -1
- package/dist/server/navigation-trace.js +18 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +20 -3
- package/dist/server/pages-api-route.js +19 -3
- package/dist/server/pages-asset-tags.d.ts +16 -4
- package/dist/server/pages-asset-tags.js +22 -12
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +16 -3
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.d.ts +3 -11
- package/dist/server/pages-node-compat.js +175 -122
- package/dist/server/pages-page-data.d.ts +39 -2
- package/dist/server/pages-page-data.js +261 -46
- package/dist/server/pages-page-handler.d.ts +5 -2
- package/dist/server/pages-page-handler.js +78 -25
- package/dist/server/pages-page-response.d.ts +47 -2
- package/dist/server/pages-page-response.js +73 -9
- package/dist/server/pages-readiness.d.ts +1 -1
- package/dist/server/pages-request-pipeline.d.ts +16 -1
- package/dist/server/pages-request-pipeline.js +96 -38
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.d.ts +39 -1
- package/dist/server/prod-server.js +107 -37
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +12 -4
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +79 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +6 -4
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +38 -11
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +11 -1
- package/dist/shims/fetch-cache.js +55 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +66 -5
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +18 -23
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +14 -17
- package/dist/shims/navigation.js +93 -46
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +434 -116
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +33 -2
- package/dist/shims/server.js +75 -18
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/client-build-manifest.js +15 -5
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +8 -1
- package/dist/utils/path.js +13 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
//#region src/server/app-browser-error.d.ts
|
|
2
|
-
|
|
2
|
+
type VinextHydrateRootErrorInfo = {
|
|
3
3
|
componentStack?: string;
|
|
4
|
-
|
|
4
|
+
errorBoundary?: unknown;
|
|
5
|
+
};
|
|
6
|
+
type HydrateRootErrorHandler = (error: unknown, errorInfo: VinextHydrateRootErrorInfo) => void;
|
|
7
|
+
declare function createOnUncaughtError(): HydrateRootErrorHandler;
|
|
8
|
+
declare function createProdOnCaughtError(onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
|
|
9
|
+
declare function createDevOnCaughtError(onCaughtError: HydrateRootErrorHandler, onImplicitRootError: HydrateRootErrorHandler): HydrateRootErrorHandler;
|
|
10
|
+
declare function prodOnCaughtError(error: unknown, errorInfo: VinextHydrateRootErrorInfo): void;
|
|
11
|
+
declare function prodOnRecoverableError(error: unknown): void;
|
|
5
12
|
//#endregion
|
|
6
|
-
export { createOnUncaughtError };
|
|
13
|
+
export { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnCaughtError, prodOnRecoverableError };
|
|
@@ -1,11 +1,52 @@
|
|
|
1
|
+
import { isUnknownRecord } from "../utils/record.js";
|
|
2
|
+
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
1
3
|
//#region src/server/app-browser-error.ts
|
|
2
|
-
function
|
|
4
|
+
function isImplicitRootErrorBoundary(errorInfo) {
|
|
5
|
+
if (!isUnknownRecord(errorInfo.errorBoundary)) return false;
|
|
6
|
+
const props = errorInfo.errorBoundary.props;
|
|
7
|
+
return isUnknownRecord(props) && props.isImplicitRootErrorBoundary === true;
|
|
8
|
+
}
|
|
9
|
+
function logCaughtError(error, errorInfo) {
|
|
10
|
+
console.error(error);
|
|
11
|
+
if (errorInfo?.componentStack) console.error("The above error occurred in a React component:\n" + errorInfo.componentStack);
|
|
12
|
+
}
|
|
13
|
+
function reportGlobalError(error) {
|
|
14
|
+
if (typeof globalThis.reportError === "function") {
|
|
15
|
+
globalThis.reportError(error);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.error(error);
|
|
19
|
+
}
|
|
20
|
+
function createOnUncaughtError() {
|
|
21
|
+
return (error) => {
|
|
22
|
+
reportGlobalError(error);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function createProdOnCaughtError(onImplicitRootError) {
|
|
3
26
|
return (error, errorInfo) => {
|
|
4
|
-
|
|
5
|
-
if (errorInfo
|
|
6
|
-
|
|
7
|
-
|
|
27
|
+
if (isNavigationSignalError(error)) return;
|
|
28
|
+
if (isImplicitRootErrorBoundary(errorInfo)) {
|
|
29
|
+
onImplicitRootError(error, errorInfo);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
logCaughtError(error, errorInfo);
|
|
8
33
|
};
|
|
9
34
|
}
|
|
35
|
+
function createDevOnCaughtError(onCaughtError, onImplicitRootError) {
|
|
36
|
+
return (error, errorInfo) => {
|
|
37
|
+
if (isImplicitRootErrorBoundary(errorInfo)) {
|
|
38
|
+
onImplicitRootError(error, errorInfo);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
onCaughtError(error, errorInfo);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function prodOnCaughtError(error, errorInfo) {
|
|
45
|
+
if (isNavigationSignalError(error)) return;
|
|
46
|
+
logCaughtError(error, errorInfo);
|
|
47
|
+
}
|
|
48
|
+
function prodOnRecoverableError(error) {
|
|
49
|
+
reportGlobalError(error instanceof Error && error.cause !== void 0 ? error.cause : error);
|
|
50
|
+
}
|
|
10
51
|
//#endregion
|
|
11
|
-
export { createOnUncaughtError };
|
|
52
|
+
export { createDevOnCaughtError, createOnUncaughtError, createProdOnCaughtError, prodOnCaughtError, prodOnRecoverableError };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { BfcacheIdMap, HistoryTraversalIntent } from "./app-history-state.js";
|
|
2
|
+
import { AppRouterState } from "./app-browser-state.js";
|
|
3
|
+
import { HistoryUpdateMode } from "./app-browser-navigation-controller.js";
|
|
4
|
+
|
|
5
|
+
//#region src/server/app-browser-history-controller.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Visible router-state metadata at the instant a hash-only navigation commits.
|
|
8
|
+
* `null` means the browser router tree has not committed yet, so the controller
|
|
9
|
+
* falls back to reading the same facts off the live history entry.
|
|
10
|
+
*/
|
|
11
|
+
type VisibleNavigationMetadata = {
|
|
12
|
+
bfcacheIds: BfcacheIdMap | null;
|
|
13
|
+
previousNextUrl: string | null;
|
|
14
|
+
};
|
|
15
|
+
type AppBrowserHistoryControllerDeps = {
|
|
16
|
+
initialHistoryState: unknown;
|
|
17
|
+
maxHistoryStateSnapshots: number; /** Reads `window.history.state`. Injected so the controller stays unit-testable. */
|
|
18
|
+
readHistoryState: () => unknown; /** Reads `window.location.href`. Injected so the controller stays unit-testable. */
|
|
19
|
+
readCurrentHref: () => string; /** Wraps `pushHistoryStateWithoutNotify(state, "", href)`. */
|
|
20
|
+
pushHistoryState: (state: unknown, href: string) => void; /** Wraps `replaceHistoryStateWithoutNotify(state, "", href)`. */
|
|
21
|
+
replaceHistoryState: (state: unknown, href: string) => void;
|
|
22
|
+
readVisibleNavigationMetadata: () => VisibleNavigationMetadata | null;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Candidate visible state resolved from a restorable history snapshot, handed to
|
|
26
|
+
* the entry's approved-visible-restore callback. The controller resolves the
|
|
27
|
+
* candidate and owns the traversal-index commit; the entry owns the actual
|
|
28
|
+
* `AppBrowserNavigationController.restoreHistorySnapshotVisibleState()` call and
|
|
29
|
+
* the `ApprovedVisibleCommit` boundary.
|
|
30
|
+
*/
|
|
31
|
+
type RestorableSnapshotCandidate = {
|
|
32
|
+
state: AppRouterState;
|
|
33
|
+
beforeCommit: () => void;
|
|
34
|
+
};
|
|
35
|
+
type RestoreHistorySnapshotOptions = {
|
|
36
|
+
historyState: unknown;
|
|
37
|
+
stageClientParams: (params: Record<string, string | string[]>) => void;
|
|
38
|
+
approveVisibleRestore: (candidate: RestorableSnapshotCandidate) => boolean;
|
|
39
|
+
};
|
|
40
|
+
type CommitNavigationHistoryOptions = {
|
|
41
|
+
bfcacheIds: BfcacheIdMap;
|
|
42
|
+
href: string;
|
|
43
|
+
historyUpdateMode: HistoryUpdateMode | undefined;
|
|
44
|
+
previousNextUrl: string | null;
|
|
45
|
+
targetHistoryIndex?: number | null;
|
|
46
|
+
stageClientParams: () => void;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Owns App Router browser-history metadata and traversal bookkeeping behind a
|
|
50
|
+
* typed seam: traversal index allocation/commit, push/replace/traverse/hash-only
|
|
51
|
+
* history-state writes, BFCache epoch/snapshot invalidation through
|
|
52
|
+
* `RestorableClientStateController`, and restorable-snapshot candidate
|
|
53
|
+
* resolution.
|
|
54
|
+
*
|
|
55
|
+
* Ownership boundary: this is not a second router or visible-state authority. It
|
|
56
|
+
* resolves history facts and delegates visible restoration through an injected
|
|
57
|
+
* approved-commit callback. It never sets router state directly, never imports
|
|
58
|
+
* `applyApprovedVisibleCommit()`, and never bypasses the `ApprovedVisibleCommit`
|
|
59
|
+
* boundary owned by `AppBrowserNavigationController`.
|
|
60
|
+
*/
|
|
61
|
+
declare class AppBrowserHistoryController {
|
|
62
|
+
#private;
|
|
63
|
+
constructor(deps: AppBrowserHistoryControllerDeps);
|
|
64
|
+
get currentHistoryTraversalIndex(): number | null;
|
|
65
|
+
allocateNavigationHistoryTraversalIndex(historyUpdateMode: HistoryUpdateMode | undefined): number | null;
|
|
66
|
+
commitHistoryTraversalIndex(index: number | null): void;
|
|
67
|
+
commitTraversalIndexFromHistoryState(historyState: unknown): void;
|
|
68
|
+
resolveTraversalIntent(historyState: unknown): HistoryTraversalIntent;
|
|
69
|
+
readCurrentBfcacheVersionHistoryIds(historyState: unknown): BfcacheIdMap | null;
|
|
70
|
+
isCacheInvalidationGuarded(): boolean;
|
|
71
|
+
isCurrentBfcacheVersion(historyState: unknown): boolean;
|
|
72
|
+
beginCacheInvalidationGuard(): () => void;
|
|
73
|
+
invalidateRestorableClientState(): void;
|
|
74
|
+
rememberHistoryStateSnapshot(state: AppRouterState): void;
|
|
75
|
+
commitHashOnlyNavigation(href: string, historyUpdateMode: HistoryUpdateMode, scroll: boolean): void;
|
|
76
|
+
/**
|
|
77
|
+
* Writes the history entry for an approved push/replace/traverse commit and
|
|
78
|
+
* advances the traversal index. `stageClientParams` runs at the exact point it
|
|
79
|
+
* ran inline in the browser-entry commit effect so client-param staging stays
|
|
80
|
+
* ordered relative to the history write. Mirrors Next.js committing tree state
|
|
81
|
+
* into the history entry during the navigation commit.
|
|
82
|
+
*/
|
|
83
|
+
commitNavigationHistory(options: CommitNavigationHistoryOptions): void;
|
|
84
|
+
syncCurrentHistoryStatePreviousNextUrl(previousNextUrl: string | null, bfcacheIds?: BfcacheIdMap | null): void;
|
|
85
|
+
/** Initial history write performed before hydration starts. */
|
|
86
|
+
writeBootstrapHistoryMetadata(): void;
|
|
87
|
+
/** History write performed on the first committed (hydrated) render. */
|
|
88
|
+
writeHydratedHistoryMetadata(options: {
|
|
89
|
+
bfcacheIds: BfcacheIdMap;
|
|
90
|
+
previousNextUrl: string | null;
|
|
91
|
+
}): void;
|
|
92
|
+
/**
|
|
93
|
+
* Resolves a restorable snapshot candidate for the given history entry and
|
|
94
|
+
* commits the traversal index after, and only after, the injected
|
|
95
|
+
* approved-visible-restore callback succeeds. The traversal-index commit and
|
|
96
|
+
* client-param staging run inside `beforeCommit`, which the
|
|
97
|
+
* `AppBrowserNavigationController` invokes only once the `ApprovedVisibleCommit`
|
|
98
|
+
* is approved. Returns false when no snapshot is restorable or the restore is
|
|
99
|
+
* not approved.
|
|
100
|
+
*/
|
|
101
|
+
restoreHistorySnapshot(options: RestoreHistorySnapshotOptions): boolean;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { AppBrowserHistoryController, RestorableSnapshotCandidate };
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { RestorableClientStateController, createHistoryStateWithNavigationMetadata, readHistoryStateBfcacheIds, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent } from "./app-history-state.js";
|
|
2
|
+
//#region src/server/app-browser-history-controller.ts
|
|
3
|
+
function stripVinextScrollState(state) {
|
|
4
|
+
if (!state || typeof state !== "object") return state;
|
|
5
|
+
const nextState = {};
|
|
6
|
+
for (const [key, value] of Object.entries(state)) {
|
|
7
|
+
if (key === "__vinext_scrollX" || key === "__vinext_scrollY") continue;
|
|
8
|
+
nextState[key] = value;
|
|
9
|
+
}
|
|
10
|
+
return Object.keys(nextState).length > 0 ? nextState : null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Owns App Router browser-history metadata and traversal bookkeeping behind a
|
|
14
|
+
* typed seam: traversal index allocation/commit, push/replace/traverse/hash-only
|
|
15
|
+
* history-state writes, BFCache epoch/snapshot invalidation through
|
|
16
|
+
* `RestorableClientStateController`, and restorable-snapshot candidate
|
|
17
|
+
* resolution.
|
|
18
|
+
*
|
|
19
|
+
* Ownership boundary: this is not a second router or visible-state authority. It
|
|
20
|
+
* resolves history facts and delegates visible restoration through an injected
|
|
21
|
+
* approved-commit callback. It never sets router state directly, never imports
|
|
22
|
+
* `applyApprovedVisibleCommit()`, and never bypasses the `ApprovedVisibleCommit`
|
|
23
|
+
* boundary owned by `AppBrowserNavigationController`.
|
|
24
|
+
*/
|
|
25
|
+
var AppBrowserHistoryController = class {
|
|
26
|
+
#restorableClientState;
|
|
27
|
+
#readHistoryState;
|
|
28
|
+
#readCurrentHref;
|
|
29
|
+
#pushHistoryState;
|
|
30
|
+
#replaceHistoryState;
|
|
31
|
+
#readVisibleNavigationMetadata;
|
|
32
|
+
#currentHistoryTraversalIndex;
|
|
33
|
+
#nextHistoryTraversalIndex;
|
|
34
|
+
constructor(deps) {
|
|
35
|
+
this.#readHistoryState = deps.readHistoryState;
|
|
36
|
+
this.#readCurrentHref = deps.readCurrentHref;
|
|
37
|
+
this.#pushHistoryState = deps.pushHistoryState;
|
|
38
|
+
this.#replaceHistoryState = deps.replaceHistoryState;
|
|
39
|
+
this.#readVisibleNavigationMetadata = deps.readVisibleNavigationMetadata;
|
|
40
|
+
this.#restorableClientState = new RestorableClientStateController({
|
|
41
|
+
initialHistoryState: deps.initialHistoryState,
|
|
42
|
+
maxHistoryStateSnapshots: deps.maxHistoryStateSnapshots
|
|
43
|
+
});
|
|
44
|
+
this.#currentHistoryTraversalIndex = readHistoryStateTraversalIndex(deps.initialHistoryState) ?? 0;
|
|
45
|
+
this.#nextHistoryTraversalIndex = this.#currentHistoryTraversalIndex;
|
|
46
|
+
}
|
|
47
|
+
get currentHistoryTraversalIndex() {
|
|
48
|
+
return this.#currentHistoryTraversalIndex;
|
|
49
|
+
}
|
|
50
|
+
allocateNavigationHistoryTraversalIndex(historyUpdateMode) {
|
|
51
|
+
switch (historyUpdateMode) {
|
|
52
|
+
case "push": return this.#nextHistoryTraversalIndex + 1;
|
|
53
|
+
case "replace": return this.#currentHistoryTraversalIndex;
|
|
54
|
+
case void 0: return null;
|
|
55
|
+
default: throw new Error("[vinext] Unknown history update mode: " + String(historyUpdateMode));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
commitHistoryTraversalIndex(index) {
|
|
59
|
+
this.#currentHistoryTraversalIndex = index;
|
|
60
|
+
if (index !== null) this.#nextHistoryTraversalIndex = Math.max(this.#nextHistoryTraversalIndex, index);
|
|
61
|
+
}
|
|
62
|
+
commitTraversalIndexFromHistoryState(historyState) {
|
|
63
|
+
this.commitHistoryTraversalIndex(readHistoryStateTraversalIndex(historyState));
|
|
64
|
+
}
|
|
65
|
+
resolveTraversalIntent(historyState) {
|
|
66
|
+
return resolveHistoryTraversalIntent({
|
|
67
|
+
currentHistoryIndex: this.#currentHistoryTraversalIndex,
|
|
68
|
+
historyState
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
readCurrentBfcacheVersionHistoryIds(historyState) {
|
|
72
|
+
return this.#restorableClientState.readCurrentBfcacheVersionHistoryIds(historyState);
|
|
73
|
+
}
|
|
74
|
+
isCacheInvalidationGuarded() {
|
|
75
|
+
return this.#restorableClientState.isCacheInvalidationGuarded();
|
|
76
|
+
}
|
|
77
|
+
isCurrentBfcacheVersion(historyState) {
|
|
78
|
+
return this.#restorableClientState.isCurrentBfcacheVersion(historyState);
|
|
79
|
+
}
|
|
80
|
+
beginCacheInvalidationGuard() {
|
|
81
|
+
return this.#restorableClientState.beginCacheInvalidationGuard();
|
|
82
|
+
}
|
|
83
|
+
invalidateRestorableClientState() {
|
|
84
|
+
this.#restorableClientState.invalidateClientState();
|
|
85
|
+
}
|
|
86
|
+
rememberHistoryStateSnapshot(state) {
|
|
87
|
+
this.#restorableClientState.rememberHistoryStateSnapshot({
|
|
88
|
+
historyIndex: this.#currentHistoryTraversalIndex,
|
|
89
|
+
state
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
commitHashOnlyNavigation(href, historyUpdateMode, scroll) {
|
|
93
|
+
const navigationHistoryIndex = this.allocateNavigationHistoryTraversalIndex(historyUpdateMode);
|
|
94
|
+
const historyState = this.#readHistoryState();
|
|
95
|
+
const visible = this.#readVisibleNavigationMetadata();
|
|
96
|
+
const previousNextUrl = visible ? visible.previousNextUrl : readHistoryStatePreviousNextUrl(historyState);
|
|
97
|
+
const bfcacheIds = visible ? visible.bfcacheIds : this.#restorableClientState.readCurrentBfcacheVersionHistoryIds(historyState);
|
|
98
|
+
const nextHistoryState = createHistoryStateWithNavigationMetadata(this.#createHashOnlyNavigationBaseHistoryState(historyUpdateMode, scroll), {
|
|
99
|
+
bfcacheIds,
|
|
100
|
+
bfcacheVersion: bfcacheIds === null ? void 0 : this.#restorableClientState.currentBfcacheVersion,
|
|
101
|
+
previousNextUrl,
|
|
102
|
+
traversalIndex: navigationHistoryIndex
|
|
103
|
+
});
|
|
104
|
+
if (historyUpdateMode === "replace") this.#replaceHistoryState(nextHistoryState, href);
|
|
105
|
+
else this.#pushHistoryState(nextHistoryState, href);
|
|
106
|
+
this.commitHistoryTraversalIndex(navigationHistoryIndex);
|
|
107
|
+
}
|
|
108
|
+
#createHashOnlyNavigationBaseHistoryState(historyUpdateMode, scroll) {
|
|
109
|
+
if (historyUpdateMode !== "replace") return null;
|
|
110
|
+
const historyState = this.#readHistoryState();
|
|
111
|
+
return scroll ? stripVinextScrollState(historyState) : historyState;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Writes the history entry for an approved push/replace/traverse commit and
|
|
115
|
+
* advances the traversal index. `stageClientParams` runs at the exact point it
|
|
116
|
+
* ran inline in the browser-entry commit effect so client-param staging stays
|
|
117
|
+
* ordered relative to the history write. Mirrors Next.js committing tree state
|
|
118
|
+
* into the history entry during the navigation commit.
|
|
119
|
+
*/
|
|
120
|
+
commitNavigationHistory(options) {
|
|
121
|
+
const currentHref = this.#readCurrentHref();
|
|
122
|
+
const origin = new URL(currentHref).origin;
|
|
123
|
+
const targetHref = new URL(options.href, origin).href;
|
|
124
|
+
const preserveExistingState = options.historyUpdateMode === "replace";
|
|
125
|
+
const navigationHistoryIndex = options.targetHistoryIndex !== void 0 ? options.targetHistoryIndex : this.allocateNavigationHistoryTraversalIndex(options.historyUpdateMode);
|
|
126
|
+
const historyState = createHistoryStateWithNavigationMetadata(preserveExistingState ? this.#readHistoryState() : null, {
|
|
127
|
+
bfcacheIds: options.bfcacheIds,
|
|
128
|
+
bfcacheVersion: this.#restorableClientState.currentBfcacheVersion,
|
|
129
|
+
previousNextUrl: options.previousNextUrl,
|
|
130
|
+
traversalIndex: navigationHistoryIndex
|
|
131
|
+
});
|
|
132
|
+
let wroteHistoryState = false;
|
|
133
|
+
if (options.historyUpdateMode === "replace" && currentHref !== targetHref) {
|
|
134
|
+
options.stageClientParams();
|
|
135
|
+
this.#replaceHistoryState(historyState, options.href);
|
|
136
|
+
wroteHistoryState = true;
|
|
137
|
+
this.commitHistoryTraversalIndex(navigationHistoryIndex);
|
|
138
|
+
} else if (options.historyUpdateMode === "push" && currentHref !== targetHref) {
|
|
139
|
+
options.stageClientParams();
|
|
140
|
+
this.#pushHistoryState(historyState, options.href);
|
|
141
|
+
wroteHistoryState = true;
|
|
142
|
+
this.commitHistoryTraversalIndex(navigationHistoryIndex);
|
|
143
|
+
}
|
|
144
|
+
if (!wroteHistoryState) {
|
|
145
|
+
this.syncCurrentHistoryStatePreviousNextUrl(options.previousNextUrl, options.bfcacheIds);
|
|
146
|
+
options.stageClientParams();
|
|
147
|
+
if (options.targetHistoryIndex !== void 0) this.commitHistoryTraversalIndex(options.targetHistoryIndex);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
syncCurrentHistoryStatePreviousNextUrl(previousNextUrl, bfcacheIds) {
|
|
151
|
+
if (this.#isHistoryStateNavigationMetadataInSync(this.#readHistoryState(), previousNextUrl, bfcacheIds)) return;
|
|
152
|
+
const nextHistoryState = createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
|
|
153
|
+
bfcacheIds,
|
|
154
|
+
bfcacheVersion: bfcacheIds === void 0 ? void 0 : this.#restorableClientState.currentBfcacheVersion,
|
|
155
|
+
previousNextUrl
|
|
156
|
+
});
|
|
157
|
+
this.#replaceHistoryState(nextHistoryState, this.#readCurrentHref());
|
|
158
|
+
if (this.#isHistoryStateNavigationMetadataInSync(this.#readHistoryState(), previousNextUrl, bfcacheIds)) return;
|
|
159
|
+
this.#replaceHistoryState(nextHistoryState, this.#readCurrentHref());
|
|
160
|
+
}
|
|
161
|
+
#isHistoryStateNavigationMetadataInSync(state, previousNextUrl, bfcacheIds) {
|
|
162
|
+
return readHistoryStatePreviousNextUrl(state) === previousNextUrl && (bfcacheIds === void 0 || areBfcacheIdMapsEqual(readHistoryStateBfcacheIds(state), bfcacheIds) && this.#restorableClientState.isCurrentBfcacheVersion(state));
|
|
163
|
+
}
|
|
164
|
+
/** Initial history write performed before hydration starts. */
|
|
165
|
+
writeBootstrapHistoryMetadata() {
|
|
166
|
+
this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
|
|
167
|
+
previousNextUrl: null,
|
|
168
|
+
traversalIndex: this.#currentHistoryTraversalIndex
|
|
169
|
+
}), this.#readCurrentHref());
|
|
170
|
+
}
|
|
171
|
+
/** History write performed on the first committed (hydrated) render. */
|
|
172
|
+
writeHydratedHistoryMetadata(options) {
|
|
173
|
+
this.#replaceHistoryState(createHistoryStateWithNavigationMetadata(this.#readHistoryState(), {
|
|
174
|
+
bfcacheIds: options.bfcacheIds,
|
|
175
|
+
bfcacheVersion: this.#restorableClientState.currentBfcacheVersion,
|
|
176
|
+
previousNextUrl: options.previousNextUrl,
|
|
177
|
+
traversalIndex: this.#currentHistoryTraversalIndex
|
|
178
|
+
}), this.#readCurrentHref());
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolves a restorable snapshot candidate for the given history entry and
|
|
182
|
+
* commits the traversal index after, and only after, the injected
|
|
183
|
+
* approved-visible-restore callback succeeds. The traversal-index commit and
|
|
184
|
+
* client-param staging run inside `beforeCommit`, which the
|
|
185
|
+
* `AppBrowserNavigationController` invokes only once the `ApprovedVisibleCommit`
|
|
186
|
+
* is approved. Returns false when no snapshot is restorable or the restore is
|
|
187
|
+
* not approved.
|
|
188
|
+
*/
|
|
189
|
+
restoreHistorySnapshot(options) {
|
|
190
|
+
const decision = this.#restorableClientState.resolveHistoryStateSnapshotRestore(options.historyState);
|
|
191
|
+
if (decision.kind === "skip") return false;
|
|
192
|
+
return options.approveVisibleRestore({
|
|
193
|
+
state: decision.state,
|
|
194
|
+
beforeCommit: () => {
|
|
195
|
+
this.commitHistoryTraversalIndex(decision.targetHistoryIndex);
|
|
196
|
+
options.stageClientParams(decision.state.navigationSnapshot.params);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
function areBfcacheIdMapsEqual(a, b) {
|
|
202
|
+
if (a === b) return true;
|
|
203
|
+
if (a === null || b === null) return false;
|
|
204
|
+
const aEntries = Object.entries(a);
|
|
205
|
+
const bEntries = Object.entries(b);
|
|
206
|
+
if (aEntries.length !== bEntries.length) return false;
|
|
207
|
+
return aEntries.every(([key, value]) => b[key] === value);
|
|
208
|
+
}
|
|
209
|
+
//#endregion
|
|
210
|
+
export { AppBrowserHistoryController };
|
|
@@ -8,6 +8,7 @@ type HydrateRootChildren = Parameters<HydrateRoot>[1];
|
|
|
8
8
|
type HydrateRootReturn = ReturnType<HydrateRoot>;
|
|
9
9
|
type HydrateRootCaughtErrorHandler = NonNullable<HydrateRootOptions["onCaughtError"]>;
|
|
10
10
|
type HydrateRootUncaughtErrorHandler = NonNullable<HydrateRootOptions["onUncaughtError"]>;
|
|
11
|
+
type HydrateRootRecoverableErrorHandler = NonNullable<HydrateRootOptions["onRecoverableError"]>;
|
|
11
12
|
type StartTransition = (action: () => void) => void;
|
|
12
13
|
declare const RSC_FORM_STATE_GLOBAL = "__VINEXT_RSC_FORM_STATE__";
|
|
13
14
|
type FormStateGlobal = {
|
|
@@ -17,6 +18,7 @@ declare function consumeInitialFormState(global: FormStateGlobal): ReactFormStat
|
|
|
17
18
|
declare function createVinextHydrateRootOptions(options: {
|
|
18
19
|
formState: ReactFormState | null;
|
|
19
20
|
onCaughtError?: HydrateRootCaughtErrorHandler;
|
|
21
|
+
onRecoverableError?: HydrateRootRecoverableErrorHandler;
|
|
20
22
|
onUncaughtError: HydrateRootUncaughtErrorHandler;
|
|
21
23
|
}): HydrateRootOptions;
|
|
22
24
|
declare function hydrateRootInTransition(options: {
|
|
@@ -8,6 +8,7 @@ function consumeInitialFormState(global) {
|
|
|
8
8
|
function createVinextHydrateRootOptions(options) {
|
|
9
9
|
const hydrateOptions = {
|
|
10
10
|
formState: options.formState,
|
|
11
|
+
...options.onRecoverableError ? { onRecoverableError: options.onRecoverableError } : {},
|
|
11
12
|
onUncaughtError: options.onUncaughtError
|
|
12
13
|
};
|
|
13
14
|
if (options.onCaughtError) return {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { RouteManifest } from "../routing/app-route-graph.js";
|
|
2
2
|
import { AppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
3
|
-
import {
|
|
3
|
+
import { NavigationRuntimeVisibleCommitMode } from "../client/navigation-runtime.js";
|
|
4
4
|
import { AppElements } from "./app-elements-wire.js";
|
|
5
5
|
import { OperationLane } from "./navigation-planner.js";
|
|
6
|
-
import {
|
|
6
|
+
import { ServerActionRevalidationKind } from "./app-browser-action-result.js";
|
|
7
|
+
import { ClientNavigationRenderSnapshot, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
|
|
7
8
|
import { AppNavigationPayloadOrigin, AppRouterState } from "./app-browser-state.js";
|
|
8
9
|
import { Dispatch, ReactNode } from "react";
|
|
9
10
|
|
|
@@ -16,6 +17,7 @@ type PendingBrowserRouterState = {
|
|
|
16
17
|
};
|
|
17
18
|
type NavigationPayloadOutcome = "committed" | "no-commit" | "hard-navigate";
|
|
18
19
|
type HardNavigationMode = "assign" | "replace";
|
|
20
|
+
type BrowserNavigationCommitEffect = () => void;
|
|
19
21
|
type BrowserNavigationCommitEffectFactory = (options: {
|
|
20
22
|
bfcacheIds: Readonly<Record<string, string>>;
|
|
21
23
|
href: string;
|
|
@@ -24,7 +26,7 @@ type BrowserNavigationCommitEffectFactory = (options: {
|
|
|
24
26
|
params: Record<string, string | string[]>;
|
|
25
27
|
previousNextUrl: string | null;
|
|
26
28
|
targetHistoryIndex?: number | null;
|
|
27
|
-
}) =>
|
|
29
|
+
}) => BrowserNavigationCommitEffect;
|
|
28
30
|
type BrowserRouterStateRef = {
|
|
29
31
|
current: AppRouterState;
|
|
30
32
|
};
|
|
@@ -75,6 +77,7 @@ type BrowserNavigationController = {
|
|
|
75
77
|
targetHistoryIndex?: number | null;
|
|
76
78
|
targetHref: string;
|
|
77
79
|
navId: number;
|
|
80
|
+
visibleCommitMode?: NavigationRuntimeVisibleCommitMode;
|
|
78
81
|
}): Promise<NavigationPayloadOutcome>;
|
|
79
82
|
commitSameUrlNavigatePayload(nextElements: Promise<AppElements>, navigationSnapshot: ClientNavigationRenderSnapshot, returnValue?: {
|
|
80
83
|
ok: boolean;
|
|
@@ -90,6 +93,7 @@ type BrowserNavigationController = {
|
|
|
90
93
|
* navigation would otherwise be lost.
|
|
91
94
|
*/
|
|
92
95
|
drainPrePaintEffects(renderId: number): void;
|
|
96
|
+
clearCommittedNavigationFailureTargets(renderId: number): void;
|
|
93
97
|
NavigationCommitSignal(this: void, {
|
|
94
98
|
renderId,
|
|
95
99
|
children
|
|
@@ -99,7 +103,6 @@ type BrowserNavigationController = {
|
|
|
99
103
|
}): ReactNode;
|
|
100
104
|
};
|
|
101
105
|
declare function clearHardNavigationLoopGuard(): void;
|
|
102
|
-
declare function createSnapshotPathAndSearch(snapshot: ClientNavigationRenderSnapshot): string;
|
|
103
106
|
declare function createBasePathStrippedPathAndSearch(url: URL, basePath: string): string;
|
|
104
107
|
declare function createAppBrowserNavigationController(deps?: BrowserNavigationControllerDeps): BrowserNavigationController;
|
|
105
108
|
//#endregion
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
|
+
import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
|
|
2
3
|
import { claimAppRouterScrollIntentForCommit, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
|
|
3
|
-
import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState } from "../shims/navigation.js";
|
|
4
|
+
import { activateNavigationSnapshot, clearPendingPathname, commitClientNavigationState, createSnapshotPathAndSearch } from "../shims/navigation.js";
|
|
4
5
|
import { shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
|
|
5
6
|
import { FRESH_APP_NAVIGATION_PAYLOAD_ORIGIN, createPendingNavigationCommit } from "./app-browser-state.js";
|
|
6
7
|
import { applyApprovedVisibleCommit, approveHmrVisibleCommit, approvePendingNavigationCommit, resolveAndClassifyNavigationCommit } from "./app-browser-visible-commit.js";
|
|
7
|
-
import { startTransition, useLayoutEffect } from "react";
|
|
8
|
+
import { startTransition, useInsertionEffect, useLayoutEffect } from "react";
|
|
9
|
+
import { flushSync } from "react-dom";
|
|
8
10
|
//#region src/server/app-browser-navigation-controller.ts
|
|
9
11
|
const HARD_NAVIGATION_LOOP_GUARD_KEY = "__vinext_hard_navigation_target__";
|
|
10
12
|
function normalizeBrowserHref(href) {
|
|
@@ -50,10 +52,6 @@ function performHardNavigationWithLoopGuard(href, mode = "assign") {
|
|
|
50
52
|
else window.location.assign(href);
|
|
51
53
|
return true;
|
|
52
54
|
}
|
|
53
|
-
function createSnapshotPathAndSearch(snapshot) {
|
|
54
|
-
const query = snapshot.searchParams.toString();
|
|
55
|
-
return query === "" ? snapshot.pathname : `${snapshot.pathname}?${query}`;
|
|
56
|
-
}
|
|
57
55
|
function createBasePathStrippedPathAndSearch(url, basePath) {
|
|
58
56
|
const pathname = stripBasePath(url.pathname, basePath);
|
|
59
57
|
const query = new URLSearchParams(url.search).toString();
|
|
@@ -76,6 +74,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
76
74
|
let nextNavigationRenderId = 0;
|
|
77
75
|
let activeNavigationId = 0;
|
|
78
76
|
const pendingNavigationCommits = /* @__PURE__ */ new Map();
|
|
77
|
+
const pendingNavigationFailureTargets = /* @__PURE__ */ new Map();
|
|
79
78
|
const pendingNavigationPrePaintEffects = /* @__PURE__ */ new Map();
|
|
80
79
|
let setBrowserRouterState = null;
|
|
81
80
|
let browserRouterStateRef = null;
|
|
@@ -194,6 +193,13 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
194
193
|
resolve();
|
|
195
194
|
}
|
|
196
195
|
}
|
|
196
|
+
function clearCommittedNavigationFailureTargets(renderId) {
|
|
197
|
+
for (const [pendingId, targetHref] of pendingNavigationFailureTargets) {
|
|
198
|
+
if (pendingId > renderId) continue;
|
|
199
|
+
pendingNavigationFailureTargets.delete(pendingId);
|
|
200
|
+
clearAppNavigationFailureTarget(targetHref);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
197
203
|
async function hmrReplaceTree(nextElements, navigationSnapshot) {
|
|
198
204
|
if (!hasBrowserRouterState()) return;
|
|
199
205
|
const pending = await createPendingNavigationCommit({
|
|
@@ -209,6 +215,9 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
209
215
|
dispatchSynchronousVisibleCommit(approveHmrVisibleCommit(pending));
|
|
210
216
|
}
|
|
211
217
|
function NavigationCommitSignal({ renderId, children }) {
|
|
218
|
+
useInsertionEffect(() => {
|
|
219
|
+
clearCommittedNavigationFailureTargets(renderId);
|
|
220
|
+
}, [renderId]);
|
|
212
221
|
useLayoutEffect(() => {
|
|
213
222
|
drainPrePaintEffects(renderId);
|
|
214
223
|
const frame = requestAnimationFrame(() => {
|
|
@@ -221,12 +230,18 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
221
230
|
}, [renderId]);
|
|
222
231
|
return children;
|
|
223
232
|
}
|
|
224
|
-
function dispatchApprovedVisibleCommit(commit, pendingRouterState) {
|
|
233
|
+
function dispatchApprovedVisibleCommit(commit, pendingRouterState, visibleCommitMode) {
|
|
225
234
|
const setter = getBrowserRouterStateSetter();
|
|
226
235
|
if (pendingRouterState) {
|
|
227
236
|
resolvePendingBrowserRouterState(pendingRouterState, commit);
|
|
228
237
|
return;
|
|
229
238
|
}
|
|
239
|
+
if (visibleCommitMode === "synchronous") {
|
|
240
|
+
flushSync(() => {
|
|
241
|
+
setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
230
245
|
startTransition(() => {
|
|
231
246
|
setter(applyApprovedVisibleCommit(getBrowserRouterState(), commit));
|
|
232
247
|
});
|
|
@@ -295,6 +310,8 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
295
310
|
}
|
|
296
311
|
async function renderNavigationPayload(options) {
|
|
297
312
|
const renderId = allocateRenderId();
|
|
313
|
+
const failureTarget = getAppNavigationFailureTarget(options.targetHref);
|
|
314
|
+
if (failureTarget) pendingNavigationFailureTargets.set(renderId, failureTarget);
|
|
298
315
|
let resolveCommitted;
|
|
299
316
|
const committed = new Promise((resolve) => {
|
|
300
317
|
resolveCommitted = resolve;
|
|
@@ -324,6 +341,8 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
324
341
|
});
|
|
325
342
|
if (approval.decision.disposition === "no-commit") {
|
|
326
343
|
settlePendingBrowserRouterState(options.pendingRouterState);
|
|
344
|
+
pendingNavigationFailureTargets.delete(renderId);
|
|
345
|
+
if (failureTarget) clearAppNavigationFailureTarget(failureTarget);
|
|
327
346
|
pendingNavigationCommits.delete(renderId);
|
|
328
347
|
resolveCommitted?.();
|
|
329
348
|
consumeAppRouterScrollIntent(options.scrollIntent ?? null);
|
|
@@ -331,9 +350,12 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
331
350
|
}
|
|
332
351
|
if (approval.decision.disposition === "hard-navigate") {
|
|
333
352
|
settlePendingBrowserRouterState(options.pendingRouterState);
|
|
353
|
+
pendingNavigationFailureTargets.delete(renderId);
|
|
334
354
|
pendingNavigationCommits.delete(renderId);
|
|
335
355
|
consumeAppRouterScrollIntent(options.scrollIntent ?? null);
|
|
336
|
-
|
|
356
|
+
if (performHardNavigation(options.targetHref)) return "hard-navigate";
|
|
357
|
+
if (failureTarget) clearAppNavigationFailureTarget(failureTarget);
|
|
358
|
+
return "no-commit";
|
|
337
359
|
}
|
|
338
360
|
const approvedCommit = approval.approvedCommit;
|
|
339
361
|
if (approvedCommit === null) throw new Error("[vinext] Commit decision did not approve a visible commit");
|
|
@@ -349,8 +371,9 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
349
371
|
claimAppRouterScrollIntentForCommit(options.scrollIntent, renderId);
|
|
350
372
|
activateNavigationSnapshot();
|
|
351
373
|
snapshotActivated = true;
|
|
352
|
-
dispatchApprovedVisibleCommit(approvedCommit, options.pendingRouterState);
|
|
374
|
+
dispatchApprovedVisibleCommit(approvedCommit, options.pendingRouterState, options.visibleCommitMode ?? "transition");
|
|
353
375
|
} catch (error) {
|
|
376
|
+
pendingNavigationFailureTargets.delete(renderId);
|
|
354
377
|
pendingNavigationPrePaintEffects.delete(renderId);
|
|
355
378
|
pendingNavigationCommits.delete(renderId);
|
|
356
379
|
if (snapshotActivated) commitClientNavigationStateImpl(options.navId);
|
|
@@ -434,6 +457,7 @@ function createAppBrowserNavigationController(deps = {}) {
|
|
|
434
457
|
commitSameUrlNavigatePayload,
|
|
435
458
|
hmrReplaceTree,
|
|
436
459
|
drainPrePaintEffects,
|
|
460
|
+
clearCommittedNavigationFailureTargets,
|
|
437
461
|
NavigationCommitSignal
|
|
438
462
|
};
|
|
439
463
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/server/app-browser-rsc-redirect.d.ts
|
|
2
|
-
declare const MAX_RSC_REDIRECT_DEPTH = 10;
|
|
3
2
|
type RscRedirectHistoryUpdateMode = "push" | "replace" | undefined;
|
|
4
3
|
type RscRedirectLifecycleDecision = {
|
|
4
|
+
href: string;
|
|
5
5
|
kind: "no-redirect";
|
|
6
6
|
} | {
|
|
7
7
|
href: string;
|
|
@@ -24,5 +24,14 @@ declare function resolveRscRedirectLifecycleHop(options: {
|
|
|
24
24
|
requestPreviousNextUrl: string | null;
|
|
25
25
|
responseUrl: string;
|
|
26
26
|
}): RscRedirectLifecycleDecision;
|
|
27
|
+
declare function resolveStreamedRscRedirectLifecycleHop(options: {
|
|
28
|
+
currentHref: string;
|
|
29
|
+
historyUpdateMode: Exclude<RscRedirectHistoryUpdateMode, undefined>;
|
|
30
|
+
maxRedirectDepth?: number;
|
|
31
|
+
origin: string;
|
|
32
|
+
redirectDepth: number;
|
|
33
|
+
requestPreviousNextUrl: string | null;
|
|
34
|
+
streamedRedirectTarget: string;
|
|
35
|
+
}): RscRedirectLifecycleDecision;
|
|
27
36
|
//#endregion
|
|
28
|
-
export {
|
|
37
|
+
export { resolveRscRedirectLifecycleHop, resolveStreamedRscRedirectLifecycleHop };
|