@rangojs/router 0.18.0 → 0.19.1
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 +37 -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 +48 -5
- 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 +126 -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 +962 -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 +67 -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 +54 -1
- package/src/cache/cache-key-utils.ts +56 -16
- package/src/cache/cache-policy.ts +9 -4
- package/src/cache/cache-runtime.ts +202 -144
- package/src/cache/cache-scope.ts +304 -112
- package/src/cache/cache-tag.ts +209 -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 +42 -5
- 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 +152 -26
- 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 +263 -124
- package/src/server/cookie-store.ts +153 -127
- package/src/server/handle-store.ts +245 -27
- package/src/server/request-context.ts +134 -87
- 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
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
* profile/DSL tags before storing.
|
|
11
11
|
*/
|
|
12
12
|
import { type RequestContext } from "../server/request-context.js";
|
|
13
|
-
import { type LoaderIdentityRead } from "../server/context.js";
|
|
13
|
+
import { type LoaderIdentityRead, type LoaderRunIdentity } from "../server/context.js";
|
|
14
|
+
import { type CacheExecScope } from "./cache-exec-scope.js";
|
|
15
|
+
import type { ExecutionStart } from "./tag-invalidation.js";
|
|
16
|
+
/**
|
|
17
|
+
* Call `fn` outside any "use cache" tag scope: detached work a cached body
|
|
18
|
+
* schedules (a stale entry's background refresh) records nothing onto the
|
|
19
|
+
* entry being filled.
|
|
20
|
+
*/
|
|
21
|
+
export declare function outsideCacheTagScope<T>(fn: () => T): T;
|
|
14
22
|
/**
|
|
15
23
|
* Arm the record tag owners for `ctx`: its match resolved a cache scope, so
|
|
16
24
|
* it can write a route cache() record (match-api.ts). A capture's or
|
|
@@ -146,19 +154,54 @@ export declare function markIdentityRead(set: Set<string>, read: LoaderIdentityR
|
|
|
146
154
|
* recorded, nearest first (breadth-first, so the execution's own read wins).
|
|
147
155
|
*/
|
|
148
156
|
export declare function recordedIdentityRead(root: Set<string>): LoaderIdentityRead | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* `value` is the promise of the execution `run` records, started by the
|
|
159
|
+
* current execution (if any), which reads it. Both loader runners call it
|
|
160
|
+
* (loader-resolution.ts createLoaderExecutor, request-context.ts
|
|
161
|
+
* createUseFunction).
|
|
162
|
+
*/
|
|
163
|
+
export declare function trackLoaderRun(value: object, run: LoaderRunIdentity): void;
|
|
164
|
+
/**
|
|
165
|
+
* A ctx.use(Loader) or getRequestContext().use(Loader) read that returns an
|
|
166
|
+
* already-started value (the request memo, a loader cache() binding's value).
|
|
167
|
+
* The current loader execution, if any, links it (it reads the value).
|
|
168
|
+
* Inside a "use cache" body the value is refused when its execution read
|
|
169
|
+
* request identity, as a body entered there would have been
|
|
170
|
+
* (guardIdentityRead). The check runs once the value settles, so a read the
|
|
171
|
+
* body makes after an await counts. Each enclosing execution also notes the
|
|
172
|
+
* value, and checks it again after encoding its result
|
|
173
|
+
* (assertLoaderReadsClean): a read that settles after the value (a nested
|
|
174
|
+
* promise in it) then fails the write instead.
|
|
175
|
+
*/
|
|
176
|
+
export declare function readStartedLoaderValue<T>(value: Promise<T>, loaderId: string): Promise<T>;
|
|
177
|
+
/** Throw when a loader value `scope` read carries an identity read. */
|
|
178
|
+
export declare function assertLoaderReadsClean(scope: CacheExecScope): void;
|
|
149
179
|
/** `root`'s tags plus those of every set it links to, transitively. */
|
|
150
180
|
export declare function flattenRecordedTags(root: Set<string>): Set<string>;
|
|
181
|
+
/** Record where the execution recording into `set` started. */
|
|
182
|
+
export declare function markTagSetStart(set: Set<string>, start: ExecutionStart): void;
|
|
183
|
+
/**
|
|
184
|
+
* The earliest start among `root` and every set it links to: a value built
|
|
185
|
+
* from another execution's value is as old as the oldest of them. A
|
|
186
|
+
* loader-cache write gates on it (loader-cache.ts), because the loader value
|
|
187
|
+
* it stores can be a run a reader started before the binding executed, and
|
|
188
|
+
* the values that run read can be older still.
|
|
189
|
+
*/
|
|
190
|
+
export declare function earliestRecordedStart(root: Set<string>): ExecutionStart | undefined;
|
|
151
191
|
/**
|
|
152
|
-
* Run a function within a cache tag scope. Any cacheTag() calls inside `fn
|
|
153
|
-
*
|
|
192
|
+
* Run a function within a cache tag scope. Any cacheTag() calls inside `fn`,
|
|
193
|
+
* and the tags a nested "use cache" call records (recordOwnedTags, #980),
|
|
194
|
+
* accumulate into the returned Set and every scope enclosing it
|
|
195
|
+
* (scopeParents).
|
|
154
196
|
*
|
|
155
197
|
* The returned Set is the LIVE reference - the caller must await `result`
|
|
156
198
|
* before reading `tags`, because an async cached function may call cacheTag()
|
|
157
|
-
* after an await boundary.
|
|
199
|
+
* after an await boundary. Pass `tagSet` to re-enter an execution's scope
|
|
200
|
+
* (its result's Flight encode, #980); it keeps the parent it opened under.
|
|
158
201
|
*
|
|
159
202
|
* @internal Used by cache-runtime.ts to wrap "use cache" execution.
|
|
160
203
|
*/
|
|
161
|
-
export declare function runWithCacheTagScope<T>(fn: () => T): {
|
|
204
|
+
export declare function runWithCacheTagScope<T>(fn: () => T, tagSet?: Set<string>): {
|
|
162
205
|
result: T;
|
|
163
206
|
tags: Set<string>;
|
|
164
207
|
};
|
|
@@ -3,32 +3,16 @@ declare global {
|
|
|
3
3
|
readonly default: Cache;
|
|
4
4
|
}
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
7
|
-
* Cloudflare Edge Cache Store
|
|
8
|
-
*
|
|
9
|
-
* Production cache store using Cloudflare's Cache API (L1) with optional
|
|
10
|
-
* KV persistence (L2).
|
|
11
|
-
*
|
|
12
|
-
* L1 (Cache API): Per-colo, fast, ephemeral. Handles SWR atomically.
|
|
13
|
-
* L2 (KV): Global, persistent, ~50ms reads. Auto-warms cold colos.
|
|
14
|
-
*
|
|
15
|
-
* Read flow: L1 hit → serve | L1 miss → L2 hit → serve + promote to L1 | both miss → render
|
|
16
|
-
* Write flow: L1 write + L2 write (both via waitUntil)
|
|
17
|
-
*
|
|
18
|
-
* Features:
|
|
19
|
-
* - Extended TTL for SWR window (max-age = ttl + swr)
|
|
20
|
-
* - Staleness via x-edge-cache-stale-at header
|
|
21
|
-
* - Atomic REVALIDATING status for thundering herd prevention (L1 only)
|
|
22
|
-
* - Non-blocking writes via waitUntil
|
|
23
|
-
* - KV L2 for cross-colo cache persistence
|
|
24
|
-
*/
|
|
25
6
|
import type { SegmentCacheStore, CachedEntryData, CacheDefaults, CacheGetResult, CacheItemResult, CacheItemOptions, ShellCacheEntry, ShellDocumentRead, ShellDocumentReadOptions, CacheReadError } from "../types.js";
|
|
26
7
|
import { type RequestContext } from "../../server/request-context.js";
|
|
27
8
|
import { CACHE_STALE_AT_HEADER, CACHE_STATUS_HEADER, CACHE_TAGS_HEADER, CACHE_TAGGED_AT_HEADER, TAG_MARKER_PREFIX, CACHE_REVALIDATING_AT_HEADER, MAX_REVALIDATION_INTERVAL, EDGE_LOOKUP_TIMEOUT_MS, EDGE_READ_TIMEOUT_MS, KV_READ_TIMEOUT_MS } from "./cf-cache-constants.js";
|
|
28
9
|
export { CACHE_STALE_AT_HEADER, CACHE_STATUS_HEADER, CACHE_TAGS_HEADER, CACHE_TAGGED_AT_HEADER, TAG_MARKER_PREFIX, CACHE_REVALIDATING_AT_HEADER, MAX_REVALIDATION_INTERVAL, EDGE_LOOKUP_TIMEOUT_MS, EDGE_READ_TIMEOUT_MS, KV_READ_TIMEOUT_MS, };
|
|
29
10
|
import type { KVNamespace, CFCacheReadDebugEvent, CFCacheDebug, CFCacheStoreOptions } from "./cf-cache-types.js";
|
|
30
11
|
export type { KVNamespace, CFCacheReadDebugEvent, CFCacheDebug, CFCacheStoreOptions, };
|
|
31
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* @internal Reset the per-isolate shell and marker memos and the once-per-
|
|
14
|
+
* isolate warnings (tests).
|
|
15
|
+
*/
|
|
32
16
|
export declare function resetCFShellMemoForTests(): void;
|
|
33
17
|
export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
34
18
|
readonly supportsPassiveShellReads: true;
|
|
@@ -290,7 +274,7 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
290
274
|
/**
|
|
291
275
|
* Generation gate for shell writes and the capture scheduler
|
|
292
276
|
* (isTagsInvalidatedSince). With KV it is the durable marker cascade.
|
|
293
|
-
* Without KV there are no markers: in purge mode the per-request
|
|
277
|
+
* Without KV there are no markers: in purge mode the per-request mask is
|
|
294
278
|
* the only signal — a capture racing THIS request's updateTag() is still
|
|
295
279
|
* rejected (read-your-own-writes), while cross-request races are bounded
|
|
296
280
|
* by ttl+swr exactly like the data families' purge-mode writes. Without
|
|
@@ -553,16 +537,16 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
553
537
|
* configured), invalidateTags() evicts L1 entries via a Cloudflare
|
|
554
538
|
* purge-by-tag call, so a hit that SURVIVED is trusted without a per-read
|
|
555
539
|
* marker lookup — that skipped lookup is the entire point of purge mode.
|
|
556
|
-
* Only the
|
|
557
|
-
* request that ran updateTag() still
|
|
558
|
-
* propagation window (read-your-own-writes).
|
|
540
|
+
* Only the request's mask and its memo are consulted (synchronous, no KV
|
|
541
|
+
* read) so a request that ran updateTag() still misses its own entries
|
|
542
|
+
* during the purge propagation window (read-your-own-writes).
|
|
559
543
|
*
|
|
560
544
|
* The trust is conditional on the entry actually CARRYING this store's
|
|
561
545
|
* entry Cache-Tag tokens (`headers`): an entry a purge cannot reach — one
|
|
562
546
|
* written before the tokens existed, or whose tag set overflowed the
|
|
563
547
|
* Cache-Tag header limit — keeps the full marker check, or purge mode
|
|
564
548
|
* would serve it stale until TTL with no eviction path. KV-less there are
|
|
565
|
-
* no markers, so it gets the per-request
|
|
549
|
+
* no markers, so it gets the per-request mask check like any hit (#973).
|
|
566
550
|
*
|
|
567
551
|
* Without tagPurge this is the full marker cascade. KV-tier reads and
|
|
568
552
|
* shells always use isGloballyInvalidated directly: purge cannot reach KV,
|
|
@@ -575,9 +559,8 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
575
559
|
/**
|
|
576
560
|
* Read a tag's latest invalidation timestamp (or null if never invalidated)
|
|
577
561
|
* through the cascade: per-request memo -> per-colo L1 cache (only when
|
|
578
|
-
* tagCacheTtl > 0) -> KV (the global truth).
|
|
579
|
-
*
|
|
580
|
-
* and every KV/L1 result is written back into the memo. A Cache API miss
|
|
562
|
+
* tagCacheTtl > 0) -> KV (the global truth). Every KV/L1 result is written
|
|
563
|
+
* back into the memo, so the request reads one value per tag. A Cache API miss
|
|
581
564
|
* always falls through to KV; absence is represented by a cached sentinel,
|
|
582
565
|
* never by a miss.
|
|
583
566
|
*
|
|
@@ -588,9 +571,9 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
588
571
|
*/
|
|
589
572
|
private readTagMarker;
|
|
590
573
|
/**
|
|
591
|
-
* A PPR shell read's marker for `tag`: this request's own
|
|
592
|
-
* one
|
|
593
|
-
*
|
|
574
|
+
* A PPR shell read's marker for `tag`: this request's own store read if it
|
|
575
|
+
* has one, else through the per-isolate marker memo (isolate-tag-memo.ts,
|
|
576
|
+
* stale-while-revalidate
|
|
594
577
|
* under `markerFreshMs` / `markerMaxStaleMs`; a request carrying the
|
|
595
578
|
* fresh-reads cookie reads L1/KV). The value is kept in the request's
|
|
596
579
|
* shell-read record, never in the per-request memo the data families read,
|
|
@@ -679,14 +662,45 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
679
662
|
*/
|
|
680
663
|
private putTagMarkerL1;
|
|
681
664
|
/**
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
665
|
+
* SegmentCacheStore.isTagsInvalidatedSince: the SAME KV markers used by
|
|
666
|
+
* runtime envelopes also evict immutable build shells, and gate the writes
|
|
667
|
+
* of cache executions that started before an invalidation (#977,
|
|
668
|
+
* tag-invalidation.ts predatesInvalidation). Marker >= since. A marker read
|
|
669
|
+
* that fails or times out answers false (fail open), or true for the write
|
|
670
|
+
* gate (`failClosed`). With KV each marker is read past the per-request
|
|
671
|
+
* memo (isInvalidatedSincePastMemo); KV-less it degrades to the per-request
|
|
672
|
+
* mask in purge mode and to false otherwise — see
|
|
687
673
|
* isShellGenerationInvalidated.
|
|
688
674
|
*/
|
|
689
|
-
isTagsInvalidatedSince(tags: string[], sinceMs: number
|
|
675
|
+
isTagsInvalidatedSince(tags: string[], sinceMs: number, options?: {
|
|
676
|
+
failClosed?: boolean;
|
|
677
|
+
}): Promise<boolean>;
|
|
678
|
+
/**
|
|
679
|
+
* isTagsInvalidatedSince with KV, never answered from a marker value this
|
|
680
|
+
* request read before the asking gate. A write gate asks after an
|
|
681
|
+
* execution that can run for seconds, and the per-request memo can hold
|
|
682
|
+
* the marker the request read before it (a stale hit reads its entry's
|
|
683
|
+
* markers, then its refresh runs): answered from it, another isolate's
|
|
684
|
+
* invalidation in between let the refresh write.
|
|
685
|
+
*
|
|
686
|
+
* - This request's own invalidations answer from its mask, checked again
|
|
687
|
+
* once the reads are back: a read in flight when the request invalidated
|
|
688
|
+
* one of the tags resolved to the marker before it.
|
|
689
|
+
* - Each tag is read through gateMarkerRead (request-tag-mask.ts): gates
|
|
690
|
+
* asking while a read is in flight share it; a settled read is not
|
|
691
|
+
* reused.
|
|
692
|
+
* - The read returns its own value from L1 (tagCacheTtl) or KV, not one an
|
|
693
|
+
* older read of the tag memoized while it was in flight, and fills the
|
|
694
|
+
* memo only when it holds nothing, so a build shell's check still serves
|
|
695
|
+
* the request's later reads. A timed-out read fills nothing.
|
|
696
|
+
* - It publishes to L1 unless the request masked the tag
|
|
697
|
+
* (fetchTagMarker), and never without a request context (a detached
|
|
698
|
+
* waitUntil task), where a mask cannot be told apart.
|
|
699
|
+
* - A read that fails or times out answers `failClosed`: the write gate
|
|
700
|
+
* counts it as an invalidation, other callers as none.
|
|
701
|
+
* @internal
|
|
702
|
+
*/
|
|
703
|
+
private isInvalidatedSincePastMemo;
|
|
690
704
|
/**
|
|
691
705
|
* Invalidate every entry tagged with any of `tags`. Receives the whole batch
|
|
692
706
|
* from one updateTag()/revalidateTag() call so the eager-purge hook fires
|
|
@@ -716,14 +730,11 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
716
730
|
invalidateTags(tags: string[]): Promise<void>;
|
|
717
731
|
/**
|
|
718
732
|
* The request-local half of invalidateTags(), run before its first await
|
|
719
|
-
* (#973):
|
|
733
|
+
* (#973): the request masks the tags (request-tag-mask.ts), so every later
|
|
720
734
|
* read in the request (data families, purge-mode L1 hits, shell reads)
|
|
721
|
-
* treats
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
* pays extra misses, never a stale read, and later requests read the
|
|
725
|
-
* durable state. Skipped where no read consults the memo (neither KV nor
|
|
726
|
-
* tagPurge).
|
|
735
|
+
* treats them as invalidated at `invalidatedAt` without waiting for the KV
|
|
736
|
+
* put or the purge that revalidateTag() leaves to waitUntil. Skipped where
|
|
737
|
+
* no read consults the mask (neither KV nor tagPurge).
|
|
727
738
|
*/
|
|
728
739
|
private maskTagsForRequest;
|
|
729
740
|
/** invalidateTags' marker writes, tag purge, and hooks. */
|
|
@@ -24,7 +24,7 @@ export interface ShellFrameHead {
|
|
|
24
24
|
/** ShellCacheEntry.reactVersion */
|
|
25
25
|
rv: string;
|
|
26
26
|
/** ShellCacheEntry.buildVersion */
|
|
27
|
-
bv
|
|
27
|
+
bv: string;
|
|
28
28
|
/** Capture-generation start time (ms epoch), used by tag marker checks. */
|
|
29
29
|
c: number;
|
|
30
30
|
/** When the entry becomes stale (ms epoch). */
|
|
@@ -12,22 +12,7 @@ export declare const TAG_MARKER_CACHE_PREFIX = "__tagmarker__/";
|
|
|
12
12
|
* never "no marker" - absence is only ever represented by this cached sentinel.
|
|
13
13
|
*/
|
|
14
14
|
export declare const TAG_MARKER_ABSENT = "none";
|
|
15
|
-
/**
|
|
16
|
-
* Request context -> store instance -> T, both levels weakly held. Also
|
|
17
|
-
* VercelCacheStore's request tag mask (#973).
|
|
18
|
-
*/
|
|
19
|
-
export type PerRequestStoreMap<T> = WeakMap<object, WeakMap<object, T>>;
|
|
20
|
-
/** The value for (ctx, store), created on first use. */
|
|
21
|
-
export declare function perRequestStoreValue<T>(map: PerRequestStoreMap<T>, ctx: object, store: object, create: () => T): T;
|
|
22
15
|
export declare function getTagMarkerMemo(ctx: object, store: object): Map<string, number | null>;
|
|
23
|
-
/**
|
|
24
|
-
* Mask `tags` at `at` for the rest of the request: in the request's mask and
|
|
25
|
-
* in every memo the request's contexts hold for `store` (a memo created later
|
|
26
|
-
* starts from the mask).
|
|
27
|
-
*/
|
|
28
|
-
export declare function maskRequestTags(ctx: object, store: object, tags: readonly string[], at: number): void;
|
|
29
|
-
/** Whether this request masked `tag` through `store` (maskRequestTags). */
|
|
30
|
-
export declare function isRequestMasked(ctx: object, store: object, tag: string): boolean;
|
|
31
16
|
/**
|
|
32
17
|
* A request's PPR shell-read marker reads (issue #941), kept apart from the
|
|
33
18
|
* per-request memo above, HIT or MISS. A shell read may answer a marker from
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
* 4. If miss → run handler, cache if response has cache headers
|
|
14
14
|
*/
|
|
15
15
|
import type { MiddlewareFn, MiddlewareContext } from "../router/middleware.js";
|
|
16
|
+
import { type RequestContext } from "../server/request-context.js";
|
|
17
|
+
/**
|
|
18
|
+
* Whether this cache will store the response the current render produces, as
|
|
19
|
+
* far as the render can tell: the middleware runs it (a MISS or a stale
|
|
20
|
+
* refresh) and the response stub already opts in. payloadInitialTheme
|
|
21
|
+
* (rsc/full-payload.ts) then renders the no-cookie default theme (#978). A
|
|
22
|
+
* Cache-Control written after next() is not on the stub yet; for that render
|
|
23
|
+
* shouldCacheResponse refuses a payload marked `_payloadVisitorTheme`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function documentCacheStoresRender(reqCtx: Pick<RequestContext, "_documentCacheRender" | "res">): boolean;
|
|
16
26
|
export interface DocumentCacheOptions<TEnv = any> {
|
|
17
27
|
/**
|
|
18
28
|
* Skip caching for specific paths (e.g., API routes)
|
|
@@ -44,6 +44,28 @@ export declare function decodeHandleValue<T>(encoded: string): Promise<T | null>
|
|
|
44
44
|
export declare function captureHandles(segments: ResolvedSegment[], handleStore: HandleStore): Record<string, SegmentHandleData>;
|
|
45
45
|
/** The owners of captureHandles' values; undefined when none is owned. */
|
|
46
46
|
export declare function captureHandleOwners(segments: ResolvedSegment[], handleStore: HandleStore): HandleOwners | undefined;
|
|
47
|
+
/** How restoreHandles delivers a record's loader-owned values. */
|
|
48
|
+
export interface OwnedPushDelivery {
|
|
49
|
+
/**
|
|
50
|
+
* Asked once per owner delivered through pushReplayed
|
|
51
|
+
* (setupLoaderAccess _claimLoaderPushes); an owner it refuses is skipped.
|
|
52
|
+
*/
|
|
53
|
+
claim?: (loaderId: string) => boolean;
|
|
54
|
+
/**
|
|
55
|
+
* A PPR shell's record (capture, document HIT tail, navigation replay): the
|
|
56
|
+
* loaders the route runs on the live lane (liveLaneLoaderIds), marked on
|
|
57
|
+
* the store (HandleStore.markLiveLane). A hole's values are replayed
|
|
58
|
+
* unclaimed, so its own cache() HIT redelivers its entry's pushes in their
|
|
59
|
+
* place (HandleStore.redeliverReplays), and its run ending without a push
|
|
60
|
+
* drops them (HandleStore.settleLoaderRun).
|
|
61
|
+
*/
|
|
62
|
+
liveLane?: ReadonlySet<string>;
|
|
63
|
+
/**
|
|
64
|
+
* A document HIT tail: every owner outside `liveLane` goes through
|
|
65
|
+
* pushRestored and stands, unclaimed.
|
|
66
|
+
*/
|
|
67
|
+
restore?: boolean;
|
|
68
|
+
}
|
|
47
69
|
/**
|
|
48
70
|
* Restore handle data from a cached snapshot into the handle store.
|
|
49
71
|
* Used when serving cached segments to replay their handle data: a route
|
|
@@ -51,15 +73,25 @@ export declare function captureHandleOwners(segments: ResolvedSegment[], handleS
|
|
|
51
73
|
*
|
|
52
74
|
* A segment with `owners` is replaced with empty arrays and re-pushed in
|
|
53
75
|
* recorded order, an owned value through pushReplayed: if the owning loader
|
|
54
|
-
* runs
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* (
|
|
58
|
-
* loader
|
|
59
|
-
*
|
|
60
|
-
*
|
|
76
|
+
* runs (a client navigation replaying a ppr route's cache() record runs its
|
|
77
|
+
* `ssr: false` loaders), its live pushes replace the recorded ones in place
|
|
78
|
+
* instead of appending a second copy. `owned.claim` is asked once per
|
|
79
|
+
* owner, so the loader's own cache() HIT does not replay its pushes a second
|
|
80
|
+
* time (loader-cache.ts replayLoaderHandles). A record without owners
|
|
81
|
+
* restores as a plain replay.
|
|
82
|
+
*
|
|
83
|
+
* `owned.restore`: a document HIT tail restoring the shell's doc record
|
|
84
|
+
* (withCacheLookup). A bake-lane owner's values are the prelude's, so they go
|
|
85
|
+
* through pushRestored and stand: a run of that loader on the HIT (a
|
|
86
|
+
* promise-carrying `ssr: false` loader, one whose record asks for a run)
|
|
87
|
+
* reads the store, and its settled pushes are dropped, not swapped in.
|
|
88
|
+
* Nothing is claimed, so the loader's own cache() HIT still replays the
|
|
89
|
+
* pushes the record could not keep (the thenable ones pushRestored lets
|
|
90
|
+
* through). A loader the route also runs on the live lane is a hole: its
|
|
91
|
+
* values keep pushReplayed, unclaimed, and its live run replaces them
|
|
92
|
+
* (#936), even inside a restored loader's body (`owned.liveLane`).
|
|
61
93
|
*/
|
|
62
|
-
export declare function restoreHandles(handles: Record<string, SegmentHandleData>, handleStore: HandleStore, owners?: HandleOwners,
|
|
94
|
+
export declare function restoreHandles(handles: Record<string, SegmentHandleData>, handleStore: HandleStore, owners?: HandleOwners, owned?: OwnedPushDelivery): void;
|
|
63
95
|
/**
|
|
64
96
|
* Append recorded handle pushes to the store, in recorded order, via push()
|
|
65
97
|
* so active captures and loader-scope tagging see them like live pushes. For
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a cache execution ("use cache", a loader's own cache(), a route
|
|
3
|
+
* cache() render, a request's document) started: its position in this
|
|
4
|
+
* isolate's order, and the store clock for invalidations this isolate did
|
|
5
|
+
* not see.
|
|
6
|
+
*/
|
|
7
|
+
export interface ExecutionStart {
|
|
8
|
+
readonly seq: number;
|
|
9
|
+
readonly at: number;
|
|
10
|
+
}
|
|
11
|
+
/** Record an execution's start, before it reads its data. */
|
|
12
|
+
export declare function executionStart(): ExecutionStart;
|
|
13
|
+
/**
|
|
14
|
+
* Whether this isolate invalidated any of `tags` after `since` (the `seq` of
|
|
15
|
+
* an ExecutionStart), in any request: the execution's value may predate the
|
|
16
|
+
* invalidation, so it is neither joined nor written (#973, #977).
|
|
17
|
+
*/
|
|
18
|
+
export declare function invalidatedSince(tags: readonly string[] | undefined, since: number): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Record an invalidation of `tags` in this isolate's order
|
|
21
|
+
* (updateTag()/revalidateTag(), before any store sees it).
|
|
22
|
+
*/
|
|
23
|
+
export declare function markInvalidated(tags: readonly string[]): void;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-request tag mask behind read-your-own-writes (#973).
|
|
3
|
+
*
|
|
4
|
+
* updateTag() and revalidateTag() call a store's invalidateTags() inside the
|
|
5
|
+
* request, and a built-in store masks the tags here before its first await:
|
|
6
|
+
* every later read in that request, through any context derived from it,
|
|
7
|
+
* treats an entry carrying one of the tags, written at or before the mask, as
|
|
8
|
+
* invalidated, without waiting for the durable write (the KV marker put, the
|
|
9
|
+
* tag purge, expireTag()) that revalidateTag() leaves to waitUntil. The mask
|
|
10
|
+
* only ever turns this request's hits into misses: if the durable write then
|
|
11
|
+
* fails, the request paid extra misses, never a stale read, and other
|
|
12
|
+
* requests read the durable state. CFCacheStore and VercelCacheStore share it.
|
|
13
|
+
*/
|
|
14
|
+
/** Request context -> store instance -> T, both levels weakly held. */
|
|
15
|
+
export type PerRequestStoreMap<T> = WeakMap<object, WeakMap<object, T>>;
|
|
16
|
+
/** The value for (ctx, store), created on first use. */
|
|
17
|
+
export declare function perRequestStoreValue<T>(map: PerRequestStoreMap<T>, ctx: object, store: object, create: () => T): T;
|
|
18
|
+
/**
|
|
19
|
+
* The request a context belongs to: RequestContext._requestRoot, which
|
|
20
|
+
* createRequestContext defines and a derived context (Object.create: a shell
|
|
21
|
+
* capture, a PPR HIT tail) inherits. A bare test context is its own root.
|
|
22
|
+
*/
|
|
23
|
+
export declare function requestRoot<T extends object>(ctx: T & {
|
|
24
|
+
_requestRoot?: T;
|
|
25
|
+
}): T;
|
|
26
|
+
/** Mask `tags` at `at` through `store` for the rest of `ctx`'s request. */
|
|
27
|
+
export declare function maskRequestTags(ctx: object, store: object, tags: readonly string[], at: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* Whether `ctx`'s request masked one of `tags` through `store` at or after
|
|
30
|
+
* `taggedAt`. `>=`, as the stores' marker checks: an entry written in the
|
|
31
|
+
* invalidation's millisecond may hold a value computed before it, so it
|
|
32
|
+
* misses (a false miss, never a stale read).
|
|
33
|
+
*/
|
|
34
|
+
export declare function maskedForRequest(ctx: object | undefined, store: object, tags: readonly string[] | undefined, taggedAt: number): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* A marker read for a write gate (isTagsInvalidatedSince, from
|
|
37
|
+
* tag-invalidation.ts predatesInvalidation), shared by the gates of a
|
|
38
|
+
* request that ask while it is in flight. A page's writes (its "use cache"
|
|
39
|
+
* misses, its route record, its document) finish together and often carry
|
|
40
|
+
* the same tags, and each read its own marker before: one KV or
|
|
41
|
+
* runtime-cache read per tag per write.
|
|
42
|
+
*
|
|
43
|
+
* A read answers only for invalidations before it was issued. So a gate
|
|
44
|
+
* shares one still in flight, issued at or after its execution started
|
|
45
|
+
* (`sinceMs` is the millisecond after that start), and the read is dropped
|
|
46
|
+
* once it settles: a gate asking later reads again, and a shared read
|
|
47
|
+
* leaves open at most one marker round-trip. Reusing a settled read let a
|
|
48
|
+
* gate asking long after it miss another isolate's invalidation in
|
|
49
|
+
* between (a capture's putShell answered by a "use cache" write's read
|
|
50
|
+
* from the start of the capture), and kept a timed-out read's fail-open
|
|
51
|
+
* answer for the rest of the request. Without a request context `read()`
|
|
52
|
+
* runs unshared.
|
|
53
|
+
*/
|
|
54
|
+
export declare function gateMarkerRead<T>(ctx: object | undefined, store: object, tag: string, sinceMs: number, read: () => Promise<T>): Promise<T>;
|