@rangojs/router 0.20.0 → 0.22.0
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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +29 -4
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/build-shell-capture.d.ts +8 -6
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +12 -6
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/build-shell-capture.ts +11 -9
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
* capture refuses for a root postpone (a live loader read with no boundary
|
|
28
28
|
* above it) or an SSR render error is captured here.
|
|
29
29
|
*
|
|
30
|
+
* A `Prerender` route serves its handler layer from the artifact
|
|
31
|
+
* `router.matchForPrerender` bakes for the URL (on its first request, kept
|
|
32
|
+
* until resetShellTestState), through the production prerender store. Its
|
|
33
|
+
* first `ppr` request is a MISS with a runtime capture, as a URL without a
|
|
34
|
+
* build-time shell is in production; build-time shells are e2e-only. An
|
|
35
|
+
* on-demand route (`Prerender(..., { onDemand })`) bakes nothing here: it
|
|
36
|
+
* serves from its prerender store, as a refresh-only page does in production.
|
|
37
|
+
*
|
|
30
38
|
* Must run under the `react-server` condition (the rsc Vitest project), with
|
|
31
39
|
* `rangoTestAliases()` resolving `@vitejs/plugin-rsc/rsc/server` to the stub
|
|
32
40
|
* that carries the Flight runtime.
|
|
@@ -36,14 +44,21 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
36
44
|
import { toInternal, type Rango } from "../router/router-interfaces.js";
|
|
37
45
|
import { ensureRouterManifest } from "../route-map-builder.js";
|
|
38
46
|
import type { SegmentCacheStore, ShellCacheEntry } from "../cache/types.js";
|
|
47
|
+
import {
|
|
48
|
+
awaitLaterMillisecond,
|
|
49
|
+
createCollectingExecutionContext,
|
|
50
|
+
} from "../cache/background-task.js";
|
|
39
51
|
import type { ExecutionContext } from "../types/request-scope.js";
|
|
40
52
|
import type { HandlerCacheConfig, SSRModule } from "../rsc/types.js";
|
|
41
53
|
import type { createRSCHandler } from "../rsc/handler.js";
|
|
54
|
+
import { setDefaultSSRModuleLoaderForTests } from "../rsc/ssr-module-loader.js";
|
|
42
55
|
import {
|
|
43
56
|
POST_QUIESCE_TASK_HOPS,
|
|
44
57
|
SHELL_CAPTURE_MAX_WAIT_MS,
|
|
45
58
|
} from "../rsc/shell-capture-constants.js";
|
|
46
59
|
import { SEGMENT_FRAGMENT_CAPABILITY_HEADER } from "../segment-fragments.js";
|
|
60
|
+
import { resolveDeferredHandleValues } from "../handles/deferred-resolution.js";
|
|
61
|
+
import type { HandleData } from "../server/handle-store.js";
|
|
47
62
|
import { _getRequestContext } from "../server/request-context.js";
|
|
48
63
|
import {
|
|
49
64
|
parsePprReplayStatus,
|
|
@@ -75,6 +90,30 @@ export interface ServeShellRequestOptions<TEnv = any> {
|
|
|
75
90
|
* `result.replayStatus`.
|
|
76
91
|
*/
|
|
77
92
|
partial?: true | { from?: string; segments?: readonly string[] };
|
|
93
|
+
/**
|
|
94
|
+
* POST this form as a submit before hydration: the no-JS request the
|
|
95
|
+
* progressive-enhancement path runs the action for and re-renders the page
|
|
96
|
+
* after. Build it with `createActionForm`. The response is the document
|
|
97
|
+
* (`flight` is its payload, `formState` what the SSR render received).
|
|
98
|
+
* Not with `partial`.
|
|
99
|
+
*/
|
|
100
|
+
form?: FormData;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** A response's handle data, as the browser consumes it. */
|
|
104
|
+
export interface ShellRequestHandles {
|
|
105
|
+
/**
|
|
106
|
+
* What the document hydrates with: `metadata.handles`, read to its end
|
|
107
|
+
* before hydration starts. For a `partial` request, the last state the
|
|
108
|
+
* navigation streamed.
|
|
109
|
+
*/
|
|
110
|
+
hydration: HandleData;
|
|
111
|
+
/**
|
|
112
|
+
* The states `metadata.handlesLate` delivered, in order. Each one replaces
|
|
113
|
+
* the client's handle data after hydration. Empty when nothing arrived
|
|
114
|
+
* late, and for a `partial` request.
|
|
115
|
+
*/
|
|
116
|
+
late: HandleData[];
|
|
78
117
|
}
|
|
79
118
|
|
|
80
119
|
/** Result of {@link serveShellRequest}. */
|
|
@@ -113,6 +152,24 @@ export interface ServeShellRequestResult {
|
|
|
113
152
|
* (CFCacheStore, VercelCacheStore) it warms the memo like any other read.
|
|
114
153
|
*/
|
|
115
154
|
readEntry(): Promise<ShellCacheEntry | null>;
|
|
155
|
+
/**
|
|
156
|
+
* Decode the handle data of `flight` as the browser reads it, deferred
|
|
157
|
+
* values resolved. Undefined when no Flight was rendered.
|
|
158
|
+
*/
|
|
159
|
+
readHandles(): Promise<ShellRequestHandles | undefined>;
|
|
160
|
+
/**
|
|
161
|
+
* The form state the SSR render received (the `formState` render option),
|
|
162
|
+
* or undefined when it received none.
|
|
163
|
+
*/
|
|
164
|
+
formState: unknown;
|
|
165
|
+
/**
|
|
166
|
+
* The payload's `formState` as the browser reads it, the value the entry
|
|
167
|
+
* hands `hydrateRoot`. Undefined when the payload carries none (or no
|
|
168
|
+
* Flight was rendered). Rejects when the action's state is not
|
|
169
|
+
* Flight-serializable: the document still renders, and the entry
|
|
170
|
+
* hydrates without it.
|
|
171
|
+
*/
|
|
172
|
+
readPayloadFormState(): Promise<unknown>;
|
|
116
173
|
}
|
|
117
174
|
|
|
118
175
|
type ShellHandler = ReturnType<typeof createRSCHandler>;
|
|
@@ -126,6 +183,8 @@ interface Recorder {
|
|
|
126
183
|
rendered?: boolean;
|
|
127
184
|
/** The HIT tail's Flight text. */
|
|
128
185
|
tail?: string;
|
|
186
|
+
/** The formState render option of the document render. */
|
|
187
|
+
formState?: unknown;
|
|
129
188
|
}
|
|
130
189
|
|
|
131
190
|
const recorders = new AsyncLocalStorage<Recorder>();
|
|
@@ -145,9 +204,12 @@ function recordShellKey(recorder: Recorder | undefined): void {
|
|
|
145
204
|
}
|
|
146
205
|
|
|
147
206
|
const SSR_STUB: SSRModule = {
|
|
148
|
-
async renderHTML(rscStream) {
|
|
207
|
+
async renderHTML(rscStream, options) {
|
|
149
208
|
const recorder = recorders.getStore();
|
|
150
|
-
if (recorder)
|
|
209
|
+
if (recorder) {
|
|
210
|
+
recorder.rendered = true;
|
|
211
|
+
recorder.formState = options?.formState ?? undefined;
|
|
212
|
+
}
|
|
151
213
|
recordShellKey(recorder);
|
|
152
214
|
return rscStream;
|
|
153
215
|
},
|
|
@@ -203,8 +265,134 @@ const SSR_STUB: SSRModule = {
|
|
|
203
265
|
},
|
|
204
266
|
};
|
|
205
267
|
|
|
206
|
-
/**
|
|
207
|
-
|
|
268
|
+
/**
|
|
269
|
+
* `router.prerender()` warms a route through `router.fetch`, whose handler is
|
|
270
|
+
* built with no `loadSSRModule` and so reaches for the Vite RSC module loader
|
|
271
|
+
* this project cannot run. It gets the stub the handlers below get:
|
|
272
|
+
* everything else on a warm's path (router.fetch, createRSCHandler, the match
|
|
273
|
+
* pipeline, the capture) is production code. A warm runs outside a
|
|
274
|
+
* serveShellRequest call, so the stub records nothing for it.
|
|
275
|
+
*/
|
|
276
|
+
setDefaultSSRModuleLoaderForTests(async () => SSR_STUB);
|
|
277
|
+
|
|
278
|
+
type HandleChannel = AsyncIterable<HandleData> | undefined;
|
|
279
|
+
|
|
280
|
+
/** Decode a Flight payload as the browser does. */
|
|
281
|
+
async function decodePayload<T>(flight: string): Promise<T> {
|
|
282
|
+
const { deserializeResult } = await import("../cache/segment-codec.js");
|
|
283
|
+
return deserializeResult<T>(flight);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Read a payload's two handle channels as browser/rsc-router.tsx does:
|
|
288
|
+
* `handles` to its end, then every `handlesLate` state.
|
|
289
|
+
*/
|
|
290
|
+
async function decodePayloadHandles(
|
|
291
|
+
flight: string,
|
|
292
|
+
): Promise<ShellRequestHandles> {
|
|
293
|
+
const { metadata } = await decodePayload<{
|
|
294
|
+
metadata?: { handles?: HandleChannel; handlesLate?: HandleChannel };
|
|
295
|
+
}>(flight);
|
|
296
|
+
let hydration: HandleData = {};
|
|
297
|
+
for await (const data of metadata?.handles ?? []) hydration = data;
|
|
298
|
+
const late: HandleData[] = [];
|
|
299
|
+
for await (const data of metadata?.handlesLate ?? []) {
|
|
300
|
+
late.push(await resolveDeferredHandleValues(data));
|
|
301
|
+
}
|
|
302
|
+
return { hydration: await resolveDeferredHandleValues(hydration), late };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Each router's Prerender artifacts by manifest key, as `vite build` bakes
|
|
307
|
+
* them (router.matchForPrerender), baked on a URL's first request the way the
|
|
308
|
+
* dev server's /__rsc_prerender endpoint bakes them (`devMode`: a Passthrough
|
|
309
|
+
* route keeps getParams()). `baked` holds the pathnames already tried, one
|
|
310
|
+
* that baked nothing (ctx.passthrough()) included.
|
|
311
|
+
*/
|
|
312
|
+
let prerenderArtifacts = new WeakMap<
|
|
313
|
+
object,
|
|
314
|
+
{ payloads: Map<string, string>; baked: Set<string> }
|
|
315
|
+
>();
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Serve a Prerender route's handler layer from its build-time artifact, as
|
|
319
|
+
* production does: through the store the built worker reads
|
|
320
|
+
* (createPrerenderStore over globalThis.__loadPrerenderManifestModule,
|
|
321
|
+
* installed as shell-prerender-phase.ts installs it for build-time shells).
|
|
322
|
+
* `env` stands in for the build's `buildEnv`. Returns the undo, or undefined
|
|
323
|
+
* when `pathname` matches no Prerender route.
|
|
324
|
+
*/
|
|
325
|
+
async function servePrerenderArtifacts(
|
|
326
|
+
router: Rango<any, any>,
|
|
327
|
+
pathname: string,
|
|
328
|
+
env: unknown,
|
|
329
|
+
): Promise<(() => void) | undefined> {
|
|
330
|
+
const internal = toInternal(router);
|
|
331
|
+
const matched = await internal.findMatch(pathname);
|
|
332
|
+
// A build bakes an on-demand route only for the params getParams() lists;
|
|
333
|
+
// a refresh-only page serves from its prerender store alone. A Passthrough
|
|
334
|
+
// route is baked here like a build bakes it: the `devMode` render below
|
|
335
|
+
// asks its getParams() and declines a param it does not list. A plain
|
|
336
|
+
// on-demand route is not: nothing here asks its getParams(), and baking
|
|
337
|
+
// every requested param would hide the 404 an unbaked one answers.
|
|
338
|
+
if (!matched?.pr || (matched.od && !matched.pt)) return undefined;
|
|
339
|
+
let artifacts = prerenderArtifacts.get(router);
|
|
340
|
+
if (!artifacts) {
|
|
341
|
+
prerenderArtifacts.set(
|
|
342
|
+
router,
|
|
343
|
+
(artifacts = { payloads: new Map(), baked: new Set() }),
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
const { payloads, baked } = artifacts;
|
|
347
|
+
if (!baked.has(pathname)) {
|
|
348
|
+
const result = await internal.matchForPrerender(
|
|
349
|
+
pathname,
|
|
350
|
+
{},
|
|
351
|
+
undefined,
|
|
352
|
+
matched.pt === true,
|
|
353
|
+
env,
|
|
354
|
+
true,
|
|
355
|
+
);
|
|
356
|
+
const { hashParams } = await import("../prerender/param-hash.js");
|
|
357
|
+
baked.add(pathname);
|
|
358
|
+
if (result && !result.passthrough) {
|
|
359
|
+
payloads.set(
|
|
360
|
+
`${result.routeName}/${hashParams(result.params)}`,
|
|
361
|
+
JSON.stringify({ segments: result.segments, handles: result.handles }),
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const [{ createPrerenderStore }, { setPrerenderStoreForTests }] =
|
|
366
|
+
await Promise.all([
|
|
367
|
+
import("../prerender/store.js"),
|
|
368
|
+
import("../router/match-middleware/cache-lookup.js"),
|
|
369
|
+
]);
|
|
370
|
+
const previousLoader = globalThis.__loadPrerenderManifestModule;
|
|
371
|
+
globalThis.__loadPrerenderManifestModule = async () => ({
|
|
372
|
+
default: Object.fromEntries([...payloads.keys()].map((key) => [key, key])),
|
|
373
|
+
loadPrerenderAsset: async (key) => ({
|
|
374
|
+
default: JSON.parse(payloads.get(key)!),
|
|
375
|
+
}),
|
|
376
|
+
});
|
|
377
|
+
const previousStore = setPrerenderStoreForTests(createPrerenderStore());
|
|
378
|
+
return () => {
|
|
379
|
+
globalThis.__loadPrerenderManifestModule = previousLoader;
|
|
380
|
+
setPrerenderStoreForTests(previousStore);
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Handlers per router, keyed by the `cacheStore` override or the router. A
|
|
386
|
+
* handler binds its router's document version when it is created, so an entry
|
|
387
|
+
* is reused only while the router would still resolve that version: a
|
|
388
|
+
* setBuildVersions() call (a simulated deploy) that changes it gets a new
|
|
389
|
+
* handler. The data version is read per request, so a data-only change reuses
|
|
390
|
+
* the handler, as a long-lived worker would.
|
|
391
|
+
*/
|
|
392
|
+
const handlers = new WeakMap<
|
|
393
|
+
object,
|
|
394
|
+
WeakMap<object, { handler: ShellHandler; versions: string }>
|
|
395
|
+
>();
|
|
208
396
|
|
|
209
397
|
async function getHandler(
|
|
210
398
|
router: Rango<any, any>,
|
|
@@ -212,10 +400,20 @@ async function getHandler(
|
|
|
212
400
|
): Promise<ShellHandler> {
|
|
213
401
|
let byStore = handlers.get(router);
|
|
214
402
|
if (!byStore) handlers.set(router, (byStore = new WeakMap()));
|
|
403
|
+
const internal = toInternal(router);
|
|
404
|
+
// Imported here, like the handler below: the module binds the build-only
|
|
405
|
+
// `@rangojs/router:version` virtual, which a flight-only test config (one
|
|
406
|
+
// that never serves a request) does not alias.
|
|
407
|
+
const { resolveRouterVersions } =
|
|
408
|
+
await import("../server/build-version-table.js");
|
|
409
|
+
// What createRSCHandler would resolve for this router now.
|
|
410
|
+
const { document: versions } = resolveRouterVersions(
|
|
411
|
+
internal.id,
|
|
412
|
+
internal.version,
|
|
413
|
+
);
|
|
215
414
|
const cached = byStore.get(cacheStore ?? router);
|
|
216
|
-
if (cached) return cached;
|
|
415
|
+
if (cached?.versions === versions) return cached.handler;
|
|
217
416
|
|
|
218
|
-
const internal = toInternal(router);
|
|
219
417
|
const routerCache = internal.cache;
|
|
220
418
|
// Resolved per request, as the handler resolves the router's own config.
|
|
221
419
|
const cache = (env: unknown, ctx?: ExecutionContext): HandlerCacheConfig => {
|
|
@@ -230,17 +428,28 @@ async function getHandler(
|
|
|
230
428
|
const handler = createRSCHandler({
|
|
231
429
|
router: internal,
|
|
232
430
|
nonce: internal.nonce,
|
|
233
|
-
version: internal.version,
|
|
234
431
|
loadSSRModule: async () => SSR_STUB,
|
|
235
432
|
cache: routerCache || cacheStore ? cache : undefined,
|
|
236
433
|
});
|
|
237
|
-
byStore.set(cacheStore ?? router, handler);
|
|
434
|
+
byStore.set(cacheStore ?? router, { handler, versions });
|
|
238
435
|
return handler;
|
|
239
436
|
}
|
|
240
437
|
|
|
241
438
|
function buildRequest(url: URL, options: ServeShellRequestOptions): Request {
|
|
242
439
|
const headers = new Headers(options.headers);
|
|
243
440
|
const partial = options.partial;
|
|
441
|
+
if (options.form) {
|
|
442
|
+
if (partial) {
|
|
443
|
+
throw new Error(
|
|
444
|
+
"serveShellRequest: form cannot be combined with partial",
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return new Request(url, {
|
|
448
|
+
method: "POST",
|
|
449
|
+
headers,
|
|
450
|
+
body: options.form,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
244
453
|
if (!partial) {
|
|
245
454
|
if (!headers.has("accept")) headers.set("accept", "text/html");
|
|
246
455
|
return new Request(url, { headers });
|
|
@@ -263,25 +472,30 @@ function buildRequest(url: URL, options: ServeShellRequestOptions): Request {
|
|
|
263
472
|
* starts as a fresh worker would: the capture's stampede guard, its backoff
|
|
264
473
|
* (a refused capture backs its URL off for later tests too), the shell path's
|
|
265
474
|
* once-per-key warnings, the build-shell manifest memo, the "use cache"
|
|
266
|
-
* in-flight leaders and warnings,
|
|
475
|
+
* in-flight leaders and warnings, CFCacheStore's isolate memos (shells,
|
|
267
476
|
* tag markers, tag hints) and warnings, which every CFCacheStore in the
|
|
268
|
-
* process shares by namespace and URL
|
|
269
|
-
*
|
|
270
|
-
* handle it is given: a new
|
|
477
|
+
* process shares by namespace and URL, and the Prerender artifacts baked so
|
|
478
|
+
* far. Call it in `beforeEach`, never while a request is in flight.
|
|
479
|
+
* VercelCacheStore's memos live on the `cache` handle it is given: a new
|
|
480
|
+
* handle starts empty.
|
|
271
481
|
*/
|
|
272
482
|
export async function resetShellTestState(): Promise<void> {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
483
|
+
prerenderArtifacts = new WeakMap();
|
|
484
|
+
const [capture, serve, buildShells, cf, cacheRuntime, cacheLookup] =
|
|
485
|
+
await Promise.all([
|
|
486
|
+
import("../rsc/shell-capture.js"),
|
|
487
|
+
import("../rsc/shell-serve.js"),
|
|
488
|
+
import("../rsc/shell-build-manifest.js"),
|
|
489
|
+
import("../cache/cf/cf-cache-store.js"),
|
|
490
|
+
import("../cache/cache-runtime.js"),
|
|
491
|
+
import("../router/match-middleware/cache-lookup.js"),
|
|
492
|
+
]);
|
|
280
493
|
capture.resetShellCaptureStateForTests();
|
|
281
494
|
serve.resetShellServeStateForTests();
|
|
282
495
|
buildShells.resetBuildShellManifestForTests();
|
|
283
496
|
cf.resetCFShellMemoForTests();
|
|
284
497
|
cacheRuntime.resetCacheRuntimeForTests();
|
|
498
|
+
cacheLookup.resetOverlayRevalidationsForTests();
|
|
285
499
|
}
|
|
286
500
|
|
|
287
501
|
/** Settle background tasks, including ones scheduled while settling. */
|
|
@@ -323,19 +537,15 @@ export async function serveShellRequest<TEnv = any>(
|
|
|
323
537
|
await ensureRouterManifest(router.id);
|
|
324
538
|
const handler = await getHandler(router, options.cacheStore);
|
|
325
539
|
const request = buildRequest(target, options);
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
waitUntil(promise) {
|
|
329
|
-
tasks.push(
|
|
330
|
-
Promise.resolve(promise).catch((error) =>
|
|
331
|
-
console.error("[waitUntil] Background task failed:", error),
|
|
332
|
-
),
|
|
333
|
-
);
|
|
334
|
-
},
|
|
335
|
-
passThroughOnException() {},
|
|
336
|
-
};
|
|
540
|
+
const executionContext = createCollectingExecutionContext();
|
|
541
|
+
const { tasks } = executionContext;
|
|
337
542
|
const recorder: Recorder = {};
|
|
338
|
-
|
|
543
|
+
const unservePrerender = await servePrerenderArtifacts(
|
|
544
|
+
router,
|
|
545
|
+
target.pathname,
|
|
546
|
+
options.env,
|
|
547
|
+
);
|
|
548
|
+
await awaitLaterMillisecond(called);
|
|
339
549
|
|
|
340
550
|
const { response, body } = await recorders.run(recorder, async () => {
|
|
341
551
|
try {
|
|
@@ -346,6 +556,7 @@ export async function serveShellRequest<TEnv = any>(
|
|
|
346
556
|
return { response, body: await response.text() };
|
|
347
557
|
} finally {
|
|
348
558
|
await settle(tasks);
|
|
559
|
+
unservePrerender?.();
|
|
349
560
|
}
|
|
350
561
|
});
|
|
351
562
|
|
|
@@ -353,21 +564,24 @@ export async function serveShellRequest<TEnv = any>(
|
|
|
353
564
|
recorder.cache && recorder.cache.enabled !== false
|
|
354
565
|
? recorder.cache
|
|
355
566
|
: undefined;
|
|
356
|
-
const key =
|
|
567
|
+
const key =
|
|
568
|
+
recorder.shellKey ?? shellCacheKey(router, target, config?.searchParams);
|
|
357
569
|
const tail = recorder.tail;
|
|
358
570
|
const isFlight =
|
|
359
571
|
recorder.rendered ||
|
|
360
572
|
response.headers.get("content-type")?.includes("text/x-component");
|
|
573
|
+
const prelude =
|
|
574
|
+
tail !== undefined && body.endsWith(tail)
|
|
575
|
+
? body.slice(0, body.length - tail.length)
|
|
576
|
+
: undefined;
|
|
577
|
+
const flight = tail ?? (isFlight && body ? body : undefined);
|
|
361
578
|
return {
|
|
362
579
|
response,
|
|
363
580
|
body,
|
|
364
581
|
shellStatus: parseShellStatus(response),
|
|
365
582
|
replayStatus: parsePprReplayStatus(response),
|
|
366
|
-
prelude
|
|
367
|
-
|
|
368
|
-
? body.slice(0, body.length - tail.length)
|
|
369
|
-
: undefined,
|
|
370
|
-
flight: tail ?? (isFlight && body ? body : undefined),
|
|
583
|
+
prelude,
|
|
584
|
+
flight,
|
|
371
585
|
key,
|
|
372
586
|
async readEntry() {
|
|
373
587
|
// Passive, like the serve path's own reads: a stale entry's SWR
|
|
@@ -377,5 +591,16 @@ export async function serveShellRequest<TEnv = any>(
|
|
|
377
591
|
});
|
|
378
592
|
return read?.entry ?? null;
|
|
379
593
|
},
|
|
594
|
+
async readHandles() {
|
|
595
|
+
return flight ? decodePayloadHandles(flight) : undefined;
|
|
596
|
+
},
|
|
597
|
+
formState: recorder.formState,
|
|
598
|
+
async readPayloadFormState() {
|
|
599
|
+
if (!flight) return undefined;
|
|
600
|
+
const payload = await decodePayload<{
|
|
601
|
+
formState?: Promise<unknown>;
|
|
602
|
+
}>(flight);
|
|
603
|
+
return payload.formState;
|
|
604
|
+
},
|
|
380
605
|
};
|
|
381
606
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 2. **Smallest status signals:** `x-rango-shell` (`HIT` | `MISS`) on document
|
|
16
16
|
* GETs, and `x-rango-ppr-replay` on partial requests to ppr routes. A replay
|
|
17
17
|
* HIT is reported only when matching consumes the captured segment record.
|
|
18
|
-
* Secondary unit signal: `store.getShell(shellCacheKey(url))` after a real
|
|
18
|
+
* Secondary unit signal: `store.getShell(shellCacheKey(router, url))` after a real
|
|
19
19
|
* capture flush (background `putShell`). There is no Flight flag for shell HIT.
|
|
20
20
|
*
|
|
21
21
|
* 3. **A real MISS → capture → HIT in unit tests:** `serveShellRequest`
|
|
@@ -82,10 +82,16 @@ export interface ShellCachePartition {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Shell store key for a document URL: the production
|
|
86
|
-
* pathname + sorted search + `:shell`)
|
|
87
|
-
*
|
|
88
|
-
*
|
|
85
|
+
* Shell store key of `router` for a document URL: the production
|
|
86
|
+
* `buildShellKey` (router id + host + pathname + sorted search + `:shell`)
|
|
87
|
+
* and `partitionShellKey`, both from the React-free leaf
|
|
88
|
+
* `rsc/shell-capture-constants.ts`, so the testing barrel never imports the
|
|
89
|
+
* shell-serve module (it pulls React).
|
|
90
|
+
*
|
|
91
|
+
* `router` is the router that serves the URL, or anything carrying its `id`
|
|
92
|
+
* (`{ id }` where the router cannot be imported, as in a Playwright test). A
|
|
93
|
+
* shell belongs to one router: two routers serving one host and path keep
|
|
94
|
+
* two entries.
|
|
89
95
|
*
|
|
90
96
|
* Accepts a `URL` or an absolute/relative request URL string (relative strings
|
|
91
97
|
* resolve against `http://localhost`). Pass the router's `cache.searchParams`
|
|
@@ -101,13 +107,18 @@ export interface ShellCachePartition {
|
|
|
101
107
|
* `{ keys, generated }` (see {@link ShellCachePartition}).
|
|
102
108
|
*/
|
|
103
109
|
export function shellCacheKey(
|
|
110
|
+
router: { readonly id: string },
|
|
104
111
|
url: URL | string,
|
|
105
112
|
searchParams?: CacheSearchParams,
|
|
106
113
|
partition?: string | readonly string[] | ShellCachePartition,
|
|
107
114
|
): string {
|
|
108
115
|
const resolved =
|
|
109
116
|
typeof url === "string" ? new URL(url, "http://localhost") : url;
|
|
110
|
-
const key = buildShellKey(
|
|
117
|
+
const key = buildShellKey(
|
|
118
|
+
router.id,
|
|
119
|
+
resolved,
|
|
120
|
+
compileSearchParamsFilter(searchParams),
|
|
121
|
+
);
|
|
111
122
|
if (partition === undefined) return key;
|
|
112
123
|
const { keys = [], generated = [] }: ShellCachePartition =
|
|
113
124
|
typeof partition === "string"
|
|
@@ -17,10 +17,15 @@
|
|
|
17
17
|
*
|
|
18
18
|
* Without the condition React's server build refuses to load, so the codec
|
|
19
19
|
* functions throw and a "use cache" call runs uncached. Any other load failure
|
|
20
|
-
* (a moved vendored path, a missing peer) throws.
|
|
21
|
-
*
|
|
20
|
+
* (a moved vendored path, a missing peer) throws. decodeAction and
|
|
21
|
+
* decodeFormState decode a no-JS form POST under the condition, resolving its
|
|
22
|
+
* action from the modules createActionForm() registered, as do
|
|
23
|
+
* `loadServerAction` and `decodeReply` for a plain form action. Without the
|
|
24
|
+
* condition they stay inert.
|
|
22
25
|
*/
|
|
23
26
|
|
|
27
|
+
import { loadServerModule } from "../internal/server-modules.js";
|
|
28
|
+
|
|
24
29
|
/** React's server build throws this on load without the react-server condition. */
|
|
25
30
|
const MISSING_REACT_SERVER_CONDITION =
|
|
26
31
|
/"react-server" condition must be enabled/;
|
|
@@ -52,11 +57,7 @@ async function loadFlightRuntime() {
|
|
|
52
57
|
// Resolves the `$$decode-client:` / `$$preserve:` ids a cached value's client
|
|
53
58
|
// and server references decode to; any other id would load a server module.
|
|
54
59
|
core.setRequireModule({
|
|
55
|
-
load: (id) =>
|
|
56
|
-
throw new Error(
|
|
57
|
-
`plugin-rsc stub: server reference module "${id}" is not loadable in a test`,
|
|
58
|
-
);
|
|
59
|
-
},
|
|
60
|
+
load: (id) => loadServerModule(id),
|
|
60
61
|
});
|
|
61
62
|
return { server, client, core };
|
|
62
63
|
}
|
|
@@ -121,7 +122,32 @@ export const encodeReply = (
|
|
|
121
122
|
: unavailable("encodeReply");
|
|
122
123
|
export const createClientTemporaryReferenceSet = (): unknown =>
|
|
123
124
|
runtime ? runtime.client.createTemporaryReferenceSet() : {};
|
|
124
|
-
export const loadServerAction = (): undefined =>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
export const loadServerAction = (id: string): Promise<unknown> | undefined => {
|
|
126
|
+
if (!runtime) return undefined;
|
|
127
|
+
const [file, name] = id.split("#");
|
|
128
|
+
return Promise.resolve(loadServerModule(file!)[name!]);
|
|
129
|
+
};
|
|
130
|
+
export const decodeReply = (
|
|
131
|
+
body: string | FormData,
|
|
132
|
+
options?: object,
|
|
133
|
+
): Promise<unknown> | undefined =>
|
|
134
|
+
runtime
|
|
135
|
+
? runtime.server.decodeReply(body, referenceManifest("$$server:"), options)
|
|
136
|
+
: undefined;
|
|
137
|
+
export const decodeAction = (
|
|
138
|
+
body: FormData,
|
|
139
|
+
): Promise<unknown> | null | undefined =>
|
|
140
|
+
runtime
|
|
141
|
+
? runtime.server.decodeAction(body, referenceManifest("$$server:"))
|
|
142
|
+
: undefined;
|
|
143
|
+
export const decodeFormState = (
|
|
144
|
+
actionResult: unknown,
|
|
145
|
+
body: FormData,
|
|
146
|
+
): Promise<unknown> | undefined =>
|
|
147
|
+
runtime
|
|
148
|
+
? runtime.server.decodeFormState(
|
|
149
|
+
actionResult,
|
|
150
|
+
body,
|
|
151
|
+
referenceManifest("$$server:"),
|
|
152
|
+
)
|
|
153
|
+
: undefined;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Stub for the build-only `@rangojs/router:version` virtual module, shipped so
|
|
2
2
|
// consumers do not have to author it. The rango Vite plugin injects this at
|
|
3
3
|
// build time; in a bare Vitest process it must be aliased to a stub. Empty
|
|
4
|
-
// string keeps generated URLs free of a version path segment.
|
|
4
|
+
// string keeps generated URLs free of a version path segment. There is no
|
|
5
|
+
// build table here; setBuildVersions (@rangojs/router/testing) installs one
|
|
6
|
+
// for a test that needs per-router versions.
|
|
5
7
|
export const VERSION = "";
|
|
8
|
+
export const ROUTER_VERSIONS: undefined = undefined;
|
package/src/thenable-status.ts
CHANGED
|
@@ -14,3 +14,13 @@ export function unwrapsSynchronously(stream: Promise<unknown>): boolean {
|
|
|
14
14
|
status === "resolved_module"
|
|
15
15
|
);
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A resolved thenable for a use() whose result is ignored: React reads the
|
|
20
|
+
* "fulfilled" stamp and returns at once. `_debugInfo` keeps React DevTools from
|
|
21
|
+
* listing a 0 ms promise on every reader that calls it.
|
|
22
|
+
*/
|
|
23
|
+
export const SETTLED_THENABLE: Promise<undefined> = Object.assign(
|
|
24
|
+
Promise.resolve(undefined),
|
|
25
|
+
{ status: "fulfilled", value: undefined, _debugInfo: [] },
|
|
26
|
+
);
|
|
@@ -449,6 +449,13 @@ export type InternalHandlerContext<
|
|
|
449
449
|
_responseType?: string;
|
|
450
450
|
/** Route name for cache key scoping (prevents cross-route collisions). */
|
|
451
451
|
_routeName?: string;
|
|
452
|
+
/**
|
|
453
|
+
* @internal The on-demand overlay holds a "removed" marker for this request
|
|
454
|
+
* (tryPrerenderLookup, cache-lookup.ts); gateOnDemandProducer reads it. On
|
|
455
|
+
* this context, not the request's: withCacheLookup documents that the
|
|
456
|
+
* request ALS can be lost mid-pipeline on workerd.
|
|
457
|
+
*/
|
|
458
|
+
_prerenderRemoved?: true;
|
|
452
459
|
/**
|
|
453
460
|
* @internal Loader-cache override table: loaderId -> memoized data promise.
|
|
454
461
|
* A single stable ctx.use interceptor consults this instead of chaining one
|
|
@@ -462,11 +469,14 @@ export type InternalHandlerContext<
|
|
|
462
469
|
*/
|
|
463
470
|
_loaderCacheOriginalUse?: (item: any) => any;
|
|
464
471
|
/**
|
|
465
|
-
* @internal A loader-cache HIT asks before replaying a
|
|
466
|
-
* pushes: true when that loader has not run in this
|
|
467
|
-
* replay delivered it; its later run then replaces
|
|
468
|
-
* (HandleStore.pushReplayed). One copy per loader per
|
|
469
|
-
*
|
|
472
|
+
* @internal A loader-cache or "use cache" HIT asks before replaying a
|
|
473
|
+
* loader's recorded pushes: true when that loader has not run in this
|
|
474
|
+
* request and no other replay delivered it; its later run then replaces
|
|
475
|
+
* the replayed values (HandleStore.pushReplayed). One copy per loader per
|
|
476
|
+
* request. A record's restore does not ask (restoreHandles): its copies
|
|
477
|
+
* are the pinned loader's own, or placeholders the claimed replay
|
|
478
|
+
* replaces. Absent on a stale refresh's ctx, whose pushes are diverted
|
|
479
|
+
* (handle-snapshot.ts appendHandles). See setupLoaderAccess.
|
|
470
480
|
*/
|
|
471
481
|
_claimLoaderPushes?: (loaderId: string) => boolean;
|
|
472
482
|
/**
|
package/src/types/route-entry.ts
CHANGED
|
@@ -82,6 +82,12 @@ export interface RouteEntry<TEnv = any> {
|
|
|
82
82
|
*/
|
|
83
83
|
passthroughRouteKeys?: Set<string>;
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Route keys in this entry that opted into on-demand prerender.
|
|
87
|
+
* Used by the non-trie match path to set the `od` flag.
|
|
88
|
+
*/
|
|
89
|
+
onDemandRouteKeys?: Set<string>;
|
|
90
|
+
|
|
85
91
|
// === Lazy evaluation fields ===
|
|
86
92
|
|
|
87
93
|
/**
|