@rangojs/router 0.16.0 → 0.18.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/README.md +255 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -0
- package/dist/types/browser/navigation-transaction.d.ts +6 -0
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/scroll-restoration.d.ts +7 -0
- package/dist/types/cache/cache-exec-scope.d.ts +18 -1
- package/dist/types/cache/cache-key-utils.d.ts +17 -2
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +132 -19
- package/dist/types/cache/cache-tag.d.ts +92 -7
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +54 -13
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +110 -21
- package/dist/types/cache/tag-invalidation.d.ts +30 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +220 -44
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.rsc.d.ts +4 -5
- package/dist/types/components/DefaultDocument.d.ts +5 -2
- package/dist/types/context-var.d.ts +6 -5
- package/dist/types/escape-script.d.ts +1 -1
- package/dist/types/handles/MetaTags.d.ts +5 -4
- package/dist/types/handles/Scripts.d.ts +8 -7
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/handles/script.d.ts +17 -16
- package/dist/types/href-client.d.ts +1 -1
- package/dist/types/html.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +3 -2
- package/dist/types/loader-store.d.ts +7 -4
- package/dist/types/prerender/build-shell-capture.d.ts +11 -4
- package/dist/types/reverse.d.ts +36 -4
- package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
- package/dist/types/route-definition/helpers-types.d.ts +33 -9
- package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
- package/dist/types/route-types.d.ts +1 -1
- package/dist/types/router/debug-manifest.d.ts +3 -2
- package/dist/types/router/error-handling.d.ts +20 -0
- package/dist/types/router/handler-context.d.ts +6 -0
- package/dist/types/router/instrument.d.ts +8 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +9 -3
- package/dist/types/router/router-context.d.ts +3 -1
- package/dist/types/router/router-interfaces.d.ts +24 -2
- package/dist/types/router/router-options.d.ts +8 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +66 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
- package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
- package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
- package/dist/types/router/segment-wrappers.d.ts +1 -1
- package/dist/types/rsc/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-route-handler.d.ts +1 -1
- package/dist/types/rsc/rsc-rendering.d.ts +1 -2
- package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
- package/dist/types/rsc/shell-capture.d.ts +151 -19
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/context.d.ts +139 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +182 -53
- package/dist/types/ssr/index.d.ts +24 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- package/dist/types/testing/generated-routes.d.ts +2 -2
- package/dist/types/testing/internal/context.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +32 -6
- package/dist/types/testing/run-loader.d.ts +18 -3
- package/dist/types/testing/serve-shell-request.d.ts +132 -0
- package/dist/types/testing/shell-status.d.ts +23 -10
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
- package/dist/types/testing/vitest.d.ts +35 -1
- package/dist/types/theme/ThemeScript.d.ts +3 -3
- package/dist/types/types/cache-types.d.ts +14 -10
- package/dist/types/types/handler-context.d.ts +28 -1
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/pattern-types.d.ts +22 -18
- package/dist/types/urls/response-types.d.ts +3 -12
- package/dist/types/use-loader.d.ts +12 -3
- package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
- package/dist/types/vite/rango.d.ts +1 -1
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1420 -1348
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +75 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +306 -124
- package/skills/caching/SKILL.md +530 -98
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +65 -38
- package/skills/cloudflare/SKILL.md +87 -20
- package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
- package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
- package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
- package/skills/comparison/SKILL.md +5 -0
- package/skills/comparison/references/framework-comparison.md +75 -57
- package/skills/composability/SKILL.md +38 -29
- package/skills/css/SKILL.md +10 -13
- package/skills/debug-manifest/SKILL.md +74 -31
- package/skills/defer-hydration/SKILL.md +52 -31
- package/skills/deployment-caching/SKILL.md +11 -3
- package/skills/document-cache/SKILL.md +98 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +55 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +34 -17
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +39 -15
- package/skills/hooks/urls.md +7 -5
- package/skills/host-router/SKILL.md +64 -12
- package/skills/i18n/SKILL.md +60 -34
- package/skills/intercept/SKILL.md +161 -26
- package/skills/layout/SKILL.md +106 -50
- package/skills/links/SKILL.md +51 -19
- package/skills/loader/SKILL.md +386 -128
- package/skills/middleware/SKILL.md +129 -26
- package/skills/migrate-nextjs/SKILL.md +156 -70
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +51 -39
- package/skills/migrate-react-router/component-migration.md +28 -7
- package/skills/migrate-react-router/data-and-actions.md +21 -6
- package/skills/migrate-react-router/route-mapping.md +19 -10
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +92 -14
- package/skills/parallel/SKILL.md +88 -47
- package/skills/ppr/SKILL.md +866 -379
- package/skills/prerender/SKILL.md +210 -108
- package/skills/rango/SKILL.md +115 -65
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +170 -60
- package/skills/router-setup/SKILL.md +420 -240
- package/skills/scripts/SKILL.md +39 -21
- package/skills/server-actions/SKILL.md +231 -59
- package/skills/shell-manifest/SKILL.md +28 -14
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +73 -33
- package/skills/testing/cache-prerender.md +60 -33
- package/skills/testing/client-components.md +59 -6
- package/skills/testing/e2e-parity.md +12 -2
- package/skills/testing/flight.md +19 -11
- package/skills/testing/handles.md +8 -5
- package/skills/testing/loader.md +26 -6
- package/skills/testing/middleware.md +8 -3
- package/skills/testing/predicates.md +120 -0
- package/skills/testing/render-handler.md +70 -22
- package/skills/testing/response-routes.md +11 -4
- package/skills/testing/reverse-and-types.md +20 -14
- package/skills/testing/serve-shell-request.md +188 -0
- package/skills/testing/server-actions.md +12 -3
- package/skills/testing/server-tree.md +9 -0
- package/skills/testing/setup.md +9 -5
- package/skills/theme/SKILL.md +155 -30
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +137 -50
- package/skills/typesafety/generated-files-and-cli.md +26 -14
- package/skills/typesafety/params-and-search.md +44 -19
- package/skills/typesafety/route-types.md +50 -14
- package/skills/use-cache/SKILL.md +224 -83
- package/skills/vercel/SKILL.md +35 -13
- package/skills/view-transitions/SKILL.md +42 -21
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- package/src/browser/index.ts +2 -2
- package/src/browser/navigation-bridge.ts +3 -4
- package/src/browser/navigation-transaction.ts +22 -2
- package/src/browser/partial-update.ts +35 -25
- package/src/browser/react/ScrollRestoration.tsx +6 -6
- package/src/browser/rsc-router.tsx +6 -1
- package/src/browser/scroll-restoration.ts +53 -6
- package/src/cache/cache-exec-scope.ts +37 -4
- package/src/cache/cache-key-utils.ts +23 -8
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +264 -68
- package/src/cache/cache-scope.ts +419 -43
- package/src/cache/cache-tag.ts +375 -11
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +990 -348
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +133 -28
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +108 -22
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +225 -44
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- package/src/client.rsc.tsx +10 -9
- package/src/client.tsx +5 -4
- package/src/components/DefaultDocument.tsx +7 -2
- package/src/context-var.ts +6 -5
- package/src/escape-script.ts +1 -1
- package/src/handles/MetaTags.tsx +13 -11
- package/src/handles/Scripts.tsx +11 -10
- package/src/handles/meta.ts +2 -2
- package/src/handles/script.ts +17 -16
- package/src/href-client.ts +1 -1
- package/src/html.ts +12 -0
- package/src/index.rsc.ts +5 -0
- package/src/index.ts +1 -0
- package/src/loader-store.ts +7 -4
- package/src/prerender/build-shell-capture.ts +73 -22
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +121 -33
- package/src/route-definition/helpers-types.ts +33 -9
- package/src/route-definition/resolve-handler-use.ts +121 -6
- package/src/route-types.ts +0 -3
- package/src/router/debug-manifest.ts +10 -2
- package/src/router/error-handling.ts +51 -15
- package/src/router/handler-context.ts +71 -28
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +141 -43
- package/src/router/loader-resolution.ts +115 -39
- package/src/router/match-api.ts +40 -26
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +110 -10
- package/src/router/match-middleware/cache-store.ts +48 -101
- package/src/router/middleware-types.ts +9 -6
- package/src/router/middleware.ts +75 -13
- package/src/router/prerender-match.ts +59 -19
- package/src/router/route-snapshot.ts +11 -1
- package/src/router/router-context.ts +2 -0
- package/src/router/router-interfaces.ts +25 -2
- package/src/router/router-options.ts +8 -5
- package/src/router/segment-resolution/fresh.ts +62 -21
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +407 -76
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +208 -56
- package/src/router/segment-resolution/mask-nested.ts +138 -44
- package/src/router/segment-resolution/revalidation.ts +61 -16
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/full-payload.ts +25 -1
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/progressive-enhancement.ts +3 -2
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-cache-serve.ts +9 -6
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +608 -225
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +73 -6
- package/src/rsc/shell-capture.ts +1068 -296
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +18 -0
- package/src/server/context.ts +300 -32
- package/src/server/cookie-store.ts +87 -61
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +297 -67
- package/src/ssr/index.tsx +136 -44
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +14 -0
- package/src/testing/generated-routes.ts +2 -2
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/internal/flight-client-globals.ts +7 -5
- package/src/testing/render-route.tsx +85 -24
- package/src/testing/run-loader.ts +68 -6
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +28 -1
- package/src/types/loader-types.ts +8 -6
- package/src/urls/pattern-types.ts +22 -18
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
- package/src/vite/router-discovery.ts +14 -4
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* serveShellRequest — one request through the production PPR serve path.
|
|
3
|
+
*
|
|
4
|
+
* Builds the router's request handler as `router.fetch` does
|
|
5
|
+
* (`createRSCHandler` with the router's `nonce`, `version` and `cache`
|
|
6
|
+
* config) and serves one GET through it, so middleware, the shell serve path
|
|
7
|
+
* and a MISS's background capture all run production code, on real Flight
|
|
8
|
+
* (the vendored react-server-dom serializer). The call settles every
|
|
9
|
+
* background task the request scheduled before it returns, so a MISS's
|
|
10
|
+
* `putShell` has landed.
|
|
11
|
+
*
|
|
12
|
+
* The one stub is the SSR module (the HTML step): `react-dom/server` refuses
|
|
13
|
+
* to load under the react-server condition this project runs with.
|
|
14
|
+
* - `renderHTML` passes the Flight stream through: a document body is its
|
|
15
|
+
* Flight payload.
|
|
16
|
+
* - `captureShellHTML` returns, as the prelude, the Flight text the capture
|
|
17
|
+
* rendered before `quiesce` (plus the post-quiesce task hops the real
|
|
18
|
+
* capture takes). `postponed` is always null. A capture that does not
|
|
19
|
+
* quiesce within what `ppr.captureTimeout` leaves after the handler output
|
|
20
|
+
* settled returns no shell; the real one goes on to its abort and returns
|
|
21
|
+
* whatever prelude rendered by then.
|
|
22
|
+
* - `resumeShellHTML` passes the tail's Flight stream through: a HIT body is
|
|
23
|
+
* the stored prelude followed by the tail's Flight payload.
|
|
24
|
+
* So there is no HTML: the prelude's `<body` sanity gate, SSR render errors
|
|
25
|
+
* (production refuses the capture on one), fizz resume of the holes,
|
|
26
|
+
* bootstrap scripts and nonce injection stay e2e-only. A route whose real
|
|
27
|
+
* capture refuses for a root postpone (a live loader read with no boundary
|
|
28
|
+
* above it) or an SSR render error is captured here.
|
|
29
|
+
*
|
|
30
|
+
* Must run under the `react-server` condition (the rsc Vitest project), with
|
|
31
|
+
* `rangoTestAliases()` resolving `@vitejs/plugin-rsc/rsc/server` to the stub
|
|
32
|
+
* that carries the Flight runtime.
|
|
33
|
+
*/
|
|
34
|
+
import { type Rango } from "../router/router-interfaces.js";
|
|
35
|
+
import type { SegmentCacheStore, ShellCacheEntry } from "../cache/types.js";
|
|
36
|
+
import { type PprReplayStatus, type ShellStatus } from "./shell-status.js";
|
|
37
|
+
/** Options for {@link serveShellRequest}. */
|
|
38
|
+
export interface ServeShellRequestOptions<TEnv = any> {
|
|
39
|
+
/**
|
|
40
|
+
* The shell and segment store for this request, in place of the router's
|
|
41
|
+
* `createRouter({ cache })` store. The rest of that config (`enabled`,
|
|
42
|
+
* `searchParams`) still applies. Omit it to serve through the router's own
|
|
43
|
+
* store.
|
|
44
|
+
*/
|
|
45
|
+
cacheStore?: SegmentCacheStore;
|
|
46
|
+
/** Environment bindings, as `router.fetch(request, { env })` passes them. */
|
|
47
|
+
env?: TEnv;
|
|
48
|
+
/**
|
|
49
|
+
* Request headers. A document request defaults `accept` to `text/html`.
|
|
50
|
+
*/
|
|
51
|
+
headers?: HeadersInit;
|
|
52
|
+
/**
|
|
53
|
+
* Serve the client navigation the browser sends (`?_rsc_partial`) instead
|
|
54
|
+
* of a document GET: from `from` (default `/`) with `segments` mounted
|
|
55
|
+
* (default none), advertising fragment passthrough. The replay decision is
|
|
56
|
+
* `result.replayStatus`.
|
|
57
|
+
*/
|
|
58
|
+
partial?: true | {
|
|
59
|
+
from?: string;
|
|
60
|
+
segments?: readonly string[];
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Result of {@link serveShellRequest}. */
|
|
64
|
+
export interface ServeShellRequestResult {
|
|
65
|
+
/** The handler's Response. Its body is already read: see `body`. */
|
|
66
|
+
response: Response;
|
|
67
|
+
/** The response body text. */
|
|
68
|
+
body: string;
|
|
69
|
+
/** `x-rango-shell` (`HIT` | `MISS`), or null when the header is absent. */
|
|
70
|
+
shellStatus: ShellStatus | null;
|
|
71
|
+
/** `x-rango-ppr-replay` on a partial request, or null. */
|
|
72
|
+
replayStatus: PprReplayStatus | null;
|
|
73
|
+
/**
|
|
74
|
+
* The prelude a HIT served: the capture's Flight text at quiesce (the
|
|
75
|
+
* shell as captured). Undefined unless `shellStatus` is `HIT`.
|
|
76
|
+
*/
|
|
77
|
+
prelude: string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The Flight payload this request rendered: a HIT's tail, a document's
|
|
80
|
+
* render, or a Flight response. Undefined when no Flight was rendered (a
|
|
81
|
+
* redirect or a middleware response).
|
|
82
|
+
*/
|
|
83
|
+
flight: string | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* The shell key production resolved for this request: for a document the
|
|
86
|
+
* serve path read and captured (a MISS or a HIT), the key it used, request
|
|
87
|
+
* partition included (a route partitioned by `cache({ key })` or the
|
|
88
|
+
* store's `keyGenerator`). Otherwise (a route without `ppr`, a request
|
|
89
|
+
* passed to axis 1 before its key was resolved, a partial request) the
|
|
90
|
+
* document URL's key without a partition, as `shellCacheKey` builds it.
|
|
91
|
+
*/
|
|
92
|
+
key: string;
|
|
93
|
+
/**
|
|
94
|
+
* Read the document shell entry under `key` from the request's store
|
|
95
|
+
* (a passive `getShell`), or null. A read, so on a store with a shell memo
|
|
96
|
+
* (CFCacheStore, VercelCacheStore) it warms the memo like any other read.
|
|
97
|
+
*/
|
|
98
|
+
readEntry(): Promise<ShellCacheEntry | null>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reset the per-isolate PPR state requests leave behind, so the next test
|
|
102
|
+
* starts as a fresh worker would: the capture's stampede guard, its backoff
|
|
103
|
+
* (a refused capture backs its URL off for later tests too), the capture's
|
|
104
|
+
* and the serve path's once-per-key warnings, the build-shell manifest memo,
|
|
105
|
+
* and CFCacheStore's isolate memos (shells, tag markers, tag hints), which
|
|
106
|
+
* every CFCacheStore in the process shares by namespace and URL. Call it in
|
|
107
|
+
* `beforeEach`, never while a request is in flight. VercelCacheStore's memos
|
|
108
|
+
* live on the `cache` handle it is given: a new handle starts empty.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resetShellTestState(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Serve one GET for `url` through the router's production request handler
|
|
113
|
+
* and settle the background tasks it scheduled (a MISS's capture and
|
|
114
|
+
* `putShell` included). The first request for a `ppr` route is a MISS; the
|
|
115
|
+
* next one with the same store is a HIT from the stored shell. The HTML step
|
|
116
|
+
* is stubbed (see the module header), so `prelude` and `flight` are Flight
|
|
117
|
+
* text. The request starts in a later millisecond than the call: a store
|
|
118
|
+
* refuses a capture that starts in the millisecond of a tag invalidation, so
|
|
119
|
+
* an `updateTag()` made just before the call never refuses its recapture.
|
|
120
|
+
* Rejects when the handler throws or the response stream errors (a failing
|
|
121
|
+
* HIT tail), after settling the tasks scheduled so far.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* const store = new MemorySegmentCacheStore();
|
|
125
|
+
* const miss = await serveShellRequest(router, "/product/1", { cacheStore: store });
|
|
126
|
+
* expect(miss.shellStatus).toBe("MISS");
|
|
127
|
+
* const hit = await serveShellRequest(router, "/product/1", { cacheStore: store });
|
|
128
|
+
* expect(hit.shellStatus).toBe("HIT");
|
|
129
|
+
* expect(hit.prelude).toContain("Widget"); // captured shell
|
|
130
|
+
* expect(hit.flight).toContain("in stock"); // live hole, rendered now
|
|
131
|
+
*/
|
|
132
|
+
export declare function serveShellRequest<TEnv = any>(router: Rango<TEnv, any>, url: string | URL, options?: ServeShellRequestOptions<TEnv>): Promise<ServeShellRequestResult>;
|
|
@@ -18,11 +18,15 @@
|
|
|
18
18
|
* Secondary unit signal: `store.getShell(shellCacheKey(url))` after a real
|
|
19
19
|
* capture flush (background `putShell`). There is no Flight flag for shell HIT.
|
|
20
20
|
*
|
|
21
|
-
* 3. **
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* 3. **A real MISS → capture → HIT in unit tests:** `serveShellRequest`
|
|
22
|
+
* (`@rangojs/router/testing/flight`, serve-shell-request.ts) serves one
|
|
23
|
+
* request through the router's production handler and settles its
|
|
24
|
+
* background capture; a later request with the same store is a real HIT or
|
|
25
|
+
* partial replay. Its only stub is the HTML step (the SSR module).
|
|
26
|
+
* **Stays e2e-only:** real HTML (the prelude's `<body` gate, fizz resume of
|
|
27
|
+
* holes), browser resume of holes, live Cloudflare/Vercel runtimes (store
|
|
28
|
+
* test doubles work in unit), and build-time producer B bake. The unit layer
|
|
29
|
+
* must never stub a shell HIT response.
|
|
26
30
|
*
|
|
27
31
|
* Import from `@rangojs/router/testing` (Vitest) or `@rangojs/router/testing/e2e`
|
|
28
32
|
* (Playwright — same pure helpers, no Vite virtuals).
|
|
@@ -34,7 +38,7 @@ export declare const SHELL_STATUS_HEADER: string;
|
|
|
34
38
|
export declare const PPR_REPLAY_STATUS_HEADER: string;
|
|
35
39
|
/** Values the serve path writes on `x-rango-shell`. */
|
|
36
40
|
export type ShellStatus = "HIT" | "MISS";
|
|
37
|
-
declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "
|
|
41
|
+
declare const PPR_REPLAY_BYPASS_REASONS: readonly ["method", "dynamic", "nonce", "store-unavailable", "passive-read-unsupported", "no-navigation-context", "prerender-store", "intercept", "cache-disabled", "read-error", "no-entry", "invalid-version", "corrupt-entry", "no-segment-snapshot", "snapshot-miss", "explicit-cache-hit", "stale-build-entry"];
|
|
38
42
|
/** Bounded reasons a PPR partial request can fall open to ordinary matching. */
|
|
39
43
|
export type PprReplayBypassReason = (typeof PPR_REPLAY_BYPASS_REASONS)[number];
|
|
40
44
|
/** Parsed `x-rango-ppr-replay` value. */
|
|
@@ -52,15 +56,24 @@ export type ShellStatusTarget = Response | {
|
|
|
52
56
|
/**
|
|
53
57
|
* Shell store key for a document URL — same formula as production
|
|
54
58
|
* `buildShellKey` in `rsc/shell-serve.ts` (host + pathname + sorted search +
|
|
55
|
-
* `:shell`)
|
|
56
|
-
*
|
|
59
|
+
* `:shell`), then the production `partitionShellKey` itself (the leaf
|
|
60
|
+
* `rsc/shell-capture-constants.ts`). The base is kept here so the testing
|
|
61
|
+
* barrel never imports the shell-serve module (it pulls React). A parity test
|
|
62
|
+
* pins the two implementations.
|
|
57
63
|
*
|
|
58
64
|
* Accepts a `URL` or an absolute/relative request URL string (relative strings
|
|
59
65
|
* resolve against `http://localhost`). Pass the router's `cache.searchParams`
|
|
60
66
|
* config as `searchParams` when the app under test sets one — the production
|
|
61
|
-
* key applies it, so the expected key must too.
|
|
67
|
+
* key applies it, so the expected key must too. When the route's record is
|
|
68
|
+
* partitioned by the request — its `cache({ key })`, or the store's
|
|
69
|
+
* `keyGenerator` — its shell is too: pass the key that function returns for
|
|
70
|
+
* the request as `partition` (appended URI-encoded; a result equal to the
|
|
71
|
+
* default key partitions nothing, so pass none). Under nested keyed
|
|
72
|
+
* `cache()` scopes, pass their `key()` results as an array, outermost first:
|
|
73
|
+
* they compose as the production record key composes them
|
|
74
|
+
* (`composeCacheKeys`).
|
|
62
75
|
*/
|
|
63
|
-
export declare function shellCacheKey(url: URL | string, searchParams?: CacheSearchParams): string;
|
|
76
|
+
export declare function shellCacheKey(url: URL | string, searchParams?: CacheSearchParams, partition?: string | readonly string[]): string;
|
|
64
77
|
/**
|
|
65
78
|
* Read `x-rango-shell` from a response. Returns `null` when the header is
|
|
66
79
|
* absent (axis-1 / non-ppr / ineligible request).
|
|
@@ -1,9 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Stub for `@vitejs/plugin-rsc/rsc` and the split `/rsc/server`, `/rsc/client`
|
|
3
|
+
* entries, shipped so consumers do not have to write a per-file `vi.mock(...)`.
|
|
4
|
+
* The real entries top-level import Vite virtuals that do not resolve in plain
|
|
5
|
+
* node.
|
|
6
|
+
*
|
|
7
|
+
* Under the `react-server` condition (the Flight project) the "use cache"
|
|
8
|
+
* codec runs on real Flight: the vendored react-server-dom `server.edge` /
|
|
9
|
+
* `client.edge` builds that plugin-rsc's `react/rsc/server` and
|
|
10
|
+
* `react/rsc/client` wrap, with the same manifests and the same server-side
|
|
11
|
+
* reference loader (`@vitejs/plugin-rsc/core/rsc` `setRequireModule`), so
|
|
12
|
+
* keys, writes, hits, value round trips and error rows match a build. The
|
|
13
|
+
* wrappers are not reused: their manifests read `import.meta.env.DEV`, which
|
|
14
|
+
* is undefined in a module node loads directly (vitest externalizes
|
|
15
|
+
* node_modules).
|
|
16
|
+
*
|
|
17
|
+
* Without the condition React's server build refuses to load, so the codec
|
|
18
|
+
* functions throw and a "use cache" call runs uncached. Any other load failure
|
|
19
|
+
* (a moved vendored path, a missing peer) throws. The action entries stay
|
|
20
|
+
* inert either way: no primitive decodes an action request.
|
|
21
|
+
*/
|
|
22
|
+
export declare const renderToReadableStream: (value: unknown, options?: object) => ReadableStream<Uint8Array>;
|
|
23
|
+
export declare const createTemporaryReferenceSet: () => unknown;
|
|
24
|
+
export declare const createFromReadableStream: (stream: ReadableStream<Uint8Array>, options?: object, extraOptions?: {
|
|
25
|
+
preserveServerReferences?: boolean;
|
|
26
|
+
}) => Promise<unknown>;
|
|
27
|
+
export declare const encodeReply: (value: unknown, options?: object) => Promise<string | FormData>;
|
|
28
|
+
export declare const createClientTemporaryReferenceSet: () => unknown;
|
|
3
29
|
export declare const loadServerAction: () => undefined;
|
|
4
30
|
export declare const decodeReply: () => undefined;
|
|
5
31
|
export declare const decodeAction: () => undefined;
|
|
6
32
|
export declare const decodeFormState: () => undefined;
|
|
7
|
-
export declare const createTemporaryReferenceSet: () => Record<string, never>;
|
|
8
|
-
export declare const encodeReply: () => never;
|
|
9
|
-
export declare const createClientTemporaryReferenceSet: () => Record<string, never>;
|
|
@@ -170,6 +170,7 @@ interface FlightTransformPlugin {
|
|
|
170
170
|
* import { defineConfig } from "vitest/config";
|
|
171
171
|
* import {
|
|
172
172
|
* rangoUseClientTransform,
|
|
173
|
+
* rangoUseCacheTransform,
|
|
173
174
|
* rangoTestAliases,
|
|
174
175
|
* rangoInlineDeps,
|
|
175
176
|
* } from "@rangojs/router/testing/vitest";
|
|
@@ -179,7 +180,7 @@ interface FlightTransformPlugin {
|
|
|
179
180
|
* process.env.NODE_ENV = "production";
|
|
180
181
|
*
|
|
181
182
|
* export default defineConfig({
|
|
182
|
-
* plugins: [rangoUseClientTransform()],
|
|
183
|
+
* plugins: [rangoUseClientTransform(), rangoUseCacheTransform()],
|
|
183
184
|
* resolve: {
|
|
184
185
|
* conditions: ["react-server"],
|
|
185
186
|
* // Bare `@rangojs/router` -> its react-server build, so a handler/component
|
|
@@ -203,4 +204,37 @@ interface FlightTransformPlugin {
|
|
|
203
204
|
* so `renderToFlightString` of pure leaf trees is unaffected.
|
|
204
205
|
*/
|
|
205
206
|
export declare function rangoUseClientTransform(): FlightTransformPlugin;
|
|
207
|
+
/** The Vite plugin shape {@link rangoUseCacheTransform} returns. */
|
|
208
|
+
interface UseCacheTransformPlugin {
|
|
209
|
+
name: string;
|
|
210
|
+
enforce: "post";
|
|
211
|
+
configResolved(config: {
|
|
212
|
+
root: string;
|
|
213
|
+
}): void;
|
|
214
|
+
transform(this: {
|
|
215
|
+
warn(message: string): void;
|
|
216
|
+
}, code: string, id: string): Promise<{
|
|
217
|
+
code: string;
|
|
218
|
+
map: unknown;
|
|
219
|
+
} | undefined>;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* A Vite plugin that applies the rango plugin's `"use cache"` transform in a
|
|
223
|
+
* Vitest project, so a function written with the directive is wrapped with
|
|
224
|
+
* `registerCachedFunction` as in dev and a build. `rango()` runs that transform
|
|
225
|
+
* only in its `rsc` environment and Vitest transforms in `ssr`, so without this
|
|
226
|
+
* plugin the directive is an inert string and the function runs on every call.
|
|
227
|
+
*
|
|
228
|
+
* Add it to the react-server project next to {@link rangoUseClientTransform}
|
|
229
|
+
* (see that function's config). There, with a seeded `cacheStore`,
|
|
230
|
+
* `renderHandler` / `runLoader` observe real hits. In the node project the
|
|
231
|
+
* wrap applies too, but the stubbed Flight serializer cannot write an entry.
|
|
232
|
+
*
|
|
233
|
+
* Ids are the ones `vite dev` emits: `<path relative to the Vitest root>#<name>`
|
|
234
|
+
* (a function-level directive gives `src/data.ts#$$hoist_0_getData`), not the
|
|
235
|
+
* build's hashed path, so store keys stay readable. `configResolved` sets that
|
|
236
|
+
* root. If `@vitejs/plugin-rsc/transforms` fails to load, the transform throws
|
|
237
|
+
* instead of leaving the module unwrapped (which the rango plugin does).
|
|
238
|
+
*/
|
|
239
|
+
export declare function rangoUseCacheTransform(): UseCacheTransformPlugin;
|
|
206
240
|
export {};
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Must be placed in the <head> element of your document, before any stylesheets.
|
|
10
10
|
*
|
|
11
|
-
* Note: when theme is enabled in the router config, `<
|
|
11
|
+
* Note: when theme is enabled in the router config, `<Html.Meta />` ALREADY
|
|
12
12
|
* renders this FOUC script. Use `<ThemeScript />` only if you do NOT render
|
|
13
|
-
* `<
|
|
13
|
+
* `<Html.Meta />`. Rendering both is safe — the inline script guards the
|
|
14
14
|
* matchMedia listener registration against double-running — but it is redundant.
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* ```tsx
|
|
18
|
-
* // In your document component. Use ThemeScript only when you do not render
|
|
18
|
+
* // In your document component. Use ThemeScript only when you do not render Html.Meta.
|
|
19
19
|
* import { ThemeScript } from "@rangojs/router/theme";
|
|
20
20
|
*
|
|
21
21
|
* export function Document({ children }) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Context passed to cache condition/key/tags functions
|
|
2
|
+
* Context passed to cache condition/key/tags functions (the full
|
|
3
|
+
* RequestContext).
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Ordering: global middleware wraps the whole request, and on RSC routes route
|
|
6
|
+
* middleware wraps the match/render pipeline (rsc/handler.ts executeRender), so
|
|
7
|
+
* variables they set before `next()` are readable via `ctx.get()`. On response
|
|
8
|
+
* routes the cache lookup runs BEFORE route middleware, which wraps only the
|
|
9
|
+
* handler run on a miss (rsc/response-route-handler.ts); only global-middleware
|
|
10
|
+
* variables are populated there.
|
|
10
11
|
*/
|
|
11
12
|
export type { RequestContext as CacheContext } from "../server/request-context.js";
|
|
12
13
|
/**
|
|
@@ -105,7 +106,8 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
105
106
|
* Return false to skip cache for this request (always fetch fresh).
|
|
106
107
|
*
|
|
107
108
|
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
108
|
-
*
|
|
109
|
+
* Runs after global and route middleware on RSC routes; on response routes,
|
|
110
|
+
* before route middleware (see CacheContext).
|
|
109
111
|
*
|
|
110
112
|
* @example
|
|
111
113
|
* ```typescript
|
|
@@ -124,7 +126,8 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
124
126
|
* Bypasses default key generation AND store's keyGenerator.
|
|
125
127
|
*
|
|
126
128
|
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
127
|
-
*
|
|
129
|
+
* Runs after global and route middleware on RSC routes; on response routes,
|
|
130
|
+
* before route middleware (see CacheContext).
|
|
128
131
|
*
|
|
129
132
|
* @example
|
|
130
133
|
* ```typescript
|
|
@@ -143,7 +146,8 @@ export interface CacheOptions<TEnv = unknown> {
|
|
|
143
146
|
* Tags for cache invalidation.
|
|
144
147
|
* Can be a static array or a function that returns tags.
|
|
145
148
|
*
|
|
146
|
-
* The built-in `MemorySegmentCacheStore
|
|
149
|
+
* The built-in `MemorySegmentCacheStore`, `CFCacheStore`, and
|
|
150
|
+
* `VercelCacheStore` index by tag.
|
|
147
151
|
* Invalidate on demand with `updateTag(...tags)` (awaitable, read-your-own-writes;
|
|
148
152
|
* for server actions) or `revalidateTag(...tags)` (background hard-purge, not
|
|
149
153
|
* awaited; for route handlers / webhooks). For `CFCacheStore`, distributed
|
|
@@ -235,6 +235,12 @@ export type HandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch extends Sear
|
|
|
235
235
|
* Current theme (from cookie or default).
|
|
236
236
|
* Only available when theme is enabled in router config.
|
|
237
237
|
*
|
|
238
|
+
* The visitor's cookie, so it is guarded like `cookies()`: reading it on a
|
|
239
|
+
* `ppr` route refuses the shell capture, and inside a `cache()` boundary or
|
|
240
|
+
* a `"use cache"` function it throws (#971). Read it with `useTheme()` in a
|
|
241
|
+
* client component, or in a live loader, on those routes. A read-only,
|
|
242
|
+
* non-enumerable getter: `{ ...ctx }` does not carry it.
|
|
243
|
+
*
|
|
238
244
|
* @example
|
|
239
245
|
* ```typescript
|
|
240
246
|
* route("settings", (ctx) => {
|
|
@@ -243,7 +249,7 @@ export type HandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch extends Sear
|
|
|
243
249
|
* });
|
|
244
250
|
* ```
|
|
245
251
|
*/
|
|
246
|
-
theme?: Theme;
|
|
252
|
+
readonly theme?: Theme;
|
|
247
253
|
/**
|
|
248
254
|
* Set the theme (only available when theme is enabled in router config).
|
|
249
255
|
* Sets a cookie with the new theme value.
|
|
@@ -335,6 +341,27 @@ export type InternalHandlerContext<TParams = {}, TEnv = DefaultEnv, TSearch exte
|
|
|
335
341
|
* table (so a loader cannot await its own in-flight memoized promise).
|
|
336
342
|
*/
|
|
337
343
|
_loaderCacheOriginalUse?: (item: any) => any;
|
|
344
|
+
/**
|
|
345
|
+
* @internal A loader-cache HIT asks before replaying a loader's recorded
|
|
346
|
+
* pushes: true when that loader has not run in this request and no other
|
|
347
|
+
* replay delivered it; its later run then replaces the replayed values
|
|
348
|
+
* (HandleStore.pushReplayed). One copy per loader per request. See
|
|
349
|
+
* setupLoaderAccess.
|
|
350
|
+
*/
|
|
351
|
+
_claimLoaderPushes?: (loaderId: string) => boolean;
|
|
352
|
+
/**
|
|
353
|
+
* @internal Run a loader on a fresh executor (own memo map): a loader-cache
|
|
354
|
+
* stale refresh, whose diverted pushes must not take a dependency's run
|
|
355
|
+
* from the page. See setupLoaderAccess.
|
|
356
|
+
*/
|
|
357
|
+
_runLoaderIsolated?: (loader: any) => Promise<any>;
|
|
358
|
+
/**
|
|
359
|
+
* @internal A loader's cache() binding started with these cache() tags: an
|
|
360
|
+
* execution of that loader outside the binding (a reader started it first,
|
|
361
|
+
* or a stale refresh runs it) answers for them too (#964). See
|
|
362
|
+
* setupLoaderAccess.
|
|
363
|
+
*/
|
|
364
|
+
_bindLoaderCacheTags?: (loaderId: string, tags: Set<string>) => void;
|
|
338
365
|
};
|
|
339
366
|
/**
|
|
340
367
|
* Generic params type - flexible object with string keys
|
|
@@ -23,9 +23,10 @@ import type { RequestScope } from "./request-scope.js";
|
|
|
23
23
|
* return await db.cart.get(user.id);
|
|
24
24
|
* });
|
|
25
25
|
*
|
|
26
|
-
* //
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* // createLoader's one type parameter is the data type; params are
|
|
27
|
+
* // Record<string, string | undefined>:
|
|
28
|
+
* const ProductLoader = createLoader<Product>(async (ctx) => {
|
|
29
|
+
* const { slug } = ctx.params; // string | undefined
|
|
29
30
|
* return await db.products.findBySlug(slug);
|
|
30
31
|
* });
|
|
31
32
|
* ```
|
|
@@ -213,9 +214,10 @@ export type LoadOptions = {
|
|
|
213
214
|
* return await db.cart.get(ctx.get("user").id);
|
|
214
215
|
* });
|
|
215
216
|
*
|
|
216
|
-
* //
|
|
217
|
-
*
|
|
218
|
-
*
|
|
217
|
+
* // createLoader's one type parameter is the data type; params are
|
|
218
|
+
* // Record<string, string | undefined>:
|
|
219
|
+
* export const ProductLoader = createLoader<Product>(async (ctx) => {
|
|
220
|
+
* const { slug } = ctx.params; // string | undefined
|
|
219
221
|
* return await db.products.findBySlug(slug);
|
|
220
222
|
* });
|
|
221
223
|
*
|
|
@@ -53,30 +53,34 @@ export interface PartialPrerenderProps {
|
|
|
53
53
|
/**
|
|
54
54
|
* Operational tags attached to the captured shell entry for
|
|
55
55
|
* `updateTag()`/`revalidateTag()`-driven eviction. UNIONED with the tags the
|
|
56
|
-
* capture
|
|
56
|
+
* capture collects: its doc record's tags (what the handler layer and the
|
|
57
|
+
* server components it rendered recorded) and its bake-lane loaders'.
|
|
57
58
|
*/
|
|
58
59
|
tags?: string[];
|
|
59
60
|
/**
|
|
60
|
-
* Upper bound (serialized UTF-8 bytes) on the
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
61
|
+
* Upper bound (serialized UTF-8 bytes) on the loader pins in the capture
|
|
62
|
+
* data snapshot: the loader records and the cache values loaders read,
|
|
63
|
+
* duplicated into the shell entry. The doc record (the handler layer every
|
|
64
|
+
* HIT replays) is exempt. Over the cap the pins are dropped: the shell is
|
|
65
|
+
* still stored and every HIT still replays the handler layer, but the
|
|
66
|
+
* pinned loaders read the live store, so drifted cached content can
|
|
67
|
+
* hydration-mismatch and be repaired client-side. Reported once per key.
|
|
68
|
+
* Defaults to 8 MiB. The whole entry is bounded separately by the store's
|
|
69
|
+
* value limit (Cloudflare KV: 25 MiB); an entry over it is refused.
|
|
68
70
|
*/
|
|
69
71
|
maxSnapshotBytes?: number;
|
|
70
72
|
/**
|
|
71
|
-
* Capture settle budget in MILLISECONDS (default 15000).
|
|
72
|
-
* background capture: the
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
73
|
+
* Capture settle budget in MILLISECONDS (default 15000). One deadline for
|
|
74
|
+
* the whole background capture: the match (the handlers, and the loaders
|
|
75
|
+
* they await), the wait for handler output (handle pushes and the promises
|
|
76
|
+
* nested in them, bake-lane loaders, and the doc record's encode, which
|
|
77
|
+
* awaits handler promises and async server components), AND the fizz
|
|
78
|
+
* prerender. Everything a handler produces is
|
|
79
|
+
* awaited and baked into the stored shell. Declare it to tighten the
|
|
80
|
+
* budget below the default or when a route's shell material takes longer
|
|
81
|
+
* than 15s to settle. A budget that expires before the doc record is
|
|
82
|
+
* written REFUSES the capture (the route stays MISS with the once-per-key
|
|
83
|
+
* warning): a shell with missing handler output is never stored. Capture is background work
|
|
80
84
|
* (waitUntil), so a longer budget costs latency-to-HIT only, never a served
|
|
81
85
|
* response; the platform waitUntil lifetime (workerd: ~30s past response
|
|
82
86
|
* completion) is the physical ceiling — the default's derivation lives in
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
import type { ContextVar } from "../context-var.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { GlobalReverseFunction } from "../reverse.js";
|
|
3
3
|
import type { DefaultReverseRouteMap, DefaultVars } from "../types/global-namespace.js";
|
|
4
4
|
import type { UseItems, ResponseRouteUseItem } from "../route-types.js";
|
|
5
5
|
import type { RequestScope } from "../types/request-scope.js";
|
|
6
|
-
/**
|
|
7
|
-
* Reverse function for response handler contexts.
|
|
8
|
-
* Global names get autocomplete and param validation from the generated route map.
|
|
9
|
-
* Local `.name` calls are accepted but not validated (scope unknown at type level).
|
|
10
|
-
*/
|
|
11
|
-
type ResponseReverseFunction = [DefaultReverseRouteMap] extends [
|
|
12
|
-
Record<string, string>
|
|
13
|
-
] ? (name: string, params?: Record<string, string>, search?: Record<string, unknown>) => string : ReverseFunction<DefaultReverseRouteMap> & {
|
|
14
|
-
(name: `.${string}`, params?: Record<string, string>, search?: Record<string, unknown>): string;
|
|
15
|
-
};
|
|
16
6
|
/**
|
|
17
7
|
* Symbol marking a route as a response route (non-RSC).
|
|
18
8
|
* Stored on PathOptions and UrlPatterns to signal the trie to short-circuit.
|
|
@@ -56,7 +46,8 @@ export interface ResponseHandlerContext<TParams = Record<string, string>, TEnv =
|
|
|
56
46
|
params: TParams;
|
|
57
47
|
/** @internal Phantom property for params type invariance. Prevents mounting handlers on wrong routes. */
|
|
58
48
|
readonly _paramCheck?: (params: TParams) => TParams;
|
|
59
|
-
|
|
49
|
+
/** Global route names only; see {@link GlobalReverseFunction}. */
|
|
50
|
+
reverse: GlobalReverseFunction<DefaultReverseRouteMap>;
|
|
60
51
|
/** Read a variable set by middleware via ctx.set(key, value) or ctx.set(ContextVar, value). */
|
|
61
52
|
get: {
|
|
62
53
|
<T>(contextVar: ContextVar<T>): T | undefined;
|
|
@@ -2,6 +2,14 @@ import type { LoaderDefinition, LoadOptions } from "./types.js";
|
|
|
2
2
|
export type LoadFunction<T> = (options?: LoadOptions) => Promise<T>;
|
|
3
3
|
export interface UseLoaderResult<T> {
|
|
4
4
|
data: T;
|
|
5
|
+
/**
|
|
6
|
+
* True while this loader family (`loader.$$id`) is in flight: a `load()` /
|
|
7
|
+
* group refresh, or a held navigation still streaming a re-run of this
|
|
8
|
+
* loader. Family-keyed, not segment-keyed: a layout `useLoader` of the same
|
|
9
|
+
* `createLoader` the child route is re-running also reports true, even if
|
|
10
|
+
* the layout copy is not replaced. Not used for the initial streamed read
|
|
11
|
+
* (that suspends).
|
|
12
|
+
*/
|
|
5
13
|
isLoading: boolean;
|
|
6
14
|
error: Error | null;
|
|
7
15
|
load: LoadFunction<T>;
|
|
@@ -9,6 +17,7 @@ export interface UseLoaderResult<T> {
|
|
|
9
17
|
}
|
|
10
18
|
export interface UseFetchLoaderResult<T> {
|
|
11
19
|
data: T | undefined;
|
|
20
|
+
/** Same family-keyed contract as {@link UseLoaderResult.isLoading}. */
|
|
12
21
|
isLoading: boolean;
|
|
13
22
|
error: Error | null;
|
|
14
23
|
load: LoadFunction<T>;
|
|
@@ -36,7 +45,7 @@ export interface UseLoaderOptions {
|
|
|
36
45
|
* @example Basic usage - accessing route loader data
|
|
37
46
|
* ```tsx
|
|
38
47
|
* "use client";
|
|
39
|
-
* import { useLoader } from "
|
|
48
|
+
* import { useLoader } from "@rangojs/router/client";
|
|
40
49
|
* import { CartLoader } from "../loaders/cart";
|
|
41
50
|
*
|
|
42
51
|
* // In route definition: loader(CartLoader)
|
|
@@ -67,7 +76,7 @@ export declare function useLoader<T>(loader: LoaderDefinition<T>, options?: UseL
|
|
|
67
76
|
* @example On-demand fetching
|
|
68
77
|
* ```tsx
|
|
69
78
|
* "use client";
|
|
70
|
-
* import { useFetchLoader } from "
|
|
79
|
+
* import { useFetchLoader } from "@rangojs/router/client";
|
|
71
80
|
* import { SearchLoader } from "../loaders/search";
|
|
72
81
|
*
|
|
73
82
|
* export function SearchResults() {
|
|
@@ -121,7 +130,7 @@ export declare function useFetchLoader<T>(loader: LoaderDefinition<T>, options?:
|
|
|
121
130
|
* @example
|
|
122
131
|
* ```tsx
|
|
123
132
|
* "use client";
|
|
124
|
-
* import { useLoader, useRefreshLoaders } from "
|
|
133
|
+
* import { useLoader, useRefreshLoaders } from "@rangojs/router/client";
|
|
125
134
|
*
|
|
126
135
|
* function Profile() {
|
|
127
136
|
* const { data } = useLoader(ProfileLoader, { key: userId, refreshGroup: "account" });
|
|
@@ -15,6 +15,37 @@
|
|
|
15
15
|
* - transformWrapExport() for file-level wrapping
|
|
16
16
|
* - transformHoistInlineDirective() for function-level hoisting
|
|
17
17
|
*/
|
|
18
|
-
import type { Plugin } from "vite";
|
|
18
|
+
import type { Plugin, Rollup } from "vite";
|
|
19
|
+
import type { Counter } from "../debug.js";
|
|
19
20
|
export declare const USE_CACHE_DIRECTIVE_RE: RegExp;
|
|
20
|
-
|
|
21
|
+
/**
|
|
22
|
+
* @param counter `rango:transform` timing counter, created by `rango()`
|
|
23
|
+
* (`createCounter` in ../debug.js); omitted when debugging is off.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useCacheTransform(counter?: Counter): Plugin;
|
|
26
|
+
/** Options for {@link transformUseCache}. */
|
|
27
|
+
export interface UseCacheTransformOptions {
|
|
28
|
+
/** Root the ids are relative to (Vite's `config.root`). */
|
|
29
|
+
root: string;
|
|
30
|
+
/** Build ids hash the path (`hashId`); dev ids are `<path>#<export>`. */
|
|
31
|
+
isBuild: boolean;
|
|
32
|
+
/** Sink for the near-miss directive warning. */
|
|
33
|
+
warn: (message: string) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Called when `@vitejs/plugin-rsc/transforms` fails to load; the module is
|
|
36
|
+
* then left unwrapped. The rango plugin omits it (skip silently).
|
|
37
|
+
*/
|
|
38
|
+
onTransformsError?: (error: unknown) => void;
|
|
39
|
+
}
|
|
40
|
+
/** Whether a module may carry a `"use cache"` directive the transform wraps. */
|
|
41
|
+
export declare function isUseCacheCandidate(code: string, id: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Wrap a module's `"use cache"` functions with `registerCachedFunction`. The
|
|
44
|
+
* rango plugin runs it in the rsc environment; `rangoUseCacheTransform()`
|
|
45
|
+
* (testing/vitest.ts) runs it in a Vitest project, whose environment is `ssr`.
|
|
46
|
+
* Call it only for an {@link isUseCacheCandidate} module.
|
|
47
|
+
*/
|
|
48
|
+
export declare function transformUseCache(code: string, id: string, options: UseCacheTransformOptions): Promise<{
|
|
49
|
+
code: string;
|
|
50
|
+
map: Rollup.ExistingRawSourceMap;
|
|
51
|
+
} | undefined>;
|
|
@@ -21,7 +21,7 @@ export { hasUseClientDirective };
|
|
|
21
21
|
* plugins: [
|
|
22
22
|
* react(),
|
|
23
23
|
* rango({ preset: 'cloudflare' }),
|
|
24
|
-
* cloudflare({ viteEnvironment: { name: 'rsc' } }),
|
|
24
|
+
* cloudflare({ viteEnvironment: { name: 'rsc', childEnvironments: ['ssr'] } }),
|
|
25
25
|
* ],
|
|
26
26
|
* });
|
|
27
27
|
* ```
|