@rangojs/router 0.17.0 → 0.19.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 +3 -2
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +18 -0
- package/dist/types/browser/navigation-transaction.d.ts +20 -2
- package/dist/types/browser/partial-update.d.ts +16 -1
- package/dist/types/browser/prefetch/cache.d.ts +6 -6
- package/dist/types/browser/react/Link.d.ts +19 -9
- package/dist/types/browser/react/context.d.ts +2 -2
- package/dist/types/browser/react/location-state-shared.d.ts +95 -56
- package/dist/types/browser/react/location-state.d.ts +1 -1
- package/dist/types/browser/transition-when.d.ts +80 -0
- package/dist/types/browser/types.d.ts +104 -9
- package/dist/types/build/generate-manifest.d.ts +8 -0
- package/dist/types/cache/background-task.d.ts +24 -2
- package/dist/types/cache/cache-exec-scope.d.ts +31 -0
- package/dist/types/cache/cache-key-utils.d.ts +48 -2
- package/dist/types/cache/cache-policy.d.ts +18 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +192 -26
- package/dist/types/cache/cache-tag.d.ts +116 -11
- 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 +224 -72
- 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 +19 -0
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +41 -8
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +141 -105
- package/dist/types/cache/tag-invalidation.d.ts +54 -3
- package/dist/types/cache/types.d.ts +267 -96
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +123 -18
- package/dist/types/client-urls/navigation.d.ts +28 -2
- package/dist/types/client-urls/server-projection.d.ts +5 -2
- package/dist/types/client-urls/types.d.ts +5 -5
- package/dist/types/client.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +1 -1
- package/dist/types/prerender/build-shell-capture.d.ts +11 -4
- package/dist/types/route-definition/helpers-types.d.ts +11 -11
- package/dist/types/route-name.d.ts +7 -0
- package/dist/types/router/error-handling.d.ts +1 -1
- package/dist/types/router/instrument.d.ts +8 -0
- package/dist/types/router/intercept-resolution.d.ts +2 -0
- package/dist/types/router/match-context.d.ts +5 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +0 -4
- package/dist/types/router/middleware-types.d.ts +6 -1
- package/dist/types/router/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +58 -12
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +33 -48
- package/dist/types/router/segment-resolution/mask-nested.d.ts +73 -24
- package/dist/types/router/segment-resolution/view-transition-default.d.ts +7 -5
- package/dist/types/router/transition-when.d.ts +24 -10
- package/dist/types/rsc/attach-transition-when.d.ts +18 -0
- package/dist/types/rsc/full-payload.d.ts +21 -0
- package/dist/types/rsc/handler.d.ts +1 -1
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +12 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +116 -12
- package/dist/types/rsc/shell-capture.d.ts +202 -74
- package/dist/types/rsc/shell-serve.d.ts +144 -50
- package/dist/types/rsc/types.d.ts +9 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +155 -33
- package/dist/types/server/cookie-store.d.ts +33 -0
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +210 -63
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/ssr/index.d.ts +9 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- package/dist/types/testing/index.d.ts +3 -2
- package/dist/types/testing/internal/action-id.d.ts +7 -0
- package/dist/types/testing/location-state-key.d.ts +24 -0
- package/dist/types/testing/render-route.d.ts +17 -1
- package/dist/types/testing/run-loader.d.ts +18 -3
- package/dist/types/testing/run-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +133 -0
- package/dist/types/testing/shell-status.d.ts +44 -19
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- package/dist/types/types/handler-context.d.ts +14 -1
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/segments.d.ts +86 -71
- package/dist/types/urls/path-helper-types.d.ts +3 -4
- package/dist/types/urls/pattern-types.d.ts +21 -18
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1005 -105
- package/package.json +1 -1
- package/skills/breadcrumbs/SKILL.md +17 -7
- package/skills/cache-guide/SKILL.md +175 -76
- package/skills/caching/SKILL.md +361 -33
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +12 -7
- package/skills/cloudflare/SKILL.md +15 -0
- package/skills/comparison/references/framework-comparison.md +52 -37
- package/skills/defer-hydration/SKILL.md +50 -30
- package/skills/deployment-caching/SKILL.md +5 -2
- package/skills/document-cache/SKILL.md +32 -2
- package/skills/handler-use/SKILL.md +2 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/handle-and-actions.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +101 -7
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +197 -44
- package/skills/middleware/SKILL.md +34 -9
- package/skills/migrate-nextjs/SKILL.md +68 -37
- package/skills/migrate-react-router/SKILL.md +2 -1
- package/skills/migrate-react-router/component-migration.md +3 -1
- package/skills/migrate-react-router/data-and-actions.md +3 -1
- package/skills/migrate-react-router/route-mapping.md +7 -4
- package/skills/observability/SKILL.md +65 -0
- package/skills/parallel/SKILL.md +13 -8
- package/skills/ppr/SKILL.md +715 -371
- package/skills/prerender/SKILL.md +30 -17
- package/skills/rango/SKILL.md +72 -34
- package/skills/route/SKILL.md +14 -7
- package/skills/router-setup/SKILL.md +4 -2
- package/skills/scripts/SKILL.md +8 -1
- package/skills/server-actions/SKILL.md +11 -0
- package/skills/shell-manifest/SKILL.md +21 -12
- package/skills/testing/SKILL.md +49 -43
- package/skills/testing/cache-prerender.md +15 -14
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +19 -1
- package/skills/testing/middleware.md +1 -0
- package/skills/testing/predicates.md +49 -49
- package/skills/testing/render-handler.md +1 -0
- package/skills/testing/serve-shell-request.md +202 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +56 -4
- package/skills/typesafety/env-and-bindings.md +18 -2
- package/skills/use-cache/SKILL.md +91 -23
- package/skills/vercel/SKILL.md +14 -2
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +75 -1
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +77 -18
- package/src/browser/navigation-client.ts +4 -3
- package/src/browser/navigation-store.ts +43 -1
- package/src/browser/navigation-transaction.ts +31 -11
- package/src/browser/partial-update.ts +146 -35
- package/src/browser/prefetch/cache.ts +6 -6
- package/src/browser/prefetch/fetch.ts +2 -2
- package/src/browser/react/Link.tsx +38 -33
- package/src/browser/react/NavigationProvider.tsx +2 -2
- package/src/browser/react/context.ts +2 -2
- package/src/browser/react/location-state-shared.ts +241 -49
- package/src/browser/react/location-state.ts +5 -2
- package/src/browser/rsc-router.tsx +9 -0
- package/src/browser/server-action-bridge.ts +84 -15
- package/src/browser/transition-when.ts +205 -0
- package/src/browser/types.ts +124 -10
- package/src/build/generate-manifest.ts +77 -1
- package/src/cache/background-task.ts +55 -2
- package/src/cache/cache-exec-scope.ts +48 -1
- package/src/cache/cache-key-utils.ts +62 -2
- package/src/cache/cache-policy.ts +31 -4
- package/src/cache/cache-runtime.ts +209 -129
- package/src/cache/cache-scope.ts +573 -69
- package/src/cache/cache-tag.ts +475 -19
- 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 +1094 -376
- 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 +55 -40
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +53 -9
- package/src/cache/index.ts +2 -0
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +249 -277
- package/src/cache/tag-invalidation.ts +109 -18
- package/src/cache/types.ts +274 -102
- package/src/cache/vercel/vercel-cache-store.ts +561 -74
- package/src/client-urls/client-root.tsx +8 -4
- package/src/client-urls/client-urls.ts +8 -6
- package/src/client-urls/navigation.ts +55 -4
- package/src/client-urls/server-projection.ts +31 -10
- package/src/client-urls/types.ts +12 -5
- package/src/client.tsx +2 -0
- package/src/host/cookie-handler.ts +2 -1
- package/src/index.rsc.ts +3 -0
- package/src/index.ts +3 -0
- package/src/loader-redirect.tsx +7 -3
- package/src/prerender/build-shell-capture.ts +173 -110
- package/src/route-definition/dsl-helpers.ts +6 -3
- package/src/route-definition/helpers-types.ts +11 -11
- package/src/route-name.ts +12 -0
- package/src/router/content-negotiation.ts +4 -1
- package/src/router/error-handling.ts +5 -2
- package/src/router/handler-context.ts +42 -5
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +30 -8
- package/src/router/loader-resolution.ts +89 -33
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +89 -42
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +14 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +52 -19
- package/src/router/match-middleware/cache-store.ts +36 -10
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware-types.ts +6 -1
- package/src/router/middleware.ts +20 -4
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +10 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +18 -13
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +366 -70
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +215 -126
- package/src/router/segment-resolution/mask-nested.ts +161 -42
- package/src/router/segment-resolution/revalidation.ts +27 -13
- package/src/router/segment-resolution/view-transition-default.ts +6 -21
- package/src/router/telemetry.ts +6 -3
- package/src/router/transition-when.ts +34 -52
- package/src/router.ts +2 -1
- package/src/rsc/attach-transition-when.ts +47 -0
- package/src/rsc/full-payload.ts +47 -3
- package/src/rsc/handler.ts +24 -10
- package/src/rsc/loader-fetch.ts +2 -1
- package/src/rsc/manifest-init.ts +4 -0
- package/src/rsc/origin-guard.ts +8 -5
- package/src/rsc/progressive-enhancement.ts +10 -32
- package/src/rsc/response-cache-serve.ts +69 -78
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +712 -338
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +49 -29
- package/src/rsc/shell-capture-constants.ts +182 -12
- package/src/rsc/shell-capture.ts +1126 -612
- package/src/rsc/shell-serve.ts +331 -85
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +9 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +328 -72
- package/src/server/cookie-store.ts +184 -133
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +364 -100
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/ssr/index.tsx +96 -37
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/flight.entry.ts +14 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/internal/action-id.ts +25 -0
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/location-state-key.ts +45 -0
- package/src/testing/render-handler.ts +1 -1
- package/src/testing/render-route.tsx +109 -16
- package/src/testing/run-client-revalidate.ts +3 -19
- package/src/testing/run-loader.ts +67 -5
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +381 -0
- package/src/testing/shell-status.ts +73 -47
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- package/src/types/handler-context.ts +14 -1
- package/src/types/index.ts +3 -0
- package/src/types/segments.ts +94 -91
- package/src/urls/path-helper-types.ts +3 -4
- package/src/urls/pattern-types.ts +21 -18
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +9 -2
- package/src/vite/discovery/virtual-module-codegen.ts +16 -6
- package/src/vite/plugins/transition-when-hoist.ts +1064 -0
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +89 -9
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
|
@@ -1,78 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Capture data snapshot: recording + seeding stores for PPR shell parity.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* A PPR HIT serves frozen prelude bytes, then a Flight payload for hydration
|
|
5
|
+
* that must agree with them byte for byte. The handler layer's part of that
|
|
6
|
+
* payload is the capture's own doc segment record: the capture writes it
|
|
7
|
+
* first, renders its prelude from it, and every HIT replays it (no handler
|
|
8
|
+
* runs on a HIT). The loader layer's part is the bake-lane (`ssr: false`)
|
|
9
|
+
* loader pins: a promise-free bake-lane loader is served from its pin and
|
|
10
|
+
* does not run; one whose return carries promises (`holes`), or whose pushes
|
|
11
|
+
* the record could not keep (`runs`), runs on the HIT. See
|
|
12
|
+
* docs/design/ppr-shell-resume.md.
|
|
11
13
|
*
|
|
12
|
-
* The
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* The invariant, verbatim: the snapshot is exactly the set of cache-store reads
|
|
22
|
-
* the capture render performed; replaying them on a HIT reproduces the shell
|
|
23
|
-
* content byte-identically; everything not recorded stays live.
|
|
14
|
+
* The invariant, verbatim: the snapshot is the doc record and the bake-lane
|
|
15
|
+
* loader pins; replaying them on a HIT reproduces the shell content
|
|
16
|
+
* byte-identically; everything else a HIT reads comes from the store. A hole
|
|
17
|
+
* (a live-lane loader, or a promise nested in a bake-lane return) never reads
|
|
18
|
+
* the capture's copy of a value: it is dynamic or has its own cache. A
|
|
19
|
+
* bake-lane loader body that runs on a HIT reads the store too; its pinned
|
|
20
|
+
* container paths stay the pin's (overlayLoaderContainer), and its settled
|
|
21
|
+
* pushes stay the record's (HandleStore.pushRestored).
|
|
24
22
|
*/
|
|
25
23
|
import type { SegmentCacheStore, CacheGetResult, CacheItemResult, CacheItemOptions, CachedEntryData, ShellCacheEntry, ShellSnapshotRecord, CacheReadError } from "./types.js";
|
|
26
24
|
/**
|
|
27
|
-
* A store wrapper the CAPTURE render reads through. Every call passes through
|
|
28
|
-
* the underlying store unchanged;
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* The shell family (getShell/putShell) is never recorded (the snapshot rides
|
|
34
|
-
* inside a shell entry). Reads that MISS are not recorded (a miss produced no
|
|
35
|
-
* shell content; if the render then computed and wrote, that write is recorded).
|
|
25
|
+
* A store wrapper the CAPTURE render reads through. Every call passes through
|
|
26
|
+
* to the underlying store unchanged; the one thing it records is the doc
|
|
27
|
+
* segment record ({@link recordSegmentWrite}). No cache read is recorded: a
|
|
28
|
+
* HIT replays the handler layer from the doc record and serves a promise-free
|
|
29
|
+
* bake-lane loader from its pin, and everything else a HIT reads (a hole, a
|
|
30
|
+
* bake-lane loader body that runs there) comes from the store.
|
|
36
31
|
*
|
|
37
32
|
* Deferred writes: cache writes run under waitUntil (fire-and-forget on Node,
|
|
38
|
-
* executionContext on workerd), so
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* executionContext on workerd), so the doc record's write may land after the
|
|
34
|
+
* capture's match returns. The capture collects those write promises via
|
|
35
|
+
* {@link trackWrite} and awaits them ({@link settleWrites}) before reading the
|
|
36
|
+
* record and draining.
|
|
42
37
|
*/
|
|
43
38
|
export declare class RecordingShellStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
44
39
|
private readonly inner;
|
|
40
|
+
/** The recorded segment records by key, last write wins. */
|
|
45
41
|
private readonly records;
|
|
46
42
|
private readonly writes;
|
|
47
43
|
constructor(inner: SegmentCacheStore<TEnv>);
|
|
48
44
|
get defaults(): SegmentCacheStore<TEnv>["defaults"];
|
|
49
45
|
get keyGenerator(): SegmentCacheStore<TEnv>["keyGenerator"];
|
|
50
46
|
get supportsPassiveShellReads(): true | undefined;
|
|
51
|
-
|
|
47
|
+
get isTagsInvalidatedSince(): SegmentCacheStore<TEnv>["isTagsInvalidatedSince"];
|
|
52
48
|
/** Track a deferred cache-write promise so the capture can await it pre-drain. */
|
|
53
49
|
trackWrite(p: Promise<unknown>): void;
|
|
54
50
|
/**
|
|
55
|
-
* Record
|
|
56
|
-
* store. The
|
|
57
|
-
* (via {@link SnapshotOnlySegmentStore}): the
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
51
|
+
* Record the doc segment record into the snapshot WITHOUT touching the
|
|
52
|
+
* inner store. The capture's implicit doc-cache scope writes through this
|
|
53
|
+
* (via {@link SnapshotOnlySegmentStore}): the record must ride ONLY inside
|
|
54
|
+
* the shell entry — a passthrough write would leave a doc-keyed entry in the
|
|
55
|
+
* real store that the NEXT capture's lookup would hit, replaying the
|
|
56
|
+
* previous generation's segments instead of re-running handlers (breaking
|
|
61
57
|
* SWR recapture freshness).
|
|
62
58
|
*/
|
|
63
59
|
recordSegmentWrite(key: string, data: CachedEntryData): void;
|
|
64
60
|
/**
|
|
65
|
-
* Await the tracked deferred writes so their records are present before
|
|
66
|
-
*
|
|
67
|
-
* cacheRoute path schedules its actual store.set in a second waitUntil
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
61
|
+
* Await the tracked deferred writes so their records are present before
|
|
62
|
+
* drain, including a NESTED write a settled one scheduled (the ring-3
|
|
63
|
+
* cacheRoute path schedules its actual store.set in a second waitUntil).
|
|
64
|
+
* Bounded: a pathologically slow write must never stall the capture task.
|
|
65
|
+
* Resolves true when every tracked write settled, false at the deadline
|
|
66
|
+
* (settleCaptureRecord then fails the capture when the doc record is among
|
|
67
|
+
* the writes still pending); a later call still waits for what is pending.
|
|
72
68
|
*/
|
|
73
|
-
settleWrites(timeoutMs: number): Promise<
|
|
74
|
-
/** The recorded
|
|
69
|
+
settleWrites(timeoutMs: number): Promise<boolean>;
|
|
70
|
+
/** The recorded segment records, or undefined if none. */
|
|
75
71
|
drainSnapshot(): ShellSnapshotRecord[] | undefined;
|
|
72
|
+
/** One recorded segment record, by key. */
|
|
73
|
+
getRecord(key: string): CachedEntryData | undefined;
|
|
76
74
|
get(key: string): Promise<CacheGetResult | null | CacheReadError>;
|
|
77
75
|
set(key: string, data: CachedEntryData, ttl: number, swr?: number): Promise<void>;
|
|
78
76
|
delete(key: string): Promise<boolean>;
|
|
@@ -93,16 +91,61 @@ export declare class RecordingShellStore<TEnv = unknown> implements SegmentCache
|
|
|
93
91
|
putShell(key: string, entry: ShellCacheEntry, ttlSeconds?: number, swrSeconds?: number, tags?: string[]): Promise<"stored" | "invalidated" | "uncacheable" | void>;
|
|
94
92
|
invalidateTags(tags: string[]): Promise<void>;
|
|
95
93
|
}
|
|
96
|
-
/**
|
|
94
|
+
/** `store` when it is a RecordingShellStore (an instanceof check). */
|
|
97
95
|
export declare function getRecordingStore<TEnv>(store: SegmentCacheStore<TEnv> | undefined): RecordingShellStore<TEnv> | undefined;
|
|
98
96
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
97
|
+
* True when `snapshot` carries the canonical doc segment record `docKey`
|
|
98
|
+
* names, with at least one segment: the record partial replay and a document
|
|
99
|
+
* HIT tail consume.
|
|
100
|
+
*/
|
|
101
|
+
export declare function hasDocRecord(snapshot: readonly ShellSnapshotRecord[] | undefined, docKey: string | undefined): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Split a capture's snapshot into what a HIT or a partial replay reads and
|
|
104
|
+
* the rest (docs/design/shell-entry-layout.md §2). Kept: the doc record
|
|
105
|
+
* (`docKey`), as a copy inside the entry (a separately stored record could be
|
|
106
|
+
* evicted on its own, and the HIT would have nothing to replay), and the
|
|
107
|
+
* loader-family pins unless the entry is navigation-only (partial replay of
|
|
108
|
+
* such an entry seeds the doc record alone). Every other record goes.
|
|
109
|
+
*/
|
|
110
|
+
export declare function pruneShellSnapshot(snapshot: readonly ShellSnapshotRecord[], navigationOnly: boolean, docKey: string | undefined): {
|
|
111
|
+
kept: ShellSnapshotRecord[];
|
|
112
|
+
pruned: ShellSnapshotRecord[];
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* The shell entry head's fields estimateShellEntryBytes does not measure
|
|
116
|
+
* (versions, timestamps, theme, lengths, flags; about 200 bytes in a
|
|
117
|
+
* CFCacheStore frame) and the frame's 12-byte prefix, with room to spare.
|
|
118
|
+
*/
|
|
119
|
+
export declare const SHELL_ENTRY_HEAD_ALLOWANCE_BYTES: number;
|
|
120
|
+
/**
|
|
121
|
+
* Bytes (UTF-8) a stored shell entry takes, as the built-in stores write it:
|
|
122
|
+
* the prelude, the snapshot's JSON, and a JSON head that carries the
|
|
123
|
+
* postponed state as an escaped string next to the tags and doc key
|
|
124
|
+
* (CFCacheStore's frame head, VercelCacheStore's envelope), plus
|
|
125
|
+
* SHELL_ENTRY_HEAD_ALLOWANCE_BYTES for the head's fixed fields and the
|
|
126
|
+
* frame prefix. Measuring the raw postponed bytes undercounted: every quote
|
|
127
|
+
* in it is escaped in the head (a /ppr-large/holes entry measured 1,098
|
|
128
|
+
* bytes under its KV value). The capture's whole-entry guard compares this
|
|
129
|
+
* with the store's value limit.
|
|
130
|
+
*/
|
|
131
|
+
export declare function estimateShellEntryBytes(parts: {
|
|
132
|
+
preludeBytes: number;
|
|
133
|
+
postponed: string | null | undefined;
|
|
134
|
+
snapshot: readonly ShellSnapshotRecord[] | undefined;
|
|
135
|
+
tags: readonly string[] | undefined;
|
|
136
|
+
docKey: string | undefined;
|
|
137
|
+
prunedRecords: string | undefined;
|
|
138
|
+
}): number;
|
|
139
|
+
/** Snapshot records by family, e.g. `segment:1/loader:2` (no commas: it rides a Server-Timing desc). */
|
|
140
|
+
export declare function countSnapshotFamilies(snapshot: readonly ShellSnapshotRecord[]): string;
|
|
141
|
+
/**
|
|
142
|
+
* The store the capture's IMPLICIT doc-cache scope resolves: reads pass
|
|
143
|
+
* through the recording store to the real one, but segment WRITES are
|
|
144
|
+
* recorded into the snapshot only — see
|
|
145
|
+
* {@link RecordingShellStore.recordSegmentWrite} for why passthrough would
|
|
146
|
+
* break SWR recapture. A route with its OWN cache() scope keeps that scope's
|
|
147
|
+
* real-store reads and writes; recordShellCaptureDocRecord (cache-store.ts)
|
|
148
|
+
* writes its doc record through this store too.
|
|
106
149
|
*/
|
|
107
150
|
export declare class SnapshotOnlySegmentStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
108
151
|
private readonly recording;
|
|
@@ -113,74 +156,67 @@ export declare class SnapshotOnlySegmentStore<TEnv = unknown> implements Segment
|
|
|
113
156
|
set(key: string, data: CachedEntryData): Promise<void>;
|
|
114
157
|
delete(key: string): Promise<boolean>;
|
|
115
158
|
}
|
|
159
|
+
/** One decoded loader-family pin (buildShellLoaderSeed). */
|
|
160
|
+
export interface ShellLoaderSeedEntry {
|
|
161
|
+
/** The Flight-deserialized elided container (recorded paths + markers). */
|
|
162
|
+
container: unknown;
|
|
163
|
+
/**
|
|
164
|
+
* True when the record carries hole markers: the HIT overlay must gate on
|
|
165
|
+
* the fresh run. False = fully pinned; the payload promise resolves
|
|
166
|
+
* immediately from the pin (loader-cache.ts pin-first path).
|
|
167
|
+
*/
|
|
168
|
+
holes: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* The record needs its loader body to run on a HIT for pushes the capture
|
|
171
|
+
* could not record (ShellSnapshotLoaderValue.runs). Only read for a
|
|
172
|
+
* hole-free record: a hole-carrying one always runs.
|
|
173
|
+
*/
|
|
174
|
+
runs: boolean;
|
|
175
|
+
}
|
|
116
176
|
/**
|
|
117
177
|
* Materialize the loader-family seed from a shell snapshot for a HIT's tail
|
|
118
178
|
* render: Flight-deserialize each recorded (promise-elided) bake-lane
|
|
119
179
|
* container into a segment-key -> container Map, which serveShellHit assigns
|
|
120
180
|
* to the tail context's `_shellLoaderSeed` for the resolveLoaderData overlay.
|
|
121
|
-
* Lives here so every snapshot family is decoded in this module (the
|
|
122
|
-
*
|
|
123
|
-
*
|
|
181
|
+
* Lives here so every snapshot family is decoded in this module (the segment
|
|
182
|
+
* family via {@link SeededShellStore}); the loader family is not a store
|
|
183
|
+
* read, so it seeds the context instead of a store.
|
|
124
184
|
*
|
|
125
185
|
* Deserializations run in parallel; a record that fails to decode is skipped
|
|
126
186
|
* (that loader drifts — the pre-snapshot behavior — instead of failing the
|
|
127
187
|
* HIT). Returns undefined when the snapshot carries no loader records, without
|
|
128
188
|
* touching the Flight codec (kept lazy for cold paths and non-RSC configs).
|
|
129
189
|
*/
|
|
130
|
-
export interface ShellLoaderSeedEntry {
|
|
131
|
-
/** The Flight-deserialized elided container (recorded paths + markers). */
|
|
132
|
-
container: unknown;
|
|
133
|
-
/**
|
|
134
|
-
* True when the record carries hole markers (or predates the capture-side
|
|
135
|
-
* hole bit, where hole-ness is unknown): the HIT overlay must gate on the
|
|
136
|
-
* fresh run. False = fully pinned; the payload promise resolves immediately
|
|
137
|
-
* from the pin (loader-cache.ts pin-first path).
|
|
138
|
-
*/
|
|
139
|
-
holes: boolean;
|
|
140
|
-
}
|
|
141
190
|
export declare function buildShellLoaderSeed(snapshot: ShellSnapshotRecord[]): Promise<Map<string, ShellLoaderSeedEntry> | undefined>;
|
|
142
191
|
/**
|
|
143
|
-
*
|
|
144
|
-
* the snapshot
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* partial navigation cannot freeze captured data or write a partial result into
|
|
153
|
-
* the canonical document namespace.
|
|
192
|
+
* The implicit doc scope's store on a HIT tail and on a partial replay: it
|
|
193
|
+
* serves the snapshot's segment records, the doc record among them, and
|
|
194
|
+
* fully isolates the segment family. Misses do not fall through, and writes
|
|
195
|
+
* or deletes stay local to the overlay, so a partial navigation cannot write
|
|
196
|
+
* a partial result into the canonical document namespace. It carries nothing
|
|
197
|
+
* else: every other read on a HIT (a hole, a bake-lane loader body that runs
|
|
198
|
+
* there) resolves the request's own store. Loader-family records are not
|
|
199
|
+
* store reads: serveShellHit seeds them onto the tail context
|
|
200
|
+
* (_shellLoaderSeed) for the resolveLoaderData overlay instead.
|
|
154
201
|
*/
|
|
155
202
|
export declare class SeededShellStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
156
203
|
private readonly inner;
|
|
157
|
-
private readonly items;
|
|
158
204
|
private readonly segments;
|
|
159
|
-
|
|
160
|
-
private readonly segmentsOnly;
|
|
161
|
-
constructor(inner: SegmentCacheStore<TEnv>, snapshot: ShellSnapshotRecord[], options?: {
|
|
162
|
-
segmentsOnly?: boolean;
|
|
163
|
-
});
|
|
205
|
+
constructor(inner: SegmentCacheStore<TEnv>, snapshot: readonly ShellSnapshotRecord[]);
|
|
164
206
|
get defaults(): SegmentCacheStore<TEnv>["defaults"];
|
|
165
207
|
get keyGenerator(): SegmentCacheStore<TEnv>["keyGenerator"];
|
|
166
|
-
get supportsPassiveShellReads(): true | undefined;
|
|
167
208
|
get(key: string): Promise<CacheGetResult | null | CacheReadError>;
|
|
168
|
-
set(key: string, data: CachedEntryData
|
|
209
|
+
set(key: string, data: CachedEntryData): Promise<void>;
|
|
169
210
|
delete(key: string): Promise<boolean>;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
entry: ShellCacheEntry;
|
|
182
|
-
shouldRevalidate?: boolean;
|
|
183
|
-
} | null>;
|
|
184
|
-
putShell(key: string, entry: ShellCacheEntry, ttlSeconds?: number, swrSeconds?: number, tags?: string[]): Promise<"stored" | "invalidated" | "uncacheable" | void>;
|
|
185
|
-
invalidateTags(tags: string[]): Promise<void>;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Thrown by a document HIT tail's match when its doc record cannot supply the
|
|
214
|
+
* handler layer (it failed to decode, or the entry lost it). The tail must not
|
|
215
|
+
* run handlers after the prelude committed, so withCacheLookup throws this
|
|
216
|
+
* instead of resolving segments, and serveShellHit degrades the response:
|
|
217
|
+
* the entry is replaced with a tombstone, the memo is dropped, a recapture is
|
|
218
|
+
* scheduled, and the browser reloads into a MISS.
|
|
219
|
+
*/
|
|
220
|
+
export declare class ShellRecordUnavailableError extends Error {
|
|
221
|
+
constructor(docKey: string | undefined);
|
|
186
222
|
}
|
|
@@ -21,7 +21,56 @@
|
|
|
21
21
|
* primitive for each tag. A single configured store (the common case) owns its
|
|
22
22
|
* own tag index and distributed invalidation - there is no separate
|
|
23
23
|
* tag-invalidation store.
|
|
24
|
+
*
|
|
25
|
+
* Both call invalidateTags() synchronously, inside the request (#973). A store
|
|
26
|
+
* masks the tags for the rest of the request before its first await (the
|
|
27
|
+
* built-in stores write their per-request marker state there), so the request
|
|
28
|
+
* that ran either verb reads its own writes; revalidateTag() leaves only the
|
|
29
|
+
* durable remainder (KV marker put, tag purge, expireTag) to waitUntil.
|
|
30
|
+
* Invariant: the mask only turns the invalidating request's hits into misses.
|
|
31
|
+
* If the durable write then fails, that request paid extra misses, never a
|
|
32
|
+
* stale read, and other requests read the durable state. Both also record
|
|
33
|
+
* the tags in the isolate's invalidation order (markInvalidated), so a cache
|
|
34
|
+
* execution that started before one of its tags was invalidated, in any
|
|
35
|
+
* request, is neither joined nor written (#973, #977): see
|
|
36
|
+
* predatesInvalidation, and docs/design/caching.md "Read-your-own-writes".
|
|
37
|
+
*/
|
|
38
|
+
import type { SegmentCacheStore } from "./types.js";
|
|
39
|
+
import { type ExecutionStart } from "./invalidation-order.js";
|
|
40
|
+
export { executionStart, invalidatedSince, type ExecutionStart, } from "./invalidation-order.js";
|
|
41
|
+
/**
|
|
42
|
+
* The write gate of every cache execution (#977): whether one of `tags` was
|
|
43
|
+
* invalidated after the execution that produced the value started.
|
|
44
|
+
*
|
|
45
|
+
* Every built-in store stamps an entry when it is written (CFCacheStore's
|
|
46
|
+
* `taggedAt`, VercelCacheStore's `ta`) or checks nothing on write
|
|
47
|
+
* (MemorySegmentCacheStore), so a value read before an invalidation and
|
|
48
|
+
* written after it would be served as newer than the invalidation until it
|
|
49
|
+
* expires. Two answers, either one skips the write:
|
|
50
|
+
*
|
|
51
|
+
* - this isolate's order (invalidatedSince), which sees every request's
|
|
52
|
+
* updateTag()/revalidateTag() here, the calling one included;
|
|
53
|
+
* - the store's markers (isTagsInvalidatedSince), for another isolate's
|
|
54
|
+
* invalidation, as far as the store can tell: KV markers on CFCacheStore
|
|
55
|
+
* (KV-less, only this request's own), `tm` markers on VercelCacheStore,
|
|
56
|
+
* the process markers on MemorySegmentCacheStore. Asked about the
|
|
57
|
+
* milliseconds after the start's: this isolate's own invalidation that
|
|
58
|
+
* preceded the start usually shares its millisecond (Workers freeze
|
|
59
|
+
* Date.now() between I/O), and `>=` would skip every write started right
|
|
60
|
+
* after it. Another isolate's invalidation in the start's own millisecond
|
|
61
|
+
* is not caught. Asked fail-closed: a marker the store cannot read
|
|
62
|
+
* counts as an invalidation.
|
|
63
|
+
*
|
|
64
|
+
* The order is read again once the store answers: its read can be in flight
|
|
65
|
+
* while this isolate invalidates (an action awaits a "use cache" miss, whose
|
|
66
|
+
* write waits on the read, then runs updateTag()), and it then answers with
|
|
67
|
+
* the markers from before. markInvalidated is synchronous, so this second
|
|
68
|
+
* look sees every invalidation made before the answer.
|
|
69
|
+
*
|
|
70
|
+
* Invariant: a skipped write only costs a later miss, never a stale read.
|
|
71
|
+
* The caller still returns the value it computed.
|
|
24
72
|
*/
|
|
73
|
+
export declare function predatesInvalidation(store: SegmentCacheStore, tags: readonly string[] | undefined, start: ExecutionStart): Promise<boolean>;
|
|
25
74
|
/**
|
|
26
75
|
* Immediately expire every cache entry tagged with any of `tags`, resolving
|
|
27
76
|
* once in-process invalidation across all configured stores completes.
|
|
@@ -47,10 +96,12 @@ export declare function updateTag(...tags: string[]): Promise<void>;
|
|
|
47
96
|
* This is NOT stale-while-revalidate: like updateTag() it hard-purges, so the
|
|
48
97
|
* next read after the invalidation lands is a miss that re-renders fresh. The
|
|
49
98
|
* only difference from updateTag() is awaitability - revalidateTag() defers the
|
|
50
|
-
*
|
|
99
|
+
* durable write off the response path and is not awaited.
|
|
51
100
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
101
|
+
* Read-your-own-writes (#973): each built-in store masks the tags for the rest
|
|
102
|
+
* of this request before revalidateTag() returns, so a Server Action's own
|
|
103
|
+
* re-render after it is fresh, as after `await updateTag()`. Other requests see
|
|
104
|
+
* the invalidation once the durable write lands.
|
|
54
105
|
*
|
|
55
106
|
* Fire-and-forget: because this returns void and runs in the background, a
|
|
56
107
|
* failed durable marker write (e.g. a transient KV outage) is NOT surfaced to
|