@rangojs/router 0.0.0-experimental.98 → 0.0.0-experimental.98914650
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 +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +60 -11
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -26
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +22 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +310 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +3 -6
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -11
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -41
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -42
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +20 -58
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -47
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -35
- package/src/vite/utils/shared-utils.ts +95 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getParallelEntries,
|
|
15
15
|
getParallelSlotEntries,
|
|
16
16
|
type EntryData,
|
|
17
|
+
type ParallelEntryData,
|
|
17
18
|
} from "../../server/context";
|
|
18
19
|
import type {
|
|
19
20
|
HandlerContext,
|
|
@@ -34,61 +35,22 @@ import {
|
|
|
34
35
|
import { resolveLoaderData } from "./loader-cache.js";
|
|
35
36
|
import {
|
|
36
37
|
handleHandlerResult,
|
|
38
|
+
warnOnStreamedResponse,
|
|
37
39
|
tryStaticHandler,
|
|
38
40
|
tryStaticSlot,
|
|
39
41
|
resolveLayoutComponent,
|
|
40
42
|
resolveWithErrorBoundary,
|
|
41
43
|
} from "./helpers.js";
|
|
44
|
+
import { applyViewTransitionDefault } from "./view-transition-default.js";
|
|
42
45
|
import { getRouterContext } from "../router-context.js";
|
|
43
46
|
import { resolveSink, safeEmit } from "../telemetry.js";
|
|
47
|
+
import { observeStreamedHandler } from "./streamed-handler-telemetry.js";
|
|
44
48
|
import {
|
|
45
49
|
track,
|
|
46
|
-
|
|
50
|
+
RangoContext,
|
|
47
51
|
runInsideLoaderScope,
|
|
48
52
|
} from "../../server/context.js";
|
|
49
53
|
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// Telemetry helpers
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Attach a fire-and-forget rejection observer to a streamed handler promise.
|
|
56
|
-
* Silently no-ops when called outside RouterContext (e.g. in unit tests).
|
|
57
|
-
*/
|
|
58
|
-
function observeStreamedHandler(
|
|
59
|
-
promise: Promise<ReactNode>,
|
|
60
|
-
segmentId: string,
|
|
61
|
-
segmentType: string,
|
|
62
|
-
pathname?: string,
|
|
63
|
-
routeKey?: string,
|
|
64
|
-
params?: Record<string, string>,
|
|
65
|
-
): void {
|
|
66
|
-
let routerCtx;
|
|
67
|
-
try {
|
|
68
|
-
routerCtx = getRouterContext();
|
|
69
|
-
} catch {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (!routerCtx?.telemetry) return;
|
|
73
|
-
const sink = resolveSink(routerCtx.telemetry);
|
|
74
|
-
const reqId = routerCtx.requestId;
|
|
75
|
-
promise.catch((err: unknown) => {
|
|
76
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
77
|
-
safeEmit(sink, {
|
|
78
|
-
type: "handler.error",
|
|
79
|
-
timestamp: performance.now(),
|
|
80
|
-
requestId: reqId,
|
|
81
|
-
segmentId,
|
|
82
|
-
segmentType,
|
|
83
|
-
error: errorObj,
|
|
84
|
-
handledByBoundary: true,
|
|
85
|
-
pathname,
|
|
86
|
-
routeKey,
|
|
87
|
-
params,
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
54
|
/**
|
|
93
55
|
* Trace a parallel slot that's being force-rendered on a full refetch (client
|
|
94
56
|
* has no cached state). User revalidate fns are bypassed in this case — see
|
|
@@ -425,6 +387,97 @@ export function buildEntryRevalidateMap(
|
|
|
425
387
|
return map;
|
|
426
388
|
}
|
|
427
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Resolve the component for a single parallel slot on the revalidation path.
|
|
392
|
+
* Pure component resolution shared verbatim by
|
|
393
|
+
* resolveParallelSegmentsWithRevalidation and the orphan-inlined loop in
|
|
394
|
+
* resolveOrphanLayoutWithRevalidation: try the static slot cache, else run the
|
|
395
|
+
* slot handler (pinning _currentSegmentId to the slot id so handle pushes land
|
|
396
|
+
* in the slot's own bucket, and wrapping a streamed handler). Returns the
|
|
397
|
+
* resolved component and whether the handler actually ran. Does NOT touch the
|
|
398
|
+
* revalidate-default policy (the caller decides shouldResolve, including the
|
|
399
|
+
* orphan-vs-main defaultOverride divergence) or loader-resolution ordering.
|
|
400
|
+
*/
|
|
401
|
+
async function resolveParallelSlotComponent<TEnv>(args: {
|
|
402
|
+
shouldResolve: boolean;
|
|
403
|
+
parallelEntry: ParallelEntryData;
|
|
404
|
+
slot: string;
|
|
405
|
+
parallelId: string;
|
|
406
|
+
handler:
|
|
407
|
+
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
408
|
+
| ReactNode
|
|
409
|
+
| undefined;
|
|
410
|
+
context: HandlerContext<any, TEnv>;
|
|
411
|
+
deps: SegmentResolutionDeps<TEnv>;
|
|
412
|
+
routeKey: string;
|
|
413
|
+
params: Record<string, string>;
|
|
414
|
+
}): Promise<{ component: ReactNode | undefined; handlerRan: boolean }> {
|
|
415
|
+
const {
|
|
416
|
+
shouldResolve,
|
|
417
|
+
parallelEntry,
|
|
418
|
+
slot,
|
|
419
|
+
parallelId,
|
|
420
|
+
handler,
|
|
421
|
+
context,
|
|
422
|
+
deps,
|
|
423
|
+
routeKey,
|
|
424
|
+
params,
|
|
425
|
+
} = args;
|
|
426
|
+
|
|
427
|
+
let component: ReactNode | undefined;
|
|
428
|
+
let handlerRan = false;
|
|
429
|
+
if (shouldResolve) {
|
|
430
|
+
component = await tryStaticSlot(parallelEntry, slot, parallelId);
|
|
431
|
+
// tryStaticSlot returning a value means the static cache supplied the
|
|
432
|
+
// component — handler did NOT run. handlerRan stays false.
|
|
433
|
+
}
|
|
434
|
+
if (component === undefined) {
|
|
435
|
+
const hasLoadingFallback =
|
|
436
|
+
parallelEntry.loading !== undefined && parallelEntry.loading !== false;
|
|
437
|
+
if (!shouldResolve) {
|
|
438
|
+
component = null;
|
|
439
|
+
} else if (handler === undefined) {
|
|
440
|
+
// Handler evicted (production static slot) but static lookup missed.
|
|
441
|
+
// Nothing to render — use null so the client keeps its cached version.
|
|
442
|
+
component = null;
|
|
443
|
+
} else {
|
|
444
|
+
// Slot-keyed pushes — slot owns its own bucket, parent layout owns its
|
|
445
|
+
// own. On slot-only revalidations the partial merge updates only the
|
|
446
|
+
// slot's bucket; the parent's bucket stays intact.
|
|
447
|
+
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
448
|
+
parallelId;
|
|
449
|
+
handlerRan = true;
|
|
450
|
+
if (hasLoadingFallback) {
|
|
451
|
+
const result =
|
|
452
|
+
typeof handler === "function" ? handler(context) : handler;
|
|
453
|
+
if (result instanceof Promise) {
|
|
454
|
+
warnOnStreamedResponse(result, parallelId);
|
|
455
|
+
const tracked = deps.trackHandler(result, {
|
|
456
|
+
segmentId: parallelId,
|
|
457
|
+
segmentType: "parallel",
|
|
458
|
+
});
|
|
459
|
+
observeStreamedHandler(
|
|
460
|
+
tracked,
|
|
461
|
+
parallelId,
|
|
462
|
+
"parallel",
|
|
463
|
+
context.pathname,
|
|
464
|
+
routeKey,
|
|
465
|
+
params,
|
|
466
|
+
);
|
|
467
|
+
component = tracked as ReactNode;
|
|
468
|
+
} else {
|
|
469
|
+
component = result as ReactNode;
|
|
470
|
+
}
|
|
471
|
+
} else {
|
|
472
|
+
component =
|
|
473
|
+
typeof handler === "function" ? await handler(context) : handler;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return { component, handlerRan };
|
|
479
|
+
}
|
|
480
|
+
|
|
428
481
|
/**
|
|
429
482
|
* Resolve parallel segments with revalidation.
|
|
430
483
|
*/
|
|
@@ -442,9 +495,30 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
442
495
|
deps: SegmentResolutionDeps<TEnv>,
|
|
443
496
|
actionContext?: ActionContext,
|
|
444
497
|
stale?: boolean,
|
|
498
|
+
options?: {
|
|
499
|
+
/**
|
|
500
|
+
* Seed for an unknown parent-chain slot (slot not in clientSegmentIds) when
|
|
501
|
+
* there are no deciding revalidate fns. "type-derived" (default, main path):
|
|
502
|
+
* `belongsToRoute || isNewParent`. "force-render" (orphan path): always
|
|
503
|
+
* `true` — orphan parallels always belong to the route and must render
|
|
504
|
+
* unless the user opts out via revalidate(); the #482 blank-parent-chain-
|
|
505
|
+
* slot guard.
|
|
506
|
+
*/
|
|
507
|
+
parentChainDefault?: "type-derived" | "force-render";
|
|
508
|
+
/**
|
|
509
|
+
* When a slot's loaders are resolved relative to the slot segment push.
|
|
510
|
+
* "after" (default, main path) pushes the slot segment first; "before"
|
|
511
|
+
* (orphan path) resolves loaders first. This only changes the
|
|
512
|
+
* segments/matchedIds emission ORDER (the client reconciler is insensitive
|
|
513
|
+
* to it: loader sub-ids are filtered out and slots are re-grouped by parent).
|
|
514
|
+
*/
|
|
515
|
+
loaderOrder?: "after" | "before";
|
|
516
|
+
},
|
|
445
517
|
): Promise<SegmentRevalidationResult> {
|
|
446
518
|
const segments: ResolvedSegment[] = [];
|
|
447
519
|
const matchedIds: string[] = [];
|
|
520
|
+
const parentChainDefault = options?.parentChainDefault ?? "type-derived";
|
|
521
|
+
const loaderOrder = options?.loaderOrder ?? "after";
|
|
448
522
|
|
|
449
523
|
const resolvedParallelEntries = new Set<string>();
|
|
450
524
|
for (const { slot, entry: parallelEntry } of getParallelSlotEntries(
|
|
@@ -469,6 +543,34 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
469
543
|
|
|
470
544
|
const isFullRefetch = clientSegmentIds.size === 0;
|
|
471
545
|
const isNewParent = !clientSegmentIds.has(entry.shortCode);
|
|
546
|
+
|
|
547
|
+
// A slot's loaders (never cached) are deduped per parallel entry and
|
|
548
|
+
// emitted either before or after the slot segment per loaderOrder.
|
|
549
|
+
const resolveSlotLoaders = async () => {
|
|
550
|
+
if (resolvedParallelEntries.has(parallelEntry.id)) return;
|
|
551
|
+
const loaderResult = await resolveLoadersWithRevalidation(
|
|
552
|
+
parallelEntry,
|
|
553
|
+
context,
|
|
554
|
+
belongsToRoute,
|
|
555
|
+
clientSegmentIds,
|
|
556
|
+
prevParams,
|
|
557
|
+
request,
|
|
558
|
+
prevUrl,
|
|
559
|
+
nextUrl,
|
|
560
|
+
routeKey,
|
|
561
|
+
deps,
|
|
562
|
+
actionContext,
|
|
563
|
+
entry.shortCode,
|
|
564
|
+
stale,
|
|
565
|
+
);
|
|
566
|
+
segments.push(...loaderResult.segments);
|
|
567
|
+
matchedIds.push(...loaderResult.matchedIds);
|
|
568
|
+
resolvedParallelEntries.add(parallelEntry.id);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
if (loaderOrder === "before") {
|
|
572
|
+
await resolveSlotLoaders();
|
|
573
|
+
}
|
|
472
574
|
// Always announce the slot in matchedIds — it's unconditionally appended
|
|
473
575
|
// to `segments` below, and a segment present in segments but missing from
|
|
474
576
|
// matched lets the client prune it (then it's missing from clientSegmentIds
|
|
@@ -488,7 +590,10 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
488
590
|
// soft chain seeds with the right "new segment" / "parent-chain" value.
|
|
489
591
|
let defaultOverride: { value: boolean; reason: string } | undefined;
|
|
490
592
|
if (!clientSegmentIds.has(parallelId)) {
|
|
491
|
-
const value =
|
|
593
|
+
const value =
|
|
594
|
+
parentChainDefault === "force-render"
|
|
595
|
+
? true
|
|
596
|
+
: belongsToRoute || isNewParent;
|
|
492
597
|
defaultOverride = {
|
|
493
598
|
value,
|
|
494
599
|
reason: value ? "new-segment" : "skip-parent-chain",
|
|
@@ -536,55 +641,17 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
536
641
|
shouldResolve,
|
|
537
642
|
);
|
|
538
643
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
component = null;
|
|
551
|
-
} else if (handler === undefined) {
|
|
552
|
-
// Handler evicted (production static slot) but static lookup missed.
|
|
553
|
-
// Nothing to render — use null so the client keeps its cached version.
|
|
554
|
-
component = null;
|
|
555
|
-
} else {
|
|
556
|
-
// Slot-keyed pushes — slot owns its own bucket, parent layout owns
|
|
557
|
-
// its own. On slot-only revalidations the partial merge updates only
|
|
558
|
-
// the slot's bucket; the parent's bucket stays intact.
|
|
559
|
-
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
560
|
-
parallelId;
|
|
561
|
-
handlerRan = true;
|
|
562
|
-
if (hasLoadingFallback) {
|
|
563
|
-
const result =
|
|
564
|
-
typeof handler === "function" ? handler(context) : handler;
|
|
565
|
-
if (result instanceof Promise) {
|
|
566
|
-
const tracked = deps.trackHandler(result, {
|
|
567
|
-
segmentId: parallelId,
|
|
568
|
-
segmentType: "parallel",
|
|
569
|
-
});
|
|
570
|
-
observeStreamedHandler(
|
|
571
|
-
tracked,
|
|
572
|
-
parallelId,
|
|
573
|
-
"parallel",
|
|
574
|
-
context.pathname,
|
|
575
|
-
routeKey,
|
|
576
|
-
params,
|
|
577
|
-
);
|
|
578
|
-
component = tracked as ReactNode;
|
|
579
|
-
} else {
|
|
580
|
-
component = result as ReactNode;
|
|
581
|
-
}
|
|
582
|
-
} else {
|
|
583
|
-
component =
|
|
584
|
-
typeof handler === "function" ? await handler(context) : handler;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
644
|
+
const { component, handlerRan } = await resolveParallelSlotComponent({
|
|
645
|
+
shouldResolve,
|
|
646
|
+
parallelEntry,
|
|
647
|
+
slot,
|
|
648
|
+
parallelId,
|
|
649
|
+
handler,
|
|
650
|
+
context,
|
|
651
|
+
deps,
|
|
652
|
+
routeKey,
|
|
653
|
+
params,
|
|
654
|
+
});
|
|
588
655
|
|
|
589
656
|
segments.push({
|
|
590
657
|
id: parallelId,
|
|
@@ -593,7 +660,10 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
593
660
|
index: 0,
|
|
594
661
|
component,
|
|
595
662
|
loading: parallelEntry.loading === false ? null : parallelEntry.loading,
|
|
596
|
-
transition:
|
|
663
|
+
transition: applyViewTransitionDefault(
|
|
664
|
+
parallelEntry.transition,
|
|
665
|
+
deps.viewTransitionDefault,
|
|
666
|
+
),
|
|
597
667
|
params,
|
|
598
668
|
slot,
|
|
599
669
|
_handlerRan: handlerRan,
|
|
@@ -604,28 +674,9 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
604
674
|
: {}),
|
|
605
675
|
});
|
|
606
676
|
|
|
607
|
-
if (
|
|
608
|
-
|
|
677
|
+
if (loaderOrder === "after") {
|
|
678
|
+
await resolveSlotLoaders();
|
|
609
679
|
}
|
|
610
|
-
|
|
611
|
-
const loaderResult = await resolveLoadersWithRevalidation(
|
|
612
|
-
parallelEntry,
|
|
613
|
-
context,
|
|
614
|
-
belongsToRoute,
|
|
615
|
-
clientSegmentIds,
|
|
616
|
-
prevParams,
|
|
617
|
-
request,
|
|
618
|
-
prevUrl,
|
|
619
|
-
nextUrl,
|
|
620
|
-
routeKey,
|
|
621
|
-
deps,
|
|
622
|
-
actionContext,
|
|
623
|
-
entry.shortCode,
|
|
624
|
-
stale,
|
|
625
|
-
);
|
|
626
|
-
segments.push(...loaderResult.segments);
|
|
627
|
-
matchedIds.push(...loaderResult.matchedIds);
|
|
628
|
-
resolvedParallelEntries.add(parallelEntry.id);
|
|
629
680
|
}
|
|
630
681
|
|
|
631
682
|
return { segments, matchedIds };
|
|
@@ -758,6 +809,7 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
758
809
|
if (!actionContext) {
|
|
759
810
|
const result = handleHandlerResult(handler(context));
|
|
760
811
|
if (result instanceof Promise) {
|
|
812
|
+
warnOnStreamedResponse(result, routeEntry.id);
|
|
761
813
|
result.finally(doneHandler).catch(() => {});
|
|
762
814
|
const tracked = deps.trackHandler(result, {
|
|
763
815
|
segmentId: entry.shortCode,
|
|
@@ -803,7 +855,10 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
803
855
|
index: 0,
|
|
804
856
|
component: resolvedComponent,
|
|
805
857
|
loading: entry.loading === false ? null : entry.loading,
|
|
806
|
-
transition:
|
|
858
|
+
transition: applyViewTransitionDefault(
|
|
859
|
+
entry.transition,
|
|
860
|
+
deps.viewTransitionDefault,
|
|
861
|
+
),
|
|
807
862
|
params,
|
|
808
863
|
belongsToRoute,
|
|
809
864
|
...(entry.type === "layout" || entry.type === "cache"
|
|
@@ -829,7 +884,6 @@ export async function resolveSegmentWithRevalidation<TEnv>(
|
|
|
829
884
|
request: Request,
|
|
830
885
|
prevUrl: URL,
|
|
831
886
|
nextUrl: URL,
|
|
832
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
833
887
|
deps: SegmentResolutionDeps<TEnv>,
|
|
834
888
|
actionContext?: ActionContext,
|
|
835
889
|
stale?: boolean,
|
|
@@ -1137,174 +1191,40 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1137
1191
|
belongsToRoute,
|
|
1138
1192
|
layoutName: orphan.id,
|
|
1139
1193
|
loading: orphan.loading === false ? null : orphan.loading,
|
|
1140
|
-
transition:
|
|
1194
|
+
transition: applyViewTransitionDefault(
|
|
1195
|
+
orphan.transition,
|
|
1196
|
+
deps.viewTransitionDefault,
|
|
1197
|
+
),
|
|
1141
1198
|
...(orphan.mountPath ? { mountPath: orphan.mountPath } : {}),
|
|
1142
1199
|
});
|
|
1143
1200
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
)
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
matchedIds.push(...loaderResult.matchedIds);
|
|
1172
|
-
resolvedParallelEntries.add(parallelEntry.id);
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
const slots = parallelEntry.handler as Record<
|
|
1176
|
-
`@${string}`,
|
|
1177
|
-
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
1178
|
-
| ReactNode
|
|
1179
|
-
>;
|
|
1180
|
-
// Handler may be undefined in production after static handler eviction.
|
|
1181
|
-
const handler = slots[slot];
|
|
1182
|
-
|
|
1183
|
-
// Use orphan.shortCode (the parent layout) to match the SSR path
|
|
1184
|
-
// (resolveParallelEntry receives parentShortCode = orphan.shortCode).
|
|
1185
|
-
// Using parallelEntry.shortCode would generate IDs the client doesn't know about.
|
|
1186
|
-
const parallelId = `${orphan.shortCode}.${slot}`;
|
|
1187
|
-
matchedIds.push(parallelId);
|
|
1188
|
-
|
|
1189
|
-
const isFullRefetch = clientSegmentIds.size === 0;
|
|
1190
|
-
let shouldResolve: boolean;
|
|
1191
|
-
if (isFullRefetch) {
|
|
1192
|
-
// Same load-bearing rationale as the main parallel path: full refetch
|
|
1193
|
-
// means the client has nothing to fall back to, so the slot must render.
|
|
1194
|
-
traceFullRefetchedParallelSlot(parallelId, belongsToRoute);
|
|
1195
|
-
shouldResolve = true;
|
|
1196
|
-
} else {
|
|
1197
|
-
// When slot is unknown to the client, seed the soft chain with `true`
|
|
1198
|
-
// (orphan parallels always belong to the route — we want them rendered
|
|
1199
|
-
// unless the user explicitly opts out via revalidate()).
|
|
1200
|
-
const defaultOverride = clientSegmentIds.has(parallelId)
|
|
1201
|
-
? undefined
|
|
1202
|
-
: { value: true, reason: "new-segment" };
|
|
1203
|
-
|
|
1204
|
-
const dummySegment: ResolvedSegment = {
|
|
1205
|
-
id: parallelId,
|
|
1206
|
-
namespace: parallelEntry.id,
|
|
1207
|
-
type: "parallel",
|
|
1208
|
-
index: 0,
|
|
1209
|
-
component: null as any,
|
|
1210
|
-
params,
|
|
1211
|
-
slot,
|
|
1212
|
-
belongsToRoute,
|
|
1213
|
-
parallelName: `${parallelEntry.id}.${slot}`,
|
|
1214
|
-
...(parallelEntry.mountPath
|
|
1215
|
-
? { mountPath: parallelEntry.mountPath }
|
|
1216
|
-
: {}),
|
|
1217
|
-
};
|
|
1218
|
-
|
|
1219
|
-
shouldResolve = await evaluateRevalidation({
|
|
1220
|
-
segment: dummySegment,
|
|
1221
|
-
prevParams,
|
|
1222
|
-
getPrevSegment: null,
|
|
1223
|
-
request,
|
|
1224
|
-
prevUrl,
|
|
1225
|
-
nextUrl,
|
|
1226
|
-
revalidations: parallelEntry.revalidate.map((fn, i) => ({
|
|
1227
|
-
name: `revalidate${i}`,
|
|
1228
|
-
fn,
|
|
1229
|
-
})),
|
|
1230
|
-
routeKey,
|
|
1231
|
-
context,
|
|
1232
|
-
actionContext,
|
|
1233
|
-
stale,
|
|
1234
|
-
traceSource: "parallel",
|
|
1235
|
-
defaultOverride,
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
emitRevalidationDecision(
|
|
1239
|
-
parallelId,
|
|
1240
|
-
context.pathname,
|
|
1241
|
-
routeKey,
|
|
1242
|
-
shouldResolve,
|
|
1243
|
-
);
|
|
1244
|
-
|
|
1245
|
-
let component: ReactNode | undefined;
|
|
1246
|
-
let handlerRan = false;
|
|
1247
|
-
if (shouldResolve) {
|
|
1248
|
-
component = await tryStaticSlot(parallelEntry, slot, parallelId);
|
|
1249
|
-
}
|
|
1250
|
-
if (component === undefined) {
|
|
1251
|
-
const hasLoadingFallback =
|
|
1252
|
-
parallelEntry.loading !== undefined && parallelEntry.loading !== false;
|
|
1253
|
-
if (!shouldResolve) {
|
|
1254
|
-
component = null;
|
|
1255
|
-
} else if (handler === undefined) {
|
|
1256
|
-
// Handler evicted (production static slot) but static lookup missed.
|
|
1257
|
-
component = null;
|
|
1258
|
-
} else {
|
|
1259
|
-
// Slot-keyed pushes — see resolveParallelSegmentsWithRevalidation.
|
|
1260
|
-
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
1261
|
-
parallelId;
|
|
1262
|
-
handlerRan = true;
|
|
1263
|
-
if (hasLoadingFallback) {
|
|
1264
|
-
const result =
|
|
1265
|
-
typeof handler === "function" ? handler(context) : handler;
|
|
1266
|
-
if (result instanceof Promise) {
|
|
1267
|
-
const tracked = deps.trackHandler(result, {
|
|
1268
|
-
segmentId: parallelId,
|
|
1269
|
-
segmentType: "parallel",
|
|
1270
|
-
});
|
|
1271
|
-
observeStreamedHandler(
|
|
1272
|
-
tracked,
|
|
1273
|
-
parallelId,
|
|
1274
|
-
"parallel",
|
|
1275
|
-
context.pathname,
|
|
1276
|
-
routeKey,
|
|
1277
|
-
params,
|
|
1278
|
-
);
|
|
1279
|
-
component = tracked as ReactNode;
|
|
1280
|
-
} else {
|
|
1281
|
-
component = result as ReactNode;
|
|
1282
|
-
}
|
|
1283
|
-
} else {
|
|
1284
|
-
component =
|
|
1285
|
-
typeof handler === "function" ? await handler(context) : handler;
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
segments.push({
|
|
1291
|
-
id: parallelId,
|
|
1292
|
-
namespace: parallelEntry.id,
|
|
1293
|
-
type: "parallel",
|
|
1294
|
-
index: 0,
|
|
1295
|
-
component,
|
|
1296
|
-
loading: parallelEntry.loading === false ? null : parallelEntry.loading,
|
|
1297
|
-
transition: parallelEntry.transition,
|
|
1298
|
-
params,
|
|
1299
|
-
slot,
|
|
1300
|
-
_handlerRan: handlerRan,
|
|
1301
|
-
belongsToRoute,
|
|
1302
|
-
parallelName: `${parallelEntry.id}.${slot}`,
|
|
1303
|
-
...(parallelEntry.mountPath
|
|
1304
|
-
? { mountPath: parallelEntry.mountPath }
|
|
1305
|
-
: {}),
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1201
|
+
// Resolve the orphan layout's parallel slots through the shared main-path
|
|
1202
|
+
// helper. The orphan policy is carried by explicit args, byte-for-byte:
|
|
1203
|
+
// - parentChainDefault "force-render": an unknown parent-chain slot seeds
|
|
1204
|
+
// `true` (orphan parallels always belong to the route — the #482 guard),
|
|
1205
|
+
// where the main path would seed `belongsToRoute || isNewParent`.
|
|
1206
|
+
// - loaderOrder "before": a slot's loaders are emitted before the slot
|
|
1207
|
+
// segment, matching the prior inlined order.
|
|
1208
|
+
// `entry.shortCode` inside the helper is `orphan.shortCode` (orphan is passed
|
|
1209
|
+
// as `entry`), so the parallel ids + loader shortCodeOverride are unchanged.
|
|
1210
|
+
const parallelResult = await resolveParallelSegmentsWithRevalidation(
|
|
1211
|
+
orphan,
|
|
1212
|
+
params,
|
|
1213
|
+
context,
|
|
1214
|
+
belongsToRoute,
|
|
1215
|
+
clientSegmentIds,
|
|
1216
|
+
prevParams,
|
|
1217
|
+
request,
|
|
1218
|
+
prevUrl,
|
|
1219
|
+
nextUrl,
|
|
1220
|
+
routeKey,
|
|
1221
|
+
deps,
|
|
1222
|
+
actionContext,
|
|
1223
|
+
stale,
|
|
1224
|
+
{ parentChainDefault: "force-render", loaderOrder: "before" },
|
|
1225
|
+
);
|
|
1226
|
+
segments.push(...parallelResult.segments);
|
|
1227
|
+
matchedIds.push(...parallelResult.matchedIds);
|
|
1308
1228
|
|
|
1309
1229
|
return { segments, matchedIds };
|
|
1310
1230
|
}
|
|
@@ -1322,7 +1242,6 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1322
1242
|
request: Request,
|
|
1323
1243
|
prevUrl: URL,
|
|
1324
1244
|
nextUrl: URL,
|
|
1325
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
1326
1245
|
actionContext: ActionContext | undefined,
|
|
1327
1246
|
interceptResult: { intercept: any; entry: EntryData } | null,
|
|
1328
1247
|
localRouteName: string,
|
|
@@ -1356,7 +1275,7 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1356
1275
|
|
|
1357
1276
|
const nonParallelEntry = entry as Exclude<EntryData, { type: "parallel" }>;
|
|
1358
1277
|
if (entry.type === "cache") {
|
|
1359
|
-
const store =
|
|
1278
|
+
const store = RangoContext.getStore();
|
|
1360
1279
|
if (store) store.insideCacheScope = true;
|
|
1361
1280
|
}
|
|
1362
1281
|
const doneEntry = track(`segment:${entry.id}`, 1);
|
|
@@ -1374,7 +1293,6 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1374
1293
|
request,
|
|
1375
1294
|
prevUrl,
|
|
1376
1295
|
nextUrl,
|
|
1377
|
-
loaderPromises,
|
|
1378
1296
|
deps,
|
|
1379
1297
|
actionContext,
|
|
1380
1298
|
stale,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import type { ReactNode } from "react";
|
|
9
9
|
import { _getRequestContext } from "../../server/request-context.js";
|
|
10
10
|
import type { StaticStore } from "../../prerender/store.js";
|
|
11
|
+
import type { SegmentHandleData } from "../../cache/types.js";
|
|
11
12
|
|
|
12
13
|
// Lazy-initialized static store for production Static handler interception.
|
|
13
14
|
// Remains undefined until first check; null means checked but no manifest.
|
|
@@ -19,6 +20,9 @@ let _staticStore: StaticStore | null | undefined =
|
|
|
19
20
|
? undefined
|
|
20
21
|
: null;
|
|
21
22
|
let _deserializeComponent: ((encoded: string) => Promise<unknown>) | undefined;
|
|
23
|
+
let _decodeHandleValue:
|
|
24
|
+
| typeof import("../../cache/handle-snapshot.js").decodeHandleValue
|
|
25
|
+
| undefined;
|
|
22
26
|
|
|
23
27
|
async function ensureStaticDeps(): Promise<void> {
|
|
24
28
|
if (_staticStore === undefined) {
|
|
@@ -29,6 +33,9 @@ async function ensureStaticDeps(): Promise<void> {
|
|
|
29
33
|
const { deserializeComponent } =
|
|
30
34
|
await import("../../cache/segment-codec.js");
|
|
31
35
|
_deserializeComponent = deserializeComponent;
|
|
36
|
+
const { decodeHandleValue } =
|
|
37
|
+
await import("../../cache/handle-snapshot.js");
|
|
38
|
+
_decodeHandleValue = decodeHandleValue;
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
|
|
@@ -53,13 +60,20 @@ export async function tryStaticLookup(
|
|
|
53
60
|
const entry = await _staticStore.get(handlerId);
|
|
54
61
|
if (!entry) return undefined;
|
|
55
62
|
|
|
56
|
-
// Replay handle data captured during build-time rendering.
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
63
|
+
// Replay handle data captured during build-time rendering. entry.handles is a
|
|
64
|
+
// Flight-encoded string ("" when none) — decode before replay so
|
|
65
|
+
// Promise/ReactNode handle values are revived. The data was keyed by handlerId
|
|
66
|
+
// at build time; replay under segmentId so it matches the segment order used
|
|
67
|
+
// by useHandle on the client.
|
|
68
|
+
if (entry.handles && _decodeHandleValue) {
|
|
60
69
|
const handleStore = _getRequestContext()?._handleStore;
|
|
61
70
|
if (handleStore) {
|
|
62
|
-
|
|
71
|
+
const segHandles = await _decodeHandleValue<SegmentHandleData>(
|
|
72
|
+
entry.handles,
|
|
73
|
+
);
|
|
74
|
+
if (segHandles) {
|
|
75
|
+
handleStore.replaySegmentData(segmentId, segHandles);
|
|
76
|
+
}
|
|
63
77
|
}
|
|
64
78
|
}
|
|
65
79
|
|