@rangojs/router 0.18.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/dist/types/browser/event-controller.d.ts +3 -3
- package/dist/types/browser/history-state.d.ts +2 -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 +44 -13
- package/dist/types/cache/cache-policy.d.ts +1 -1
- package/dist/types/cache/cache-runtime.d.ts +7 -0
- package/dist/types/cache/cache-scope.d.ts +117 -35
- package/dist/types/cache/cache-tag.d.ts +24 -4
- package/dist/types/cache/cf/cf-cache-store.d.ts +55 -44
- package/dist/types/cache/cf/cf-shell-frame.d.ts +1 -1
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +0 -15
- package/dist/types/cache/document-cache.d.ts +10 -0
- package/dist/types/cache/handle-snapshot.d.ts +40 -8
- package/dist/types/cache/invalidation-order.d.ts +23 -0
- package/dist/types/cache/request-tag-mask.d.ts +54 -0
- package/dist/types/cache/shell-snapshot.d.ts +88 -141
- package/dist/types/cache/tag-invalidation.d.ts +38 -14
- package/dist/types/cache/types.d.ts +68 -61
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +23 -16
- 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/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/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/router-options.d.ts +4 -1
- package/dist/types/router/segment-resolution/loader-cache.d.ts +18 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -4
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +14 -40
- package/dist/types/router/segment-resolution/mask-nested.d.ts +11 -3
- 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 +14 -7
- package/dist/types/rsc/response-cache-serve.d.ts +15 -12
- package/dist/types/rsc/shell-build-manifest.d.ts +4 -3
- package/dist/types/rsc/shell-capture-constants.d.ts +77 -20
- package/dist/types/rsc/shell-capture.d.ts +78 -81
- package/dist/types/rsc/shell-serve.d.ts +19 -48
- package/dist/types/rsc/types.d.ts +2 -0
- package/dist/types/segment-system.d.ts +7 -0
- package/dist/types/server/context.d.ts +89 -61
- package/dist/types/server/cookie-store.d.ts +30 -18
- package/dist/types/server/handle-store.d.ts +52 -1
- package/dist/types/server/request-context.d.ts +66 -45
- package/dist/types/server/request-headers.d.ts +44 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/e2e/index.d.ts +1 -1
- 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-transition-when.d.ts +44 -69
- package/dist/types/testing/serve-shell-request.d.ts +7 -6
- package/dist/types/testing/shell-status.d.ts +34 -22
- package/dist/types/transition-when-ref.d.ts +79 -0
- package/dist/types/types/cache-types.d.ts +15 -3
- 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 +3 -4
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +45 -0
- package/dist/vite/index.js +960 -97
- package/package.json +1 -1
- package/skills/cache-guide/SKILL.md +76 -49
- package/skills/caching/SKILL.md +167 -69
- package/skills/client-urls/SKILL.md +1 -1
- package/skills/comparison/references/framework-comparison.md +8 -5
- package/skills/document-cache/SKILL.md +24 -0
- package/skills/hooks/SKILL.md +3 -1
- package/skills/hooks/navigation.md +23 -2
- package/skills/hooks/state.md +98 -6
- package/skills/intercept/SKILL.md +29 -12
- package/skills/loader/SKILL.md +52 -21
- package/skills/middleware/SKILL.md +18 -0
- package/skills/migrate-nextjs/SKILL.md +3 -3
- package/skills/observability/SKILL.md +6 -5
- package/skills/parallel/SKILL.md +1 -1
- package/skills/ppr/SKILL.md +129 -77
- package/skills/prerender/SKILL.md +3 -3
- package/skills/rango/SKILL.md +25 -6
- package/skills/route/SKILL.md +2 -0
- package/skills/testing/SKILL.md +27 -25
- package/skills/testing/cache-prerender.md +9 -9
- package/skills/testing/client-components.md +45 -3
- package/skills/testing/loader.md +3 -2
- 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 +14 -0
- package/skills/testing/server-actions.md +9 -3
- package/skills/theme/SKILL.md +8 -4
- package/skills/typesafety/env-and-bindings.md +8 -0
- package/skills/use-cache/SKILL.md +64 -19
- package/skills/view-transitions/SKILL.md +150 -29
- package/src/__augment-tests__/augmented.check.ts +23 -0
- package/src/browser/event-controller.ts +4 -4
- package/src/browser/history-state.ts +52 -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 +4 -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 +56 -16
- package/src/cache/cache-policy.ts +9 -4
- package/src/cache/cache-runtime.ts +197 -144
- package/src/cache/cache-scope.ts +304 -112
- package/src/cache/cache-tag.ts +105 -13
- package/src/cache/cf/cf-cache-store.ts +152 -76
- package/src/cache/cf/cf-shell-frame.ts +2 -2
- package/src/cache/cf/cf-tag-marker-memo.ts +11 -100
- package/src/cache/document-cache.ts +53 -7
- package/src/cache/handle-snapshot.ts +52 -9
- package/src/cache/invalidation-order.ts +84 -0
- package/src/cache/request-tag-mask.ts +147 -0
- package/src/cache/shell-snapshot.ts +130 -348
- package/src/cache/tag-invalidation.ts +57 -51
- package/src/cache/types.ts +71 -67
- package/src/cache/vercel/vercel-cache-store.ts +61 -58
- 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 +155 -146
- package/src/route-definition/dsl-helpers.ts +2 -0
- 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 +10 -7
- package/src/router/intercept-resolution.ts +11 -1
- package/src/router/loader-resolution.ts +28 -3
- package/src/router/logging.ts +5 -3
- package/src/router/match-api.ts +62 -34
- package/src/router/match-context.ts +5 -0
- package/src/router/match-handlers.ts +9 -29
- package/src/router/match-middleware/background-revalidation.ts +3 -5
- package/src/router/match-middleware/cache-lookup.ts +35 -19
- package/src/router/match-middleware/cache-store.ts +15 -9
- package/src/router/match-result.ts +1 -0
- package/src/router/middleware.ts +2 -5
- package/src/router/navigation-snapshot.ts +6 -5
- package/src/router/prerender-match.ts +4 -0
- package/src/router/request-classification.ts +7 -4
- package/src/router/router-options.ts +4 -1
- package/src/router/segment-resolution/fresh.ts +0 -4
- package/src/router/segment-resolution/loader-cache.ts +150 -25
- package/src/router/segment-resolution/loader-mask.ts +3 -4
- package/src/router/segment-resolution/loader-snapshot.ts +15 -78
- package/src/router/segment-resolution/mask-nested.ts +47 -22
- package/src/router/segment-resolution/revalidation.ts +0 -3
- 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 +30 -10
- package/src/rsc/handler.ts +12 -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 +7 -30
- package/src/rsc/response-cache-serve.ts +68 -80
- package/src/rsc/response-route-handler.ts +2 -2
- package/src/rsc/rsc-rendering.ts +206 -252
- package/src/rsc/server-action.ts +8 -20
- package/src/rsc/shell-build-manifest.ts +22 -20
- package/src/rsc/shell-capture-constants.ts +136 -20
- package/src/rsc/shell-capture.ts +352 -589
- package/src/rsc/shell-serve.ts +73 -109
- package/src/rsc/ssr-setup.ts +3 -2
- package/src/rsc/types.ts +2 -0
- package/src/segment-system.tsx +40 -7
- package/src/server/context.ts +189 -124
- package/src/server/cookie-store.ts +153 -127
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +123 -84
- package/src/server/request-headers.ts +134 -0
- package/src/server.ts +4 -0
- package/src/testing/dispatch.ts +4 -7
- package/src/testing/e2e/index.ts +1 -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 +5 -1
- package/src/testing/run-transition-when.ts +109 -172
- package/src/testing/serve-shell-request.ts +10 -7
- package/src/testing/shell-status.ts +60 -56
- package/src/transition-when-ref.ts +220 -0
- package/src/types/cache-types.ts +15 -3
- 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 +3 -4
- package/src/vite/discovery/discover-routers.ts +3 -0
- package/src/vite/discovery/shell-prerender-phase.ts +0 -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 +75 -5
- package/dist/types/rsc/transition-gate.d.ts +0 -23
- package/src/rsc/transition-gate.ts +0 -86
|
@@ -5,23 +5,20 @@
|
|
|
5
5
|
* that must agree with them byte for byte. The handler layer's part of that
|
|
6
6
|
* payload is the capture's own doc segment record: the capture writes it
|
|
7
7
|
* first, renders its prelude from it, and every HIT replays it (no handler
|
|
8
|
-
* runs on a HIT).
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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.
|
|
12
13
|
*
|
|
13
|
-
* The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* The invariant, verbatim: the snapshot is the doc record plus the cache-store
|
|
22
|
-
* reads the capture's loaders performed; replaying them on a HIT reproduces
|
|
23
|
-
* the shell content byte-identically; everything not recorded stays live.
|
|
24
|
-
* {@link pruneShellSnapshot} drops the rest.
|
|
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).
|
|
25
22
|
*/
|
|
26
23
|
|
|
27
24
|
import type {
|
|
@@ -32,74 +29,46 @@ import type {
|
|
|
32
29
|
CachedEntryData,
|
|
33
30
|
ShellCacheEntry,
|
|
34
31
|
ShellSnapshotRecord,
|
|
35
|
-
ShellSnapshotItemValue,
|
|
36
|
-
ShellSnapshotResponseValue,
|
|
37
32
|
ShellSnapshotLoaderValue,
|
|
38
33
|
CacheReadError,
|
|
39
34
|
} from "./types.js";
|
|
40
|
-
import {
|
|
41
|
-
import { bufferToBase64, base64ToBuffer } from "./cf/cf-base64.js";
|
|
42
|
-
import { isPerClientSignalHeader } from "../browser/cookie-name.js";
|
|
43
|
-
import { isInsideAnyLoaderScope } from "../server/context.js";
|
|
44
|
-
|
|
45
|
-
/** Compose the last-write-wins map key. NUL (`\u0000`) cannot appear in a cache key. */
|
|
46
|
-
function recordKey(family: ShellSnapshotRecord["family"], key: string): string {
|
|
47
|
-
return `${family}\u0000${key}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Serialize a Response to the snapshot's stored shape (base64 body). */
|
|
51
|
-
async function serializeResponse(
|
|
52
|
-
response: Response,
|
|
53
|
-
): Promise<ShellSnapshotResponseValue> {
|
|
54
|
-
const body = await response.clone().arrayBuffer();
|
|
55
|
-
const headers: [string, string][] = [];
|
|
56
|
-
response.headers.forEach((value, name) => {
|
|
57
|
-
// Mirror putResponse: per-client signal headers never enter a shared entry.
|
|
58
|
-
if (isPerClientSignalHeader(name)) return;
|
|
59
|
-
headers.push([name, value]);
|
|
60
|
-
});
|
|
61
|
-
return { status: response.status, headers, body: bufferToBase64(body) };
|
|
62
|
-
}
|
|
35
|
+
import { settleGrowing } from "./background-task.js";
|
|
63
36
|
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The inner store's isTagsInvalidatedSince, absent when it has none. A
|
|
39
|
+
* capture runs on RecordingShellStore as the request's store, and the writes
|
|
40
|
+
* it passes through gate on it (#977, tag-invalidation.ts
|
|
41
|
+
* predatesInvalidation).
|
|
42
|
+
*/
|
|
43
|
+
function forwardTagHistory<TEnv>(
|
|
44
|
+
inner: SegmentCacheStore<TEnv>,
|
|
45
|
+
): SegmentCacheStore<TEnv>["isTagsInvalidatedSince"] {
|
|
46
|
+
return inner.isTagsInvalidatedSince
|
|
47
|
+
? (tags, sinceMs, options) =>
|
|
48
|
+
inner.isTagsInvalidatedSince!(tags, sinceMs, options)
|
|
49
|
+
: undefined;
|
|
70
50
|
}
|
|
71
51
|
|
|
72
52
|
/**
|
|
73
|
-
* A store wrapper the CAPTURE render reads through. Every call passes through
|
|
74
|
-
* the underlying store unchanged;
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* The shell family (getShell/putShell) is never recorded (the snapshot rides
|
|
80
|
-
* inside a shell entry). Reads that MISS are not recorded (a miss produced no
|
|
81
|
-
* shell content; if the render then computed and wrote, that write is recorded).
|
|
53
|
+
* A store wrapper the CAPTURE render reads through. Every call passes through
|
|
54
|
+
* to the underlying store unchanged; the one thing it records is the doc
|
|
55
|
+
* segment record ({@link recordSegmentWrite}). No cache read is recorded: a
|
|
56
|
+
* HIT replays the handler layer from the doc record and serves a promise-free
|
|
57
|
+
* bake-lane loader from its pin, and everything else a HIT reads (a hole, a
|
|
58
|
+
* bake-lane loader body that runs there) comes from the store.
|
|
82
59
|
*
|
|
83
60
|
* Deferred writes: cache writes run under waitUntil (fire-and-forget on Node,
|
|
84
|
-
* executionContext on workerd), so
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* Loader attribution: every item/response access made inside a loader scope
|
|
90
|
-
* (hit, miss or write) marks its key in {@link loaderKeys}. A loader re-runs
|
|
91
|
-
* on every HIT, so those records stay pinned when the snapshot is pruned. A
|
|
92
|
-
* miss counts too: a loader that joins a handler's in-flight "use cache" call
|
|
93
|
-
* reads the store first (cache-runtime.ts) and finds nothing, and the record
|
|
94
|
-
* then comes from the handler's write.
|
|
61
|
+
* executionContext on workerd), so the doc record's write may land after the
|
|
62
|
+
* capture's match returns. The capture collects those write promises via
|
|
63
|
+
* {@link trackWrite} and awaits them ({@link settleWrites}) before reading the
|
|
64
|
+
* record and draining.
|
|
95
65
|
*/
|
|
96
66
|
export class RecordingShellStore<
|
|
97
67
|
TEnv = unknown,
|
|
98
68
|
> implements SegmentCacheStore<TEnv> {
|
|
99
|
-
|
|
69
|
+
/** The recorded segment records by key, last write wins. */
|
|
70
|
+
private readonly records = new Map<string, CachedEntryData>();
|
|
100
71
|
private readonly writes: Promise<unknown>[] = [];
|
|
101
|
-
/** Record keys ({@link recordKey}) a loader read or wrote during the capture. */
|
|
102
|
-
readonly loaderKeys: Set<string> = new Set();
|
|
103
72
|
|
|
104
73
|
constructor(private readonly inner: SegmentCacheStore<TEnv>) {}
|
|
105
74
|
|
|
@@ -112,20 +81,8 @@ export class RecordingShellStore<
|
|
|
112
81
|
get supportsPassiveShellReads(): true | undefined {
|
|
113
82
|
return this.inner.supportsPassiveShellReads;
|
|
114
83
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
family: ShellSnapshotRecord["family"],
|
|
118
|
-
key: string,
|
|
119
|
-
value: ShellSnapshotRecord["value"],
|
|
120
|
-
): void {
|
|
121
|
-
this.records.set(recordKey(family, key), { family, key, value });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private noteLoaderAccess(
|
|
125
|
-
family: ShellSnapshotRecord["family"],
|
|
126
|
-
key: string,
|
|
127
|
-
): void {
|
|
128
|
-
if (isInsideAnyLoaderScope()) this.loaderKeys.add(recordKey(family, key));
|
|
84
|
+
get isTagsInvalidatedSince(): SegmentCacheStore<TEnv>["isTagsInvalidatedSince"] {
|
|
85
|
+
return forwardTagHistory(this.inner);
|
|
129
86
|
}
|
|
130
87
|
|
|
131
88
|
/** Track a deferred cache-write promise so the capture can await it pre-drain. */
|
|
@@ -134,74 +91,50 @@ export class RecordingShellStore<
|
|
|
134
91
|
}
|
|
135
92
|
|
|
136
93
|
/**
|
|
137
|
-
* Record
|
|
138
|
-
* store. The
|
|
139
|
-
* (via {@link SnapshotOnlySegmentStore}): the
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
94
|
+
* Record the doc segment record into the snapshot WITHOUT touching the
|
|
95
|
+
* inner store. The capture's implicit doc-cache scope writes through this
|
|
96
|
+
* (via {@link SnapshotOnlySegmentStore}): the record must ride ONLY inside
|
|
97
|
+
* the shell entry — a passthrough write would leave a doc-keyed entry in the
|
|
98
|
+
* real store that the NEXT capture's lookup would hit, replaying the
|
|
99
|
+
* previous generation's segments instead of re-running handlers (breaking
|
|
143
100
|
* SWR recapture freshness).
|
|
144
101
|
*/
|
|
145
102
|
recordSegmentWrite(key: string, data: CachedEntryData): void {
|
|
146
|
-
this.
|
|
103
|
+
this.records.set(key, data);
|
|
147
104
|
}
|
|
148
105
|
|
|
149
106
|
/**
|
|
150
|
-
* Await the tracked deferred writes so their records are present before
|
|
151
|
-
*
|
|
152
|
-
* cacheRoute path schedules its actual store.set in a second waitUntil
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* when the doc record is among the writes still pending).
|
|
107
|
+
* Await the tracked deferred writes so their records are present before
|
|
108
|
+
* drain, including a NESTED write a settled one scheduled (the ring-3
|
|
109
|
+
* cacheRoute path schedules its actual store.set in a second waitUntil).
|
|
110
|
+
* Bounded: a pathologically slow write must never stall the capture task.
|
|
111
|
+
* Resolves true when every tracked write settled, false at the deadline
|
|
112
|
+
* (settleCaptureRecord then fails the capture when the doc record is among
|
|
113
|
+
* the writes still pending); a later call still waits for what is pending.
|
|
158
114
|
*/
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
while (this.writes.length > 0) {
|
|
162
|
-
const remaining = deadline - Date.now();
|
|
163
|
-
if (remaining <= 0) return false;
|
|
164
|
-
// Take the current batch; new writes scheduled while awaiting accumulate in
|
|
165
|
-
// this.writes and are drained on the next iteration.
|
|
166
|
-
const batch = this.writes.splice(0);
|
|
167
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
168
|
-
const guard = new Promise<false>((resolve) => {
|
|
169
|
-
timer = setTimeout(() => resolve(false), remaining);
|
|
170
|
-
(timer as { unref?: () => void }).unref?.();
|
|
171
|
-
});
|
|
172
|
-
const settled = await Promise.race([
|
|
173
|
-
Promise.allSettled(batch).then(() => true as const),
|
|
174
|
-
guard,
|
|
175
|
-
]);
|
|
176
|
-
if (timer) clearTimeout(timer);
|
|
177
|
-
if (!settled) {
|
|
178
|
-
// Keep tracking the batch: a later settleWrites still waits for it.
|
|
179
|
-
this.writes.unshift(...batch);
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return true;
|
|
115
|
+
settleWrites(timeoutMs: number): Promise<boolean> {
|
|
116
|
+
return settleGrowing(this.writes, Date.now() + timeoutMs);
|
|
184
117
|
}
|
|
185
118
|
|
|
186
|
-
/** The recorded
|
|
119
|
+
/** The recorded segment records, or undefined if none. */
|
|
187
120
|
drainSnapshot(): ShellSnapshotRecord[] | undefined {
|
|
188
|
-
|
|
121
|
+
if (this.records.size === 0) return undefined;
|
|
122
|
+
return [...this.records].map(
|
|
123
|
+
([key, value]): ShellSnapshotRecord => ({
|
|
124
|
+
family: "segment",
|
|
125
|
+
key,
|
|
126
|
+
value,
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
189
129
|
}
|
|
190
130
|
|
|
191
|
-
/** One recorded
|
|
192
|
-
getRecord(
|
|
193
|
-
|
|
194
|
-
key: string,
|
|
195
|
-
): ShellSnapshotRecord["value"] | undefined {
|
|
196
|
-
return this.records.get(recordKey(family, key))?.value;
|
|
131
|
+
/** One recorded segment record, by key. */
|
|
132
|
+
getRecord(key: string): CachedEntryData | undefined {
|
|
133
|
+
return this.records.get(key);
|
|
197
134
|
}
|
|
198
135
|
|
|
199
136
|
async get(key: string): Promise<CacheGetResult | null | CacheReadError> {
|
|
200
|
-
|
|
201
|
-
if (result && result !== CACHE_READ_ERROR) {
|
|
202
|
-
this.record("segment", key, result.data);
|
|
203
|
-
}
|
|
204
|
-
return result;
|
|
137
|
+
return this.inner.get(key);
|
|
205
138
|
}
|
|
206
139
|
|
|
207
140
|
async set(
|
|
@@ -210,7 +143,6 @@ export class RecordingShellStore<
|
|
|
210
143
|
ttl: number,
|
|
211
144
|
swr?: number,
|
|
212
145
|
): Promise<void> {
|
|
213
|
-
this.record("segment", key, data);
|
|
214
146
|
return this.inner.set(key, data, ttl, swr);
|
|
215
147
|
}
|
|
216
148
|
|
|
@@ -225,12 +157,7 @@ export class RecordingShellStore<
|
|
|
225
157
|
async getResponse(
|
|
226
158
|
key: string,
|
|
227
159
|
): Promise<{ response: Response; shouldRevalidate: boolean } | null> {
|
|
228
|
-
|
|
229
|
-
this.noteLoaderAccess("response", key);
|
|
230
|
-
const result = await this.inner.getResponse(key);
|
|
231
|
-
if (result)
|
|
232
|
-
this.record("response", key, await serializeResponse(result.response));
|
|
233
|
-
return result;
|
|
160
|
+
return this.inner.getResponse ? this.inner.getResponse(key) : null;
|
|
234
161
|
}
|
|
235
162
|
|
|
236
163
|
async putResponse(
|
|
@@ -240,25 +167,11 @@ export class RecordingShellStore<
|
|
|
240
167
|
swr?: number,
|
|
241
168
|
tags?: string[],
|
|
242
169
|
): Promise<void> {
|
|
243
|
-
|
|
244
|
-
this.noteLoaderAccess("response", key);
|
|
245
|
-
this.record("response", key, await serializeResponse(response));
|
|
246
|
-
return this.inner.putResponse(key, response, ttl, swr, tags);
|
|
170
|
+
return this.inner.putResponse?.(key, response, ttl, swr, tags);
|
|
247
171
|
}
|
|
248
172
|
|
|
249
173
|
async getItem(key: string): Promise<CacheItemResult | null> {
|
|
250
|
-
|
|
251
|
-
this.noteLoaderAccess("item", key);
|
|
252
|
-
const result = await this.inner.getItem(key);
|
|
253
|
-
if (result) {
|
|
254
|
-
const value: ShellSnapshotItemValue = {
|
|
255
|
-
value: result.value,
|
|
256
|
-
handles: result.handles,
|
|
257
|
-
tags: result.tags,
|
|
258
|
-
};
|
|
259
|
-
this.record("item", key, value);
|
|
260
|
-
}
|
|
261
|
-
return result;
|
|
174
|
+
return this.inner.getItem ? this.inner.getItem(key) : null;
|
|
262
175
|
}
|
|
263
176
|
|
|
264
177
|
async setItem(
|
|
@@ -266,15 +179,7 @@ export class RecordingShellStore<
|
|
|
266
179
|
value: string,
|
|
267
180
|
options?: CacheItemOptions,
|
|
268
181
|
): Promise<void> {
|
|
269
|
-
|
|
270
|
-
this.noteLoaderAccess("item", key);
|
|
271
|
-
const stored: ShellSnapshotItemValue = {
|
|
272
|
-
value,
|
|
273
|
-
handles: options?.handles,
|
|
274
|
-
tags: options?.tags,
|
|
275
|
-
};
|
|
276
|
-
this.record("item", key, stored);
|
|
277
|
-
return this.inner.setItem(key, value, options);
|
|
182
|
+
return this.inner.setItem?.(key, value, options);
|
|
278
183
|
}
|
|
279
184
|
|
|
280
185
|
async getShell(
|
|
@@ -299,7 +204,7 @@ export class RecordingShellStore<
|
|
|
299
204
|
}
|
|
300
205
|
}
|
|
301
206
|
|
|
302
|
-
/**
|
|
207
|
+
/** `store` when it is a RecordingShellStore (an instanceof check). */
|
|
303
208
|
export function getRecordingStore<TEnv>(
|
|
304
209
|
store: SegmentCacheStore<TEnv> | undefined,
|
|
305
210
|
): RecordingShellStore<TEnv> | undefined {
|
|
@@ -308,8 +213,8 @@ export function getRecordingStore<TEnv>(
|
|
|
308
213
|
|
|
309
214
|
/**
|
|
310
215
|
* True when `snapshot` carries the canonical doc segment record `docKey`
|
|
311
|
-
* names, with at least one segment: the record partial replay and a
|
|
312
|
-
*
|
|
216
|
+
* names, with at least one segment: the record partial replay and a document
|
|
217
|
+
* HIT tail consume.
|
|
313
218
|
*/
|
|
314
219
|
export function hasDocRecord(
|
|
315
220
|
snapshot: readonly ShellSnapshotRecord[] | undefined,
|
|
@@ -333,42 +238,24 @@ export function hasDocRecord(
|
|
|
333
238
|
}
|
|
334
239
|
|
|
335
240
|
/**
|
|
336
|
-
*
|
|
337
|
-
* (docs/design/shell-entry-layout.md §2):
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* the handler layer from the doc record and never runs a handler, so the
|
|
343
|
-
* records only handler code read are dead weight.
|
|
344
|
-
*/
|
|
345
|
-
export type ShellSnapshotReaders = "segments" | "loaders";
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Split a capture's snapshot into what its readers consume and the rest: the
|
|
349
|
-
* doc record (`docKey`) always; with "loaders", the loader-family records and
|
|
350
|
-
* the item/response records a loader touched during the capture
|
|
351
|
-
* (RecordingShellStore.loaderKeys). Every other segment record goes: an
|
|
352
|
-
* explicit cache() tier's reads and writes are keyed where no HIT tail and no
|
|
353
|
-
* partial replay looks (both consult only the doc record). The doc record
|
|
354
|
-
* stays a copy inside the entry: a reference to a separately stored record
|
|
355
|
-
* could be evicted on its own, and the HIT would have nothing to replay.
|
|
241
|
+
* Split a capture's snapshot into what a HIT or a partial replay reads and
|
|
242
|
+
* the rest (docs/design/shell-entry-layout.md §2). Kept: the doc record
|
|
243
|
+
* (`docKey`), as a copy inside the entry (a separately stored record could be
|
|
244
|
+
* evicted on its own, and the HIT would have nothing to replay), and the
|
|
245
|
+
* loader-family pins unless the entry is navigation-only (partial replay of
|
|
246
|
+
* such an entry seeds the doc record alone). Every other record goes.
|
|
356
247
|
*/
|
|
357
248
|
export function pruneShellSnapshot(
|
|
358
249
|
snapshot: readonly ShellSnapshotRecord[],
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
docKey: string,
|
|
250
|
+
navigationOnly: boolean,
|
|
251
|
+
docKey: string | undefined,
|
|
362
252
|
): { kept: ShellSnapshotRecord[]; pruned: ShellSnapshotRecord[] } {
|
|
363
253
|
const kept: ShellSnapshotRecord[] = [];
|
|
364
254
|
const pruned: ShellSnapshotRecord[] = [];
|
|
365
255
|
for (const record of snapshot) {
|
|
366
256
|
const keep =
|
|
367
257
|
(record.family === "segment" && record.key === docKey) ||
|
|
368
|
-
(
|
|
369
|
-
(record.family === "loader" ||
|
|
370
|
-
(record.family !== "segment" &&
|
|
371
|
-
loaderKeys.has(recordKey(record.family, record.key)))));
|
|
258
|
+
(record.family === "loader" && !navigationOnly);
|
|
372
259
|
(keep ? kept : pruned).push(record);
|
|
373
260
|
}
|
|
374
261
|
return { kept, pruned };
|
|
@@ -419,7 +306,7 @@ export function estimateShellEntryBytes(parts: {
|
|
|
419
306
|
);
|
|
420
307
|
}
|
|
421
308
|
|
|
422
|
-
/** Snapshot records by family, e.g. `segment:1/
|
|
309
|
+
/** Snapshot records by family, e.g. `segment:1/loader:2` (no commas: it rides a Server-Timing desc). */
|
|
423
310
|
export function countSnapshotFamilies(
|
|
424
311
|
snapshot: readonly ShellSnapshotRecord[],
|
|
425
312
|
): string {
|
|
@@ -431,13 +318,13 @@ export function countSnapshotFamilies(
|
|
|
431
318
|
}
|
|
432
319
|
|
|
433
320
|
/**
|
|
434
|
-
* The store the
|
|
435
|
-
*
|
|
436
|
-
* recorded
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
321
|
+
* The store the capture's IMPLICIT doc-cache scope resolves: reads pass
|
|
322
|
+
* through the recording store to the real one, but segment WRITES are
|
|
323
|
+
* recorded into the snapshot only — see
|
|
324
|
+
* {@link RecordingShellStore.recordSegmentWrite} for why passthrough would
|
|
325
|
+
* break SWR recapture. A route with its OWN cache() scope keeps that scope's
|
|
326
|
+
* real-store reads and writes; recordShellCaptureDocRecord (cache-store.ts)
|
|
327
|
+
* writes its doc record through this store too.
|
|
441
328
|
*/
|
|
442
329
|
export class SnapshotOnlySegmentStore<
|
|
443
330
|
TEnv = unknown,
|
|
@@ -464,28 +351,14 @@ export class SnapshotOnlySegmentStore<
|
|
|
464
351
|
}
|
|
465
352
|
}
|
|
466
353
|
|
|
467
|
-
/**
|
|
468
|
-
* Materialize the loader-family seed from a shell snapshot for a HIT's tail
|
|
469
|
-
* render: Flight-deserialize each recorded (promise-elided) bake-lane
|
|
470
|
-
* container into a segment-key -> container Map, which serveShellHit assigns
|
|
471
|
-
* to the tail context's `_shellLoaderSeed` for the resolveLoaderData overlay.
|
|
472
|
-
* Lives here so every snapshot family is decoded in this module (the
|
|
473
|
-
* item/segment/response families via {@link SeededShellStore}); the loader
|
|
474
|
-
* family is not a store read, so it seeds the context instead of a store.
|
|
475
|
-
*
|
|
476
|
-
* Deserializations run in parallel; a record that fails to decode is skipped
|
|
477
|
-
* (that loader drifts — the pre-snapshot behavior — instead of failing the
|
|
478
|
-
* HIT). Returns undefined when the snapshot carries no loader records, without
|
|
479
|
-
* touching the Flight codec (kept lazy for cold paths and non-RSC configs).
|
|
480
|
-
*/
|
|
354
|
+
/** One decoded loader-family pin (buildShellLoaderSeed). */
|
|
481
355
|
export interface ShellLoaderSeedEntry {
|
|
482
356
|
/** The Flight-deserialized elided container (recorded paths + markers). */
|
|
483
357
|
container: unknown;
|
|
484
358
|
/**
|
|
485
|
-
* True when the record carries hole markers
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
* from the pin (loader-cache.ts pin-first path).
|
|
359
|
+
* True when the record carries hole markers: the HIT overlay must gate on
|
|
360
|
+
* the fresh run. False = fully pinned; the payload promise resolves
|
|
361
|
+
* immediately from the pin (loader-cache.ts pin-first path).
|
|
489
362
|
*/
|
|
490
363
|
holes: boolean;
|
|
491
364
|
/**
|
|
@@ -496,6 +369,20 @@ export interface ShellLoaderSeedEntry {
|
|
|
496
369
|
runs: boolean;
|
|
497
370
|
}
|
|
498
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Materialize the loader-family seed from a shell snapshot for a HIT's tail
|
|
374
|
+
* render: Flight-deserialize each recorded (promise-elided) bake-lane
|
|
375
|
+
* container into a segment-key -> container Map, which serveShellHit assigns
|
|
376
|
+
* to the tail context's `_shellLoaderSeed` for the resolveLoaderData overlay.
|
|
377
|
+
* Lives here so every snapshot family is decoded in this module (the segment
|
|
378
|
+
* family via {@link SeededShellStore}); the loader family is not a store
|
|
379
|
+
* read, so it seeds the context instead of a store.
|
|
380
|
+
*
|
|
381
|
+
* Deserializations run in parallel; a record that fails to decode is skipped
|
|
382
|
+
* (that loader drifts — the pre-snapshot behavior — instead of failing the
|
|
383
|
+
* HIT). Returns undefined when the snapshot carries no loader records, without
|
|
384
|
+
* touching the Flight codec (kept lazy for cold paths and non-RSC configs).
|
|
385
|
+
*/
|
|
499
386
|
export async function buildShellLoaderSeed(
|
|
500
387
|
snapshot: ShellSnapshotRecord[],
|
|
501
388
|
): Promise<Map<string, ShellLoaderSeedEntry> | undefined> {
|
|
@@ -515,10 +402,9 @@ export async function buildShellLoaderSeed(
|
|
|
515
402
|
rec.key,
|
|
516
403
|
{
|
|
517
404
|
container: await deserializeResult(stored.value),
|
|
518
|
-
// A record
|
|
519
|
-
// reads as hole-carrying
|
|
520
|
-
//
|
|
521
|
-
// the loader-owned pushes, so the body supplies them).
|
|
405
|
+
// A record stored before the bits existed (v0.17) lacks the
|
|
406
|
+
// loader-owned pushes: it reads as hole-carrying and as runs,
|
|
407
|
+
// so the loader body supplies them.
|
|
522
408
|
holes: stored.holes !== 0,
|
|
523
409
|
runs: stored.runs !== 0,
|
|
524
410
|
},
|
|
@@ -537,50 +423,29 @@ export async function buildShellLoaderSeed(
|
|
|
537
423
|
}
|
|
538
424
|
|
|
539
425
|
/**
|
|
540
|
-
*
|
|
541
|
-
* the snapshot
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* partial navigation cannot freeze captured data or write a partial result into
|
|
550
|
-
* the canonical document namespace.
|
|
426
|
+
* The implicit doc scope's store on a HIT tail and on a partial replay: it
|
|
427
|
+
* serves the snapshot's segment records, the doc record among them, and
|
|
428
|
+
* fully isolates the segment family. Misses do not fall through, and writes
|
|
429
|
+
* or deletes stay local to the overlay, so a partial navigation cannot write
|
|
430
|
+
* a partial result into the canonical document namespace. It carries nothing
|
|
431
|
+
* else: every other read on a HIT (a hole, a bake-lane loader body that runs
|
|
432
|
+
* there) resolves the request's own store. Loader-family records are not
|
|
433
|
+
* store reads: serveShellHit seeds them onto the tail context
|
|
434
|
+
* (_shellLoaderSeed) for the resolveLoaderData overlay instead.
|
|
551
435
|
*/
|
|
552
436
|
export class SeededShellStore<
|
|
553
437
|
TEnv = unknown,
|
|
554
438
|
> implements SegmentCacheStore<TEnv> {
|
|
555
|
-
private readonly items: Map<string, ShellSnapshotItemValue> | undefined;
|
|
556
439
|
private readonly segments = new Map<string, CachedEntryData>();
|
|
557
|
-
private readonly responses:
|
|
558
|
-
| Map<string, ShellSnapshotResponseValue>
|
|
559
|
-
| undefined;
|
|
560
|
-
private readonly segmentsOnly: boolean;
|
|
561
440
|
|
|
562
441
|
constructor(
|
|
563
442
|
private readonly inner: SegmentCacheStore<TEnv>,
|
|
564
|
-
snapshot: ShellSnapshotRecord[],
|
|
565
|
-
options?: { segmentsOnly?: boolean },
|
|
443
|
+
snapshot: readonly ShellSnapshotRecord[],
|
|
566
444
|
) {
|
|
567
|
-
this.segmentsOnly = options?.segmentsOnly === true;
|
|
568
|
-
this.items = this.segmentsOnly ? undefined : new Map();
|
|
569
|
-
this.responses = this.segmentsOnly ? undefined : new Map();
|
|
570
445
|
for (const rec of snapshot) {
|
|
571
|
-
if (
|
|
572
|
-
if (rec.family === "segment") {
|
|
446
|
+
if (rec && typeof rec === "object" && rec.family === "segment") {
|
|
573
447
|
this.segments.set(rec.key, rec.value as CachedEntryData);
|
|
574
|
-
} else if (this.segmentsOnly) {
|
|
575
|
-
continue;
|
|
576
|
-
} else if (rec.family === "item") {
|
|
577
|
-
this.items?.set(rec.key, rec.value as ShellSnapshotItemValue);
|
|
578
|
-
} else if (rec.family === "response") {
|
|
579
|
-
this.responses?.set(rec.key, rec.value as ShellSnapshotResponseValue);
|
|
580
448
|
}
|
|
581
|
-
// "loader" family records are not store reads — serveShellHit seeds them
|
|
582
|
-
// onto the tail context (_shellLoaderSeed) for the resolveLoaderData
|
|
583
|
-
// overlay instead.
|
|
584
449
|
}
|
|
585
450
|
}
|
|
586
451
|
|
|
@@ -590,101 +455,18 @@ export class SeededShellStore<
|
|
|
590
455
|
get keyGenerator(): SegmentCacheStore<TEnv>["keyGenerator"] {
|
|
591
456
|
return this.inner.keyGenerator;
|
|
592
457
|
}
|
|
593
|
-
get supportsPassiveShellReads(): true | undefined {
|
|
594
|
-
return this.inner.supportsPassiveShellReads;
|
|
595
|
-
}
|
|
596
458
|
|
|
597
459
|
async get(key: string): Promise<CacheGetResult | null | CacheReadError> {
|
|
598
460
|
const seeded = this.segments.get(key);
|
|
599
|
-
|
|
600
|
-
if (this.segmentsOnly) return null;
|
|
601
|
-
return this.inner.get(key);
|
|
461
|
+
return seeded ? { data: seeded, shouldRevalidate: false } : null;
|
|
602
462
|
}
|
|
603
463
|
|
|
604
|
-
async set(
|
|
605
|
-
key
|
|
606
|
-
data: CachedEntryData,
|
|
607
|
-
ttl: number,
|
|
608
|
-
swr?: number,
|
|
609
|
-
): Promise<void> {
|
|
610
|
-
if (this.segmentsOnly) {
|
|
611
|
-
this.segments.set(key, data);
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
return this.inner.set(key, data, ttl, swr);
|
|
464
|
+
async set(key: string, data: CachedEntryData): Promise<void> {
|
|
465
|
+
this.segments.set(key, data);
|
|
615
466
|
}
|
|
616
467
|
|
|
617
468
|
async delete(key: string): Promise<boolean> {
|
|
618
|
-
|
|
619
|
-
return this.segments.delete(key);
|
|
620
|
-
}
|
|
621
|
-
return this.inner.delete(key);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
async clear(): Promise<void> {
|
|
625
|
-
return this.inner.clear?.();
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
async getResponse(
|
|
629
|
-
key: string,
|
|
630
|
-
): Promise<{ response: Response; shouldRevalidate: boolean } | null> {
|
|
631
|
-
const seeded = this.responses?.get(key);
|
|
632
|
-
if (seeded) {
|
|
633
|
-
return { response: deserializeResponse(seeded), shouldRevalidate: false };
|
|
634
|
-
}
|
|
635
|
-
return this.inner.getResponse ? this.inner.getResponse(key) : null;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
async putResponse(
|
|
639
|
-
key: string,
|
|
640
|
-
response: Response,
|
|
641
|
-
ttl: number,
|
|
642
|
-
swr?: number,
|
|
643
|
-
tags?: string[],
|
|
644
|
-
): Promise<void> {
|
|
645
|
-
return this.inner.putResponse?.(key, response, ttl, swr, tags);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
async getItem(key: string): Promise<CacheItemResult | null> {
|
|
649
|
-
const seeded = this.items?.get(key);
|
|
650
|
-
if (seeded) {
|
|
651
|
-
return {
|
|
652
|
-
value: seeded.value,
|
|
653
|
-
handles: seeded.handles,
|
|
654
|
-
tags: seeded.tags,
|
|
655
|
-
shouldRevalidate: false,
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
return this.inner.getItem ? this.inner.getItem(key) : null;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
async setItem(
|
|
662
|
-
key: string,
|
|
663
|
-
value: string,
|
|
664
|
-
options?: CacheItemOptions,
|
|
665
|
-
): Promise<void> {
|
|
666
|
-
return this.inner.setItem?.(key, value, options);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
async getShell(
|
|
670
|
-
key: string,
|
|
671
|
-
options?: { claimRevalidation?: boolean },
|
|
672
|
-
): Promise<{ entry: ShellCacheEntry; shouldRevalidate?: boolean } | null> {
|
|
673
|
-
return this.inner.getShell ? this.inner.getShell(key, options) : null;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
async putShell(
|
|
677
|
-
key: string,
|
|
678
|
-
entry: ShellCacheEntry,
|
|
679
|
-
ttlSeconds?: number,
|
|
680
|
-
swrSeconds?: number,
|
|
681
|
-
tags?: string[],
|
|
682
|
-
): Promise<"stored" | "invalidated" | "uncacheable" | void> {
|
|
683
|
-
return this.inner.putShell?.(key, entry, ttlSeconds, swrSeconds, tags);
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
async invalidateTags(tags: string[]): Promise<void> {
|
|
687
|
-
return this.inner.invalidateTags?.(tags);
|
|
469
|
+
return this.segments.delete(key);
|
|
688
470
|
}
|
|
689
471
|
}
|
|
690
472
|
|