@rangojs/router 0.22.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rango.js +10 -4
- package/dist/testing/vitest.js +31 -1
- package/dist/types/browser/defer.d.ts +48 -0
- package/dist/types/browser/document-revealed.d.ts +17 -0
- package/dist/types/browser/event-controller.d.ts +7 -1
- package/dist/types/browser/merge-segment-loaders.d.ts +5 -2
- package/dist/types/browser/navigation-transaction.d.ts +21 -7
- package/dist/types/browser/partial-update.d.ts +39 -8
- package/dist/types/browser/react/NavigationProvider.d.ts +19 -5
- package/dist/types/browser/react/context.d.ts +3 -2
- package/dist/types/browser/react/filter-segment-order.d.ts +7 -0
- package/dist/types/browser/response-adapter.d.ts +7 -0
- package/dist/types/browser/types.d.ts +24 -10
- package/dist/types/browser/validate-redirect-origin.d.ts +11 -0
- package/dist/types/build/generate-route-types.d.ts +1 -1
- package/dist/types/build/route-types/router-processing.d.ts +1 -1
- package/dist/types/build/route-types/scan-filter.d.ts +22 -2
- package/dist/types/cache/cf/cf-cache-store.d.ts +16 -1
- package/dist/types/cache/cf/cf-cache-types.d.ts +23 -2
- package/dist/types/cache/document-cache-policy.d.ts +24 -0
- package/dist/types/cache/document-cache.d.ts +2 -10
- package/dist/types/client-urls/client-urls.d.ts +1 -1
- package/dist/types/client-urls/hoisted-revalidate.d.ts +13 -0
- package/dist/types/client-urls/navigation.d.ts +0 -37
- package/dist/types/client-urls/revalidate-registry.d.ts +4 -0
- package/dist/types/client-urls/server-projection.d.ts +29 -1
- package/dist/types/client-urls/types.d.ts +34 -69
- package/dist/types/client.d.ts +0 -1
- package/dist/types/context-var.d.ts +12 -0
- package/dist/types/errors.d.ts +15 -0
- package/dist/types/handles/deferred-resolution.d.ts +2 -1
- package/dist/types/handles/pushed-by.d.ts +31 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.rsc.d.ts +2 -0
- package/dist/types/loader-store.d.ts +8 -0
- package/dist/types/prefetch-markers.d.ts +11 -0
- package/dist/types/response-utils.d.ts +7 -0
- package/dist/types/reverse.d.ts +8 -8
- package/dist/types/route-definition/helpers-types.d.ts +27 -0
- package/dist/types/route-definition/rewrite.d.ts +56 -0
- package/dist/types/route-map-builder.d.ts +7 -2
- package/dist/types/router/basename.d.ts +7 -0
- package/dist/types/router/handler-context.d.ts +1 -5
- package/dist/types/router/internal-params.d.ts +8 -0
- package/dist/types/router/is-action.d.ts +2 -1
- package/dist/types/router/middleware-types.d.ts +15 -0
- package/dist/types/router/revalidation.d.ts +1 -2
- package/dist/types/router/route-trie-builder.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -2
- package/dist/types/router/segment-resolution/mask-nested.d.ts +4 -2
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +264 -0
- package/dist/types/rsc/full-payload.d.ts +11 -0
- package/dist/types/rsc/handler.d.ts +33 -0
- package/dist/types/rsc/helpers.d.ts +8 -0
- package/dist/types/rsc/loader-fetch.d.ts +16 -0
- package/dist/types/rsc/rewrite-passes.d.ts +74 -0
- package/dist/types/rsc/ssr-setup.d.ts +3 -1
- package/dist/types/server/context.d.ts +21 -1
- package/dist/types/server/handle-store.d.ts +9 -1
- package/dist/types/server/request-context.d.ts +52 -2
- package/dist/types/server/rewrite-trail.d.ts +49 -0
- package/dist/types/server/slot-accessors.d.ts +29 -0
- package/dist/types/server.d.ts +1 -0
- package/dist/types/testing/flight.entry.d.ts +1 -1
- package/dist/types/testing/index.d.ts +4 -4
- package/dist/types/testing/internal/action-id.d.ts +10 -1
- package/dist/types/testing/internal/client-urls-projection.d.ts +16 -0
- package/dist/types/testing/internal/test-action.d.ts +8 -0
- package/dist/types/testing/render-route.d.ts +8 -0
- package/dist/types/testing/run-loader.d.ts +2 -1
- package/dist/types/testing/run-middleware.d.ts +20 -0
- package/dist/types/testing/run-revalidate.d.ts +74 -0
- package/dist/types/testing/run-transition-when.d.ts +2 -3
- package/dist/types/testing/serve-shell-request.d.ts +40 -1
- package/dist/types/testing/vitest.d.ts +11 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/boundaries.d.ts +9 -0
- package/dist/types/types/handler-context.d.ts +14 -0
- package/dist/types/types/loader-types.d.ts +30 -0
- package/dist/types/types/request-scope.d.ts +7 -0
- package/dist/types/types/segments.d.ts +21 -4
- package/dist/types/urls/path-helper-types.d.ts +25 -4
- package/dist/types/urls/type-extraction.d.ts +6 -2
- package/dist/types/vite/discovery/discover-routers.d.ts +9 -0
- package/dist/types/vite/discovery/state.d.ts +14 -4
- package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +54 -0
- package/dist/types/vite/plugins/hoist/literal.d.ts +83 -0
- package/dist/types/vite/plugins/hoist/scope.d.ts +40 -0
- package/dist/types/vite/plugins/hoist/source.d.ts +41 -0
- package/dist/types/vite/plugins/transition-when-hoist.d.ts +8 -11
- package/dist/types/vite/router-discovery.d.ts +10 -0
- package/dist/vite/index.js +974 -379
- package/package.json +1 -1
- package/skills/caching/SKILL.md +54 -5
- package/skills/catalog.json +3 -3
- package/skills/client-urls/SKILL.md +197 -24
- package/skills/cloudflare/SKILL.md +14 -9
- package/skills/hooks/SKILL.md +16 -3
- package/skills/hooks/data.md +3 -1
- package/skills/links/SKILL.md +24 -0
- package/skills/loader/SKILL.md +199 -2
- package/skills/middleware/SKILL.md +183 -2
- package/skills/migrate-nextjs/SKILL.md +2 -2
- package/skills/migrate-react-router/SKILL.md +10 -7
- package/skills/migrate-react-router/data-and-actions.md +1 -1
- package/skills/ppr/SKILL.md +22 -0
- package/skills/prerender/SKILL.md +22 -8
- package/skills/rango/SKILL.md +13 -7
- package/skills/route/SKILL.md +139 -0
- package/skills/server-actions/SKILL.md +27 -0
- package/skills/testing/SKILL.md +3 -2
- package/skills/testing/client-components.md +2 -1
- package/skills/testing/middleware.md +31 -10
- package/skills/testing/predicates.md +67 -32
- package/skills/testing/response-routes.md +1 -0
- package/skills/testing/serve-shell-request.md +107 -19
- package/skills/testing/setup.md +2 -2
- package/skills/typesafety/route-types.md +2 -2
- package/skills/use-cache/SKILL.md +4 -2
- package/skills/view-transitions/SKILL.md +26 -0
- package/src/__augment-tests__/augmented.check.ts +20 -0
- package/src/browser/defer.ts +82 -0
- package/src/browser/document-revealed.ts +52 -0
- package/src/browser/event-controller.ts +46 -32
- package/src/browser/merge-segment-loaders.ts +31 -18
- package/src/browser/navigation-bridge.ts +82 -16
- package/src/browser/navigation-client.ts +48 -36
- package/src/browser/navigation-store.ts +13 -0
- package/src/browser/navigation-transaction.ts +25 -8
- package/src/browser/partial-update.ts +554 -146
- package/src/browser/prefetch/fetch.ts +2 -1
- package/src/browser/react/Link.tsx +7 -9
- package/src/browser/react/NavigationProvider.tsx +88 -49
- package/src/browser/react/context.ts +3 -2
- package/src/browser/react/filter-segment-order.ts +13 -2
- package/src/browser/react/use-router.ts +2 -4
- package/src/browser/response-adapter.ts +20 -0
- package/src/browser/rsc-router.tsx +17 -45
- package/src/browser/server-action-bridge.ts +25 -63
- package/src/browser/types.ts +24 -10
- package/src/browser/validate-redirect-origin.ts +16 -0
- package/src/build/generate-route-types.ts +1 -0
- package/src/build/route-types/router-processing.ts +3 -6
- package/src/build/route-types/scan-filter.ts +45 -11
- package/src/cache/cf/cf-cache-store.ts +59 -21
- package/src/cache/cf/cf-cache-types.ts +24 -2
- package/src/cache/document-cache-policy.ts +131 -0
- package/src/cache/document-cache.ts +21 -107
- package/src/client-urls/client-urls.ts +22 -6
- package/src/client-urls/hoisted-revalidate.ts +25 -0
- package/src/client-urls/navigation.ts +0 -96
- package/src/client-urls/revalidate-registry.ts +30 -0
- package/src/client-urls/server-projection.ts +151 -65
- package/src/client-urls/types.ts +39 -71
- package/src/client.tsx +9 -5
- package/src/context-var.ts +32 -2
- package/src/errors.ts +34 -0
- package/src/handles/deferred-resolution.ts +28 -5
- package/src/handles/pushed-by.ts +148 -0
- package/src/index.rsc.ts +8 -0
- package/src/index.ts +7 -0
- package/src/loader-store.ts +18 -7
- package/src/prefetch-markers.ts +13 -0
- package/src/response-utils.ts +19 -0
- package/src/reverse.ts +17 -14
- package/src/route-content-wrapper.tsx +18 -4
- package/src/route-definition/dsl-helpers.ts +27 -4
- package/src/route-definition/helpers-types.ts +27 -1
- package/src/route-definition/redirect.ts +2 -15
- package/src/route-definition/rewrite.ts +146 -0
- package/src/route-map-builder.ts +14 -11
- package/src/router/basename.ts +20 -0
- package/src/router/handler-context.ts +3 -13
- package/src/router/intercept-resolution.ts +35 -16
- package/src/router/internal-params.ts +16 -0
- package/src/router/is-action.ts +2 -1
- package/src/router/loader-resolution.ts +85 -4
- package/src/router/match-api.ts +36 -1
- package/src/router/match-middleware/background-revalidation.ts +16 -4
- package/src/router/match-middleware/cache-lookup.ts +35 -7
- package/src/router/match-middleware/cache-store.ts +15 -1
- package/src/router/match-middleware/intercept-resolution.ts +4 -2
- package/src/router/match-result.ts +14 -2
- package/src/router/middleware-types.ts +16 -0
- package/src/router/middleware.ts +127 -49
- package/src/router/navigation-snapshot.ts +2 -1
- package/src/router/revalidation.ts +1 -1
- package/src/router/route-trie-builder.ts +28 -1
- package/src/router/segment-resolution/fresh.ts +22 -18
- package/src/router/segment-resolution/loader-cache.ts +2 -1
- package/src/router/segment-resolution/loader-mask.ts +5 -3
- package/src/router/segment-resolution/loader-snapshot.ts +18 -4
- package/src/router/segment-resolution/mask-nested.ts +8 -4
- package/src/router/segment-resolution/prefetch-deferral.ts +583 -0
- package/src/router/segment-resolution/revalidation.ts +215 -82
- package/src/rsc/full-payload.ts +37 -5
- package/src/rsc/handler.ts +82 -55
- package/src/rsc/helpers.ts +24 -0
- package/src/rsc/loader-fetch.ts +79 -24
- package/src/rsc/response-cache-serve.ts +18 -2
- package/src/rsc/response-route-handler.ts +4 -7
- package/src/rsc/rewrite-passes.ts +203 -0
- package/src/rsc/rsc-rendering.ts +54 -9
- package/src/rsc/shell-capture.ts +2 -1
- package/src/rsc/ssr-setup.ts +11 -5
- package/src/segment-loader-promise.ts +23 -20
- package/src/segment-system.tsx +60 -26
- package/src/server/context.ts +39 -5
- package/src/server/cookie-parse.ts +36 -12
- package/src/server/cookie-store.ts +7 -3
- package/src/server/handle-store.ts +152 -25
- package/src/server/request-context.ts +175 -64
- package/src/server/request-headers.ts +4 -14
- package/src/server/rewrite-trail.ts +190 -0
- package/src/server/slot-accessors.ts +57 -0
- package/src/server.ts +4 -0
- package/src/ssr/index.tsx +118 -16
- package/src/testing/action-form.ts +2 -11
- package/src/testing/dispatch.ts +138 -67
- package/src/testing/e2e/page-helpers.ts +3 -1
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +7 -3
- package/src/testing/internal/action-id.ts +16 -1
- package/src/testing/internal/client-urls-projection.ts +70 -0
- package/src/testing/internal/test-action.ts +25 -0
- package/src/testing/render-route.tsx +16 -3
- package/src/testing/run-loader.ts +4 -1
- package/src/testing/run-middleware.ts +56 -11
- package/src/testing/run-revalidate.ts +142 -0
- package/src/testing/run-transition-when.ts +7 -8
- package/src/testing/serve-shell-request.ts +131 -8
- package/src/testing/vitest.ts +67 -1
- package/src/thenable-status.ts +11 -0
- package/src/types/boundaries.ts +12 -0
- package/src/types/handler-context.ts +14 -0
- package/src/types/loader-types.ts +30 -0
- package/src/types/request-scope.ts +8 -0
- package/src/types/segments.ts +26 -4
- package/src/urls/path-helper-types.ts +27 -5
- package/src/urls/type-extraction.ts +30 -10
- package/src/use-loader.tsx +18 -13
- package/src/vite/discovery/client-urls-projection.ts +20 -21
- package/src/vite/discovery/discover-routers.ts +94 -26
- package/src/vite/discovery/state.ts +28 -4
- package/src/vite/discovery/virtual-module-codegen.ts +22 -17
- package/src/vite/plugins/client-urls-revalidate-hoist.ts +564 -0
- package/src/vite/plugins/expose-internal-ids.ts +2 -3
- package/src/vite/plugins/hoist/literal.ts +417 -0
- package/src/vite/plugins/hoist/scope.ts +370 -0
- package/src/vite/plugins/hoist/source.ts +84 -0
- package/src/vite/plugins/transition-when-hoist.ts +113 -779
- package/src/vite/rango.ts +2 -0
- package/src/vite/router-discovery.ts +116 -53
- package/dist/types/client-urls/revalidate-chain.d.ts +0 -33
- package/dist/types/client-urls/revalidation-protocol.d.ts +0 -25
- package/dist/types/testing/run-client-revalidate.d.ts +0 -43
- package/src/client-urls/revalidate-chain.ts +0 -83
- package/src/client-urls/revalidation-protocol.ts +0 -56
- package/src/testing/run-client-revalidate.ts +0 -92
package/dist/bin/rango.js
CHANGED
|
@@ -210,9 +210,15 @@ var init_codegen = __esm({
|
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
// src/build/route-types/scan-filter.ts
|
|
213
|
-
import { join, relative } from "node:path";
|
|
213
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
214
214
|
import { readdirSync } from "node:fs";
|
|
215
215
|
import picomatch from "picomatch";
|
|
216
|
+
function isUniversallySkippedScanDir(name) {
|
|
217
|
+
return name === "node_modules" || name === "dist" || name === "coverage" || name.startsWith(".");
|
|
218
|
+
}
|
|
219
|
+
function isSkippedSourceScanDir(name) {
|
|
220
|
+
return isUniversallySkippedScanDir(name) || name === "build";
|
|
221
|
+
}
|
|
216
222
|
function findTsFiles(dir, filter) {
|
|
217
223
|
const results = [];
|
|
218
224
|
let entries;
|
|
@@ -227,8 +233,7 @@ function findTsFiles(dir, filter) {
|
|
|
227
233
|
for (const entry of entries) {
|
|
228
234
|
const fullPath = join(dir, entry.name);
|
|
229
235
|
if (entry.isDirectory()) {
|
|
230
|
-
if (entry.name
|
|
231
|
-
continue;
|
|
236
|
+
if (isSkippedSourceScanDir(entry.name)) continue;
|
|
232
237
|
results.push(...findTsFiles(fullPath, filter));
|
|
233
238
|
} else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
|
|
234
239
|
if (filter && !filter(fullPath)) continue;
|
|
@@ -1032,7 +1037,7 @@ function isRoutableSourceFile(name) {
|
|
|
1032
1037
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
1033
1038
|
}
|
|
1034
1039
|
function isExcludedScanDir(name) {
|
|
1035
|
-
return name
|
|
1040
|
+
return isUniversallySkippedScanDir(name) || name === "__tests__" || name === "__mocks__";
|
|
1036
1041
|
}
|
|
1037
1042
|
function findCallSiteFilesRecursive(dir, pattern, patternG, stopAtMatchDir, filter, results) {
|
|
1038
1043
|
let entries;
|
|
@@ -1443,6 +1448,7 @@ var init_router_processing = __esm({
|
|
|
1443
1448
|
"src/build/route-types/router-processing.ts"() {
|
|
1444
1449
|
"use strict";
|
|
1445
1450
|
init_codegen();
|
|
1451
|
+
init_scan_filter();
|
|
1446
1452
|
init_source_scan();
|
|
1447
1453
|
init_include_resolution();
|
|
1448
1454
|
init_per_module_writer();
|
package/dist/testing/vitest.js
CHANGED
|
@@ -243,6 +243,22 @@ function resolveFromRouter(spec) {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
var rsdServerEdgePath = resolveFromRouter(RSD_SERVER_EDGE_SPEC);
|
|
246
|
+
var CLIENT_URLS_SOURCE_QUERY = "rango-client-urls-source";
|
|
247
|
+
var CLIENT_ENTRY_RSC_PATH = here("src/client.rsc.tsx").replaceAll(
|
|
248
|
+
"\\",
|
|
249
|
+
"/"
|
|
250
|
+
);
|
|
251
|
+
var CLIENT_URLS_INSTALLER_PATH = here(
|
|
252
|
+
"src/testing/internal/client-urls-projection.ts"
|
|
253
|
+
).replaceAll("\\", "/");
|
|
254
|
+
function clientUrlsProjectionInstall(id) {
|
|
255
|
+
const source = `${id}${id.includes("?") ? "&" : "?"}${CLIENT_URLS_SOURCE_QUERY}`;
|
|
256
|
+
return `
|
|
257
|
+
import * as $$RangoClientUrlsSource from ${JSON.stringify(source)};
|
|
258
|
+
import { installClientUrlsProjection as $$rangoInstallClientUrlsProjection } from ${JSON.stringify(CLIENT_URLS_INSTALLER_PATH)};
|
|
259
|
+
$$rangoInstallClientUrlsProjection(${JSON.stringify(`${id}#default`)}, $$RangoClientUrlsSource);
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
246
262
|
function rangoTestAliases(opts = {}) {
|
|
247
263
|
const aliases = [
|
|
248
264
|
// Real impls (index.rsc.ts) for the bare specifier ONLY — exact regex so
|
|
@@ -290,8 +306,19 @@ function rangoTestConfig(opts = {}) {
|
|
|
290
306
|
function rangoUseClientTransform() {
|
|
291
307
|
return {
|
|
292
308
|
name: "rango:testing-use-client",
|
|
309
|
+
resolveId: {
|
|
310
|
+
// Before Vite's resolver, which resolves the bare specifier first.
|
|
311
|
+
order: "pre",
|
|
312
|
+
handler(source, importer) {
|
|
313
|
+
if (source === "@rangojs/router/client" && importer?.includes(CLIENT_URLS_SOURCE_QUERY)) {
|
|
314
|
+
return CLIENT_ENTRY_RSC_PATH;
|
|
315
|
+
}
|
|
316
|
+
return void 0;
|
|
317
|
+
}
|
|
318
|
+
},
|
|
293
319
|
async transform(code, id) {
|
|
294
320
|
if (id.includes("/node_modules/")) return void 0;
|
|
321
|
+
if (id.includes(CLIENT_URLS_SOURCE_QUERY)) return void 0;
|
|
295
322
|
if (!code.includes("use client")) return void 0;
|
|
296
323
|
const { parseAstAsync } = await import("vite");
|
|
297
324
|
const { hasDirective, transformDirectiveProxyExport } = await import("@vitejs/plugin-rsc/transforms");
|
|
@@ -308,12 +335,15 @@ function rangoUseClientTransform() {
|
|
|
308
335
|
runtime: (name) => `$$RangoRSD.registerClientReference(() => { throw new Error("client reference " + ${JSON.stringify(name)} + " is not callable on the server"); }, ${JSON.stringify(id)}, ${JSON.stringify(name)})`
|
|
309
336
|
});
|
|
310
337
|
if (!result) return void 0;
|
|
311
|
-
const { output } = result;
|
|
338
|
+
const { output, exportNames } = result;
|
|
312
339
|
const rsdHref = rsdServerEdgePath ? pathToFileURL(rsdServerEdgePath).href : RSD_SERVER_EDGE_SPEC;
|
|
313
340
|
output.prepend(
|
|
314
341
|
`import * as $$RangoRSD from ${JSON.stringify(rsdHref)};
|
|
315
342
|
`
|
|
316
343
|
);
|
|
344
|
+
if (code.includes("clientUrls(") && exportNames.includes("default")) {
|
|
345
|
+
output.append(clientUrlsProjectionInstall(id));
|
|
346
|
+
}
|
|
317
347
|
return {
|
|
318
348
|
code: output.toString(),
|
|
319
349
|
map: output.generateMap({ hires: true })
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One hole of a `prefetch: false` adoption (browser/partial-update.ts
|
|
3
|
+
* armHoles): the promise every reader of the hole waits on, and what the
|
|
4
|
+
* router knows of it. The router sets `status` and `value` here; it never
|
|
5
|
+
* writes React's thenable fields on `promise`.
|
|
6
|
+
*
|
|
7
|
+
* Resolve-only: a hole is filled or released (releaseHoles), never rejected.
|
|
8
|
+
* A failure arrives as a fulfilled value (a loader's error envelope, an
|
|
9
|
+
* error segment's node).
|
|
10
|
+
*/
|
|
11
|
+
export declare class Defer<T> {
|
|
12
|
+
status: "pending" | "fulfilled";
|
|
13
|
+
value: T | undefined;
|
|
14
|
+
/** A reader has handed React `promise` (readDefer). */
|
|
15
|
+
read?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Resolved with a value the router holds (a node), the hole is
|
|
18
|
+
* "fulfilled" at once. Resolved with a stream (a Flight chunk), its promise
|
|
19
|
+
* follows the stream, and so does the hole: "fulfilled" with the stream's
|
|
20
|
+
* value once it arrives, so a reader that mounts after that reads the value
|
|
21
|
+
* as it would read the chunk Flight marked. A rejected stream leaves the
|
|
22
|
+
* hole pending; its promise carries the rejection.
|
|
23
|
+
*/
|
|
24
|
+
resolve: (value: T) => void;
|
|
25
|
+
readonly promise: Promise<T>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The read rule, for a component that reads a hole (Suspender, useLoader).
|
|
29
|
+
* A hole that has fulfilled and that no reader has handed React is its
|
|
30
|
+
* value: use() of a promise React has not seen suspends an urgent render
|
|
31
|
+
* once, and the boundary shows its fallback. Once a reader has handed React
|
|
32
|
+
* the promise, every read is use() of that promise: React has marked it and
|
|
33
|
+
* returns its value at once, and a replay of the reader must hand use() the
|
|
34
|
+
* thenable it read before ("A component was suspended by an uncached
|
|
35
|
+
* promise"). Either way use() is called once, as at every useLoader read.
|
|
36
|
+
*/
|
|
37
|
+
export declare function readDefer<T>(hole: Defer<T>): T;
|
|
38
|
+
/**
|
|
39
|
+
* A hole as the loader-streams convention has it: its promise while pending,
|
|
40
|
+
* its value once fulfilled. Anything else is returned as it is. For an
|
|
41
|
+
* aggregate, the pending-stream registry, and a node React reads itself (a
|
|
42
|
+
* segment or slot with no `loading()`): a router component there would be a
|
|
43
|
+
* fiber the filled page's node does not have, and the next render from the
|
|
44
|
+
* filled entry would remount the segment. React suspends such a read on the
|
|
45
|
+
* component above it, which commits nothing until the hole fulfils, so the
|
|
46
|
+
* value can stand where React read the promise.
|
|
47
|
+
*/
|
|
48
|
+
export declare function asStream(value: unknown): unknown;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves once the document has finished parsing and no Suspense boundary of
|
|
3
|
+
* it is unrevealed.
|
|
4
|
+
*
|
|
5
|
+
* Parsing ends with the stream, but React reveals a streamed boundary in
|
|
6
|
+
* batches up to 300 ms later (Fizz's $RC marks it `$~` and reveals it from a
|
|
7
|
+
* timer), so the boundary is still pending at DOMContentLoaded. A transition
|
|
8
|
+
* then would make React client-render it over its server HTML.
|
|
9
|
+
*
|
|
10
|
+
* A reveal rewrites the same comment's data, or React removes the node; a
|
|
11
|
+
* boundary nested in revealed content joins the document only then, so it
|
|
12
|
+
* resolves only once a full walk finds none. Polls with setTimeout, not
|
|
13
|
+
* requestAnimationFrame: a hidden tab never runs rAF, which would hold late
|
|
14
|
+
* handle pushes and location state until the tab is shown again. A tab hidden
|
|
15
|
+
* from load still waits: Fizz reveals boundaries from a rAF-gated script.
|
|
16
|
+
*/
|
|
17
|
+
export declare function awaitDocumentRevealed(): Promise<void>;
|
|
@@ -178,7 +178,13 @@ export interface EventController {
|
|
|
178
178
|
startNavigation(url: string, options?: NavigateOptionsInternal & {
|
|
179
179
|
skipLoadingState?: boolean;
|
|
180
180
|
}): NavigationHandle;
|
|
181
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Abort the pending navigation, and the committed one whose stream is
|
|
183
|
+
* still open. `pendingOnly` leaves the committed one alone: a page
|
|
184
|
+
* restored from the back/forward cache is not being left
|
|
185
|
+
* (navigation-bridge.ts handlePageShow).
|
|
186
|
+
*/
|
|
187
|
+
abortNavigation(pendingOnly?: boolean): void;
|
|
182
188
|
startAction(actionId: string, args: unknown[],
|
|
183
189
|
/** Originating history entry key; scopes location-state arbitration. */
|
|
184
190
|
cohort?: string): ActionHandle;
|
|
@@ -3,8 +3,11 @@ import type { ResolvedSegment } from "./types.js";
|
|
|
3
3
|
* Merge partial loader data from server with cached loader data.
|
|
4
4
|
*
|
|
5
5
|
* During partial revalidation (stale or action), the server may return only
|
|
6
|
-
* some loaders that pass the revalidation check
|
|
7
|
-
* all loader data, so we merge fresh data with
|
|
6
|
+
* some loaders that pass the revalidation check, none when every one is held.
|
|
7
|
+
* The component still needs all loader data, so we merge fresh data with
|
|
8
|
+
* cached data. Two settled aggregates merge into the array itself: a fresh
|
|
9
|
+
* Promise.all over settled parts is a promise React has not read, and content
|
|
10
|
+
* on screen handed one suspends (docs/internal/suspense-contract.md, rule 2).
|
|
8
11
|
*
|
|
9
12
|
* @param fromServer - Segment returned from server with partial loaders
|
|
10
13
|
* @param fromCache - Cached segment with full loader data
|
|
@@ -65,6 +65,24 @@ interface BoundCommitOverrides {
|
|
|
65
65
|
/** No payload follows this commit (CommitOptions.treeless). */
|
|
66
66
|
treeless?: boolean;
|
|
67
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* What a commit decided about scroll, in the shape the update that follows
|
|
70
|
+
* carries it (NavigationUpdate.scroll). A navigation always decides, and "do
|
|
71
|
+
* not scroll" is a decision (`<Link scroll={false}>`, an intercept): it
|
|
72
|
+
* replaces a pending one. A commit that is not a navigation decides nothing:
|
|
73
|
+
* an action refetch into the entry on screen (`storeOnly`) and a cache-only
|
|
74
|
+
* commit return no `scroll`, and their update leaves a pending decision alone
|
|
75
|
+
* (react/NavigationProvider.tsx).
|
|
76
|
+
*
|
|
77
|
+
* Scar tissue: those two used to answer `scroll: false`. An action refetch
|
|
78
|
+
* that landed before React committed a navigation then replaced the
|
|
79
|
+
* navigation's pending scroll with "do not scroll".
|
|
80
|
+
*/
|
|
81
|
+
export interface CommitResult {
|
|
82
|
+
scroll?: {
|
|
83
|
+
enabled: boolean | undefined;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
68
86
|
/**
|
|
69
87
|
* Bound transaction with pre-configured commit options (without segmentIds/segments)
|
|
70
88
|
*/
|
|
@@ -80,19 +98,15 @@ export interface BoundTransaction {
|
|
|
80
98
|
readonly transitionGatedOff?: boolean;
|
|
81
99
|
/** Start streaming and get a token to end it when the stream completes */
|
|
82
100
|
startStreaming(): StreamingToken;
|
|
83
|
-
/** Commit the navigation. Returns
|
|
84
|
-
commit(segmentIds: string[], segments: ResolvedSegment[], overrides?: BoundCommitOverrides):
|
|
85
|
-
scroll?: boolean;
|
|
86
|
-
};
|
|
101
|
+
/** Commit the navigation. Returns its scroll decision, for the update. */
|
|
102
|
+
commit(segmentIds: string[], segments: ResolvedSegment[], overrides?: BoundCommitOverrides): CommitResult;
|
|
87
103
|
}
|
|
88
104
|
/**
|
|
89
105
|
* Navigation transaction for managing state during navigation
|
|
90
106
|
* Uses the event controller handle for lifecycle management
|
|
91
107
|
*/
|
|
92
108
|
interface NavigationTransaction extends Disposable {
|
|
93
|
-
commit(options: CommitOptions):
|
|
94
|
-
scroll?: boolean;
|
|
95
|
-
};
|
|
109
|
+
commit(options: CommitOptions): CommitResult;
|
|
96
110
|
with(options: Omit<CommitOptions, "segmentIds" | "segments">): BoundTransaction;
|
|
97
111
|
/** The navigation handle from the event controller */
|
|
98
112
|
handle: NavigationHandle;
|
|
@@ -2,7 +2,7 @@ import type { NavigationStore, NavigationClient, UpdateSubscriber, ResolvedSegme
|
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import type { RenderSegmentsOptions } from "../segment-system.js";
|
|
4
4
|
import type { BoundTransaction } from "./navigation-transaction.js";
|
|
5
|
-
import type { NavigationUpdate } from "./types.js";
|
|
5
|
+
import type { HandleData, NavigationUpdate, RscMetadata } from "./types.js";
|
|
6
6
|
import type { LoaderStore } from "../loader-store.js";
|
|
7
7
|
import { type TransitionWhenActionInput } from "./transition-when.js";
|
|
8
8
|
/**
|
|
@@ -30,6 +30,31 @@ export interface PartialUpdateConfig {
|
|
|
30
30
|
renderSegments: (segments: ResolvedSegment[], options?: RenderSegmentsOptions) => Promise<ReactNode> | ReactNode;
|
|
31
31
|
/** RSC version getter — returns the current version (may change after HMR) */
|
|
32
32
|
getVersion?: () => string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* A fill (`prefetch: false`) lands after its navigation has committed: the
|
|
35
|
+
* transaction has recorded the entry and handed React the tree, and the
|
|
36
|
+
* fill hands React no update that would carry what its response holds to
|
|
37
|
+
* the stores. The bridge that owns navigation supplies the writes, the
|
|
38
|
+
* ones its own updates make. Without them a redirect is a document
|
|
39
|
+
* navigation and the rest is dropped.
|
|
40
|
+
*/
|
|
41
|
+
fill?: {
|
|
42
|
+
redirect(url: string, state?: Record<string, unknown>): void;
|
|
43
|
+
/** The location state the server set, to the entry and its readers. */
|
|
44
|
+
locationState(state: Record<string, unknown>): void;
|
|
45
|
+
/** What the response's handlers pushed, to the handle store. */
|
|
46
|
+
handles(metadata: RscMetadata): void;
|
|
47
|
+
/**
|
|
48
|
+
* Deliver the navigation state to its readers now. A page built with
|
|
49
|
+
* holes commits in the task of its click, before the notification of the
|
|
50
|
+
* click has gone out (event-controller.ts makeDebouncedNotifier), and
|
|
51
|
+
* React holds that commit where a hole is read with no boundary: without
|
|
52
|
+
* this useNavigation() reads idle, on the page being left, for the whole
|
|
53
|
+
* wait. Delivered first, `loading` is on screen when the commit is
|
|
54
|
+
* handed over, and stays while React holds it, as for a plain click.
|
|
55
|
+
*/
|
|
56
|
+
flush(): void;
|
|
57
|
+
};
|
|
33
58
|
}
|
|
34
59
|
/**
|
|
35
60
|
* Options that can override the pre-configured commit settings
|
|
@@ -58,18 +83,24 @@ export type UpdateMode = {
|
|
|
58
83
|
* when we send cached segment IDs to the server - if the server returns empty diff,
|
|
59
84
|
* we use the same segments we told the server we have. */
|
|
60
85
|
targetCacheSegments?: ResolvedSegment[];
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
63
|
-
|
|
86
|
+
/** The handle state of `targetCacheSegments`: the entry's pushes, and
|
|
87
|
+
* the live pushes of the page on screen for each segment taken from it.
|
|
88
|
+
* Read at commit; the page starts from it and the response's handles,
|
|
89
|
+
* when it has any, merge onto it (NavigationProvider). */
|
|
90
|
+
targetCacheHandleData?: () => HandleData;
|
|
64
91
|
/** Source URL for intercept restore (popstate cache miss) */
|
|
65
92
|
interceptSourceUrl?: string;
|
|
66
93
|
/**
|
|
67
|
-
* The
|
|
68
|
-
*
|
|
94
|
+
* The optimistic clientUrls() destination the bridge presented for
|
|
95
|
+
* this navigation. Transition-lane commits add
|
|
69
96
|
* OPTIMISTIC_COMMIT_TRANSITION_TYPE so router <ViewTransition>
|
|
70
|
-
* boundaries do not animate the identical repaint
|
|
97
|
+
* boundaries do not animate the identical repaint, and `clear()` runs
|
|
98
|
+
* once the canonical tree is handed to React: `useOutlet().pending`
|
|
99
|
+
* ends with that commit, not with a `prefetch: false` fill after it.
|
|
71
100
|
*/
|
|
72
|
-
|
|
101
|
+
presentation?: {
|
|
102
|
+
clear(): void;
|
|
103
|
+
};
|
|
73
104
|
/**
|
|
74
105
|
* A router.refresh() (or cross-tab refresh) of the current URL:
|
|
75
106
|
* transition({ when }) sees kind "revalidate", not "replace".
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import type { NavigationStore, NavigationUpdate, NavigationBridge } from "../types.js";
|
|
2
|
+
import type { NavigationStore, NavigationUpdate, NavigationBridge, RscMetadata } from "../types.js";
|
|
3
3
|
import type { EventController } from "../event-controller.js";
|
|
4
4
|
import type { ResolvedThemeConfig, Theme } from "../../theme/types.js";
|
|
5
5
|
import { type AppShellRef } from "../app-shell.js";
|
|
6
|
+
/**
|
|
7
|
+
* Read the handle stream of `metadata` into the event controller and the
|
|
8
|
+
* entry on screen. The provider's own call for every payload it is handed,
|
|
9
|
+
* and the one write for a response that hands React nothing (a fill,
|
|
10
|
+
* browser/partial-update.ts fillHoles).
|
|
11
|
+
*/
|
|
12
|
+
export declare function consumeHandles(metadata: RscMetadata, eventController: EventController, store: NavigationStore): void;
|
|
6
13
|
/**
|
|
7
14
|
* Props for NavigationProvider
|
|
8
15
|
*/
|
|
@@ -67,10 +74,17 @@ export interface NavigationProviderProps {
|
|
|
67
74
|
* The document this provider hydrates (initBrowserApp; renderRoute with
|
|
68
75
|
* `hydrate: true`), whose store EventController.lockHydration locked.
|
|
69
76
|
* `settled` resolves once the stream has ended and React has revealed every
|
|
70
|
-
* boundary.
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
77
|
+
* boundary. Then a transition changes HydrationBarrierContext alone, and
|
|
78
|
+
* React commits it once every boundary has hydrated, one still suspended on
|
|
79
|
+
* the client (a lazy chunk, a deferred-hydration gate) included. Until that
|
|
80
|
+
* commit location state is `undefined`, as SSR rendered it, through any
|
|
81
|
+
* commit no payload follows (a shallow navigation), and the store is
|
|
82
|
+
* locked; after it the entry's state lands in a transition of its own
|
|
83
|
+
* and the store is released (handle data lands in that release
|
|
84
|
+
* notification). A navigation committed earlier releases the store before
|
|
85
|
+
* its update, for the whole hold when the navigation is held: an old-page
|
|
86
|
+
* boundary hydrating meanwhile reads the destination's values and can
|
|
87
|
+
* mismatch.
|
|
74
88
|
* Absent for a provider mounted on the client.
|
|
75
89
|
*/
|
|
76
90
|
hydration?: {
|
|
@@ -76,7 +76,8 @@ export declare const LocationStateContext: Context<LocationStateSnapshot>;
|
|
|
76
76
|
* Read by no component. NavigationProvider changes its value in a transition so
|
|
77
77
|
* that React hydrates every boundary still dehydrated beneath it before that
|
|
78
78
|
* commit: React hydrates a dehydrated boundary first when a provider above it
|
|
79
|
-
* changes, and nothing re-renders for a value nobody reads.
|
|
80
|
-
*
|
|
79
|
+
* changes, and nothing re-renders for a value nobody reads. It must stay
|
|
80
|
+
* unread and alone in its lane (docs/internal/execution-model.md, "The reveal
|
|
81
|
+
* barrier is alone in its lane"). See NavigationProviderProps.hydration.
|
|
81
82
|
*/
|
|
82
83
|
export declare const HydrationBarrierContext: Context<number>;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A loader sub-id carries a `D${index}.` marker ("M0L0D1.user"). Non-global,
|
|
3
|
+
* so `.test` and `.replace` are stateless.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LOADER_SEGMENT_ID: RegExp;
|
|
6
|
+
/** True for a loader sub-id ("M0L0D1.user"), false for a layout/route/slot id. */
|
|
7
|
+
export declare function isLoaderSegmentId(id: string): boolean;
|
|
1
8
|
/**
|
|
2
9
|
* Build the handle-collection segment order from a raw `matched` list.
|
|
3
10
|
*
|
|
@@ -6,6 +6,13 @@ type HeaderResult = {
|
|
|
6
6
|
* Returns { url } if valid, "blocked" if present but invalid origin, null if absent.
|
|
7
7
|
*/
|
|
8
8
|
export declare function extractRscHeaderUrl(response: Response, header: string): HeaderResult;
|
|
9
|
+
/**
|
|
10
|
+
* Run `request` with a signal that `signal` aborts until the request settles,
|
|
11
|
+
* and only until then. A response that has arrived streams to its end:
|
|
12
|
+
* aborting a Flight body mid-read rejects every chunk a mounted tree may be
|
|
13
|
+
* reading. Aborted, the request rejects with `signal.reason`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function abortUntilResponse<T>(signal: AbortSignal | undefined, request: (signal: AbortSignal | undefined) => Promise<T>): Promise<T>;
|
|
9
16
|
/**
|
|
10
17
|
* Empty 200 response that won't choke Flight parsing.
|
|
11
18
|
* Used when a header URL is blocked by origin validation.
|
|
@@ -80,7 +80,11 @@ export interface RscMetadata {
|
|
|
80
80
|
* positions and must complete at the handler barrier.
|
|
81
81
|
*/
|
|
82
82
|
handlesLate?: AsyncGenerator<HandleData, void, unknown>;
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Handle data of the history-cache entry the update renders from (a
|
|
85
|
+
* back/forward restore, or a link to a cached page). It replaces the handle
|
|
86
|
+
* state, and `handles`, when present, merge onto it.
|
|
87
|
+
*/
|
|
84
88
|
cachedHandleData?: HandleData;
|
|
85
89
|
/**
|
|
86
90
|
* RSC version string from the server.
|
|
@@ -277,7 +281,12 @@ export interface HistoryEntryMemory {
|
|
|
277
281
|
export interface NavigationUpdate {
|
|
278
282
|
root: ReactNode | Promise<ReactNode>;
|
|
279
283
|
metadata: RscMetadata;
|
|
280
|
-
/**
|
|
284
|
+
/**
|
|
285
|
+
* The scroll decision of the navigation transaction this update commits,
|
|
286
|
+
* applied after React commits it. Absent on every update that is not a
|
|
287
|
+
* navigation's (server action, error, `prefetch: false` fill): such an
|
|
288
|
+
* update says nothing about scroll, and leaves a pending decision alone.
|
|
289
|
+
*/
|
|
281
290
|
scroll?: {
|
|
282
291
|
/** For back/forward: restore saved position */
|
|
283
292
|
restore?: boolean;
|
|
@@ -537,6 +546,12 @@ export interface NavigationStore {
|
|
|
537
546
|
* probe and write into one historyCache scan for the per-yield streaming path.
|
|
538
547
|
*/
|
|
539
548
|
updateCacheHandleDataIfOwned(historyKey: string, handleData: HandleData, ownerInstance: number, stale?: boolean, handlesPending?: boolean): void;
|
|
549
|
+
/**
|
|
550
|
+
* The history keys whose entries show the page `historyKey`'s entry shows:
|
|
551
|
+
* that entry and the copies a shallow navigation made of it, which share its
|
|
552
|
+
* segments array. `[historyKey]` when it has no entry.
|
|
553
|
+
*/
|
|
554
|
+
getPageHistoryKeys(historyKey: string): string[];
|
|
540
555
|
markHistoryCacheStale(): void;
|
|
541
556
|
markCacheAsStaleAndBroadcast(): void;
|
|
542
557
|
clearHistoryCache(): void;
|
|
@@ -558,13 +573,6 @@ export interface FetchPartialOptions {
|
|
|
558
573
|
signal?: AbortSignal;
|
|
559
574
|
/** If true, this is a stale cache revalidation request - server should force revalidators */
|
|
560
575
|
staleRevalidation?: boolean;
|
|
561
|
-
/**
|
|
562
|
-
* Encoded client-run per-loader revalidation decisions
|
|
563
|
-
* (clientUrls revalidate() predicates executed in the browser); sent as
|
|
564
|
-
* X-Rango-Client-Reval and honored only by materialized client-urls loader
|
|
565
|
-
* stubs. Null/absent = locked server defaults.
|
|
566
|
-
*/
|
|
567
|
-
clientRevalidation?: string | null;
|
|
568
576
|
interceptSourceUrl?: string;
|
|
569
577
|
/** RSC version for cache invalidation detection */
|
|
570
578
|
version?: string;
|
|
@@ -572,6 +580,12 @@ export interface FetchPartialOptions {
|
|
|
572
580
|
routerId?: string;
|
|
573
581
|
/** If true, this is an HMR refetch - server should invalidate manifest cache */
|
|
574
582
|
hmr?: boolean;
|
|
583
|
+
/**
|
|
584
|
+
* The fill request of an adopted prefetch that carried deferred segments
|
|
585
|
+
* (`prefetch: false`): marked `_rsc_fill`, never answered from or written
|
|
586
|
+
* to a prefetch cache or the HTTP cache, and it cancels no prefetch.
|
|
587
|
+
*/
|
|
588
|
+
fill?: boolean;
|
|
575
589
|
}
|
|
576
590
|
/**
|
|
577
591
|
* Result of a partial fetch including stream completion tracking
|
|
@@ -644,7 +658,7 @@ export interface NavigationBridgeConfig {
|
|
|
644
658
|
export type { ResolvedSegment };
|
|
645
659
|
/**
|
|
646
660
|
* Token for tracking an active stream.
|
|
647
|
-
* Call end() when the stream completes.
|
|
661
|
+
* Call end() when the stream completes. Only the first call counts.
|
|
648
662
|
*/
|
|
649
663
|
export interface StreamingToken {
|
|
650
664
|
end(): void;
|
|
@@ -26,3 +26,14 @@ export declare function validateRedirectOrigin(url: string, currentOrigin: strin
|
|
|
26
26
|
* @returns The normalized URL string on success, or null if blocked.
|
|
27
27
|
*/
|
|
28
28
|
export declare function validateExternalRedirect(url: string, currentOrigin: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* The target of a redirect a Flight payload carries (`metadata.redirect`), or
|
|
31
|
+
* null when the client refuses it. An explicit off-host one
|
|
32
|
+
* (`redirect(url, { external: true })`) is scheme-validated only:
|
|
33
|
+
* `external` waives the same-origin check the app opted out of, not scheme
|
|
34
|
+
* safety. Every other one must stay on this origin.
|
|
35
|
+
*/
|
|
36
|
+
export declare function validatePayloadRedirect(redirect: {
|
|
37
|
+
url: string;
|
|
38
|
+
external?: boolean;
|
|
39
|
+
}): string | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { extractParamsFromPattern, formatRouteEntry, } from "./route-types/param-extraction.js";
|
|
2
2
|
export { extractRoutesFromSource } from "./route-types/ast-route-extraction.js";
|
|
3
3
|
export { generatePerModuleTypesSource, generateRouteTypesSource, } from "./route-types/codegen.js";
|
|
4
|
-
export { DEFAULT_EXCLUDE_PATTERNS, type ScanFilter, createScanFilter, findTsFiles, } from "./route-types/scan-filter.js";
|
|
4
|
+
export { DEFAULT_EXCLUDE_PATTERNS, type ScanFilter, createScanFilter, findTsFiles, isInSkippedScanDir, } from "./route-types/scan-filter.js";
|
|
5
5
|
export { writePerModuleRouteTypes, writePerModuleRouteTypesForFile, } from "./route-types/per-module-writer.js";
|
|
6
6
|
export { type UnresolvableReason, type UnresolvableInclude, extractIncludesWithDiagnostics, } from "./route-types/include-resolution.js";
|
|
7
7
|
export { extractUrlsFromRouter, extractBasenameFromRouter, type UrlsExtractionResult, buildCombinedRouteMapForRouterFile, detectUnresolvableIncludes, detectUnresolvableIncludesForUrlsFile, findNestedRouterConflict, formatNestedRouterConflictError, findRouterFiles, findHostRouterFiles, writeCombinedRouteTypes, genFileTsPath, resolveSearchSchemas, } from "./route-types/router-processing.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ScanFilter } from "./scan-filter.js";
|
|
2
2
|
import { type UnresolvableInclude } from "./include-resolution.js";
|
|
3
3
|
export declare function findNestedRouterConflict(routerFiles: string[]): {
|
|
4
4
|
ancestor: string;
|
|
@@ -11,7 +11,27 @@ export declare function createScanFilter(root: string, opts: {
|
|
|
11
11
|
exclude?: string[];
|
|
12
12
|
}): ScanFilter | undefined;
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Directory names no discovery scan enters: findTsFiles() and the router scans
|
|
15
|
+
* (findRouterFiles/findHostRouterFiles, router-processing.ts) all build their
|
|
16
|
+
* skip rule on this, so a file below one is never discovered. Dot-directories
|
|
17
|
+
* cover a nested git worktree, a tool cache, or a test's working copy of
|
|
18
|
+
* another app.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isUniversallySkippedScanDir(name: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether a file under `root` sits in a directory every discovery scan skips
|
|
23
|
+
* (isUniversallySkippedScanDir). The dev route-file watcher uses it to ignore
|
|
24
|
+
* files discovery would never find. A path outside `root` is false.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isInSkippedScanDir(root: string, absolutePath: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Directory names the source-file scans skip: findTsFiles() and the build
|
|
29
|
+
* loader pre-scan (expose-internal-ids.ts). The isUniversallySkippedScanDir()
|
|
30
|
+
* set plus `build`, which the router scans still enter.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isSkippedSourceScanDir(name: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Recursively find .ts/.tsx files under a directory, skipping the directories
|
|
35
|
+
* isSkippedSourceScanDir() names and .gen. files.
|
|
16
36
|
*/
|
|
17
37
|
export declare function findTsFiles(dir: string, filter?: ScanFilter): string[];
|
|
@@ -53,6 +53,7 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
53
53
|
private readonly tagPurge?;
|
|
54
54
|
private readonly tagInvalidationTtl?;
|
|
55
55
|
private readonly tagCacheTtl;
|
|
56
|
+
private readonly kvFallThrough;
|
|
56
57
|
constructor(options: CFCacheStoreOptions<TEnv>);
|
|
57
58
|
/**
|
|
58
59
|
* Warn about a namespace-scoped misconfiguration once per namespace per
|
|
@@ -350,7 +351,10 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
350
351
|
* dropped and read from the store (SWR recapture scheduling and each mode's
|
|
351
352
|
* invalidation semantics stay with the store read). That read keeps the
|
|
352
353
|
* caller's `tagHints`: cfTagHints may have evicted the key while the memo
|
|
353
|
-
* still holds it.
|
|
354
|
+
* still holds it. A shell a tag marker rejects is dropped and read from
|
|
355
|
+
* the store too, which may hold a capture from after the marker (see
|
|
356
|
+
* get(), "Tag invalidation"), unless the request's own mask rejected it
|
|
357
|
+
* (declinesKvFallThrough).
|
|
354
358
|
*/
|
|
355
359
|
private readMemoizedShell;
|
|
356
360
|
/**
|
|
@@ -577,6 +581,17 @@ export declare class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<T
|
|
|
577
581
|
* @internal
|
|
578
582
|
*/
|
|
579
583
|
private isL1Invalidated;
|
|
584
|
+
/**
|
|
585
|
+
* Whether a rejected L1 copy skips the KV read: always unless the
|
|
586
|
+
* `kvFallThrough` option is on, and with it on when this request's own
|
|
587
|
+
* updateTag()/revalidateTag() (its mask, request-tag-mask.ts) rejects an
|
|
588
|
+
* entry tagged at `taggedAt`. KV holds a newer entry only if something
|
|
589
|
+
* rendered after this request's invalidation, while the request re-renders
|
|
590
|
+
* every entry it masked, so the read would add one KV get per masked entry
|
|
591
|
+
* to that re-render.
|
|
592
|
+
* @internal
|
|
593
|
+
*/
|
|
594
|
+
private declinesKvFallThrough;
|
|
580
595
|
/**
|
|
581
596
|
* Synthetic Cache API request for a tag's L1-cached invalidation marker.
|
|
582
597
|
* Unversioned for the same reason as tagMarkerKey; the cache namespace
|
|
@@ -51,8 +51,11 @@ export interface CFCacheReadDebugEvent {
|
|
|
51
51
|
* - kv-timeout: the L2/KV read budget fired (read abandoned, NOT a genuine
|
|
52
52
|
* absence -- distinct from kv-miss so a degradation signal is separable)
|
|
53
53
|
* - tag-invalidated: a live L1/KV entry whose cache tags were invalidated
|
|
54
|
-
* after it was written --
|
|
55
|
-
*
|
|
54
|
+
* after it was written -- never served (the tag-invalidation read path,
|
|
55
|
+
* distinct from a plain miss). With `kvFallThrough` on, an L1 copy then
|
|
56
|
+
* reads L2/KV, so a kv-* event follows unless the request invalidated the
|
|
57
|
+
* tag itself; from L2/KV it is a miss and the next render re-populates
|
|
58
|
+
* the entry
|
|
56
59
|
* - error: the read threw
|
|
57
60
|
*/
|
|
58
61
|
outcome: "l1-fresh" | "l1-stale-revalidate" | "l1-revalidating-guarded" | "match-timeout" | "match-error" | "body-timeout" | "body-error" | "non-200" | "tag-invalidated" | "l1-miss" | "kv-fresh" | "kv-stale" | "kv-stale-suppressed" | "kv-miss" | "kv-timeout" | "error";
|
|
@@ -335,6 +338,24 @@ export interface CFCacheStoreOptions<TEnv = unknown> {
|
|
|
335
338
|
* <= 0) to disable and always await KV.
|
|
336
339
|
*/
|
|
337
340
|
kvReadTimeoutMs?: number;
|
|
341
|
+
/**
|
|
342
|
+
* After `updateTag()`/`revalidateTag()`, a location whose own L1 copy a tag
|
|
343
|
+
* marker rejects reads KV next, and serves the entry another location (or a
|
|
344
|
+
* `router.prerender()` warm) wrote after the invalidation, instead of
|
|
345
|
+
* rendering again. Covers `cache()` records, `"use cache"` results, cached
|
|
346
|
+
* responses and `ppr` shells. The request that invalidated the tag still
|
|
347
|
+
* re-renders its own entries without the read.
|
|
348
|
+
*
|
|
349
|
+
* Cost: one KV get per rejected copy per location after each invalidation
|
|
350
|
+
* (150 ms added wait, measured in #1069 locally at 50 ms per KV read on a
|
|
351
|
+
* document with a shell, a record and one `"use cache"` result, every copy
|
|
352
|
+
* rejected; not measured on a deployed worker), paid even when KV holds only
|
|
353
|
+
* the old twin. Worth it where re-rendering costs more than a KV read
|
|
354
|
+
* (several locations, expensive renders). Needs `kv`; ignored without it.
|
|
355
|
+
*
|
|
356
|
+
* Defaults to false: a rejected L1 copy is a miss and the location renders.
|
|
357
|
+
*/
|
|
358
|
+
kvFallThrough?: boolean;
|
|
338
359
|
/**
|
|
339
360
|
* Per-isolate memos ({@link StoreMemoOptions}), one set per isolate and
|
|
340
361
|
* shared by every CFCacheStore in it. `shellMs` (default 2000) and
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document cache storage policy: which responses the document cache stores.
|
|
3
|
+
* A leaf (types and the per-client signal only), so request-scoped code can
|
|
4
|
+
* ask whether a render will be stored (documentCacheStoresRender) without
|
|
5
|
+
* importing the cache middleware.
|
|
6
|
+
*/
|
|
7
|
+
import type { RequestContext } from "../server/request-context.js";
|
|
8
|
+
export interface CacheDirectives {
|
|
9
|
+
sMaxAge?: number;
|
|
10
|
+
staleWhileRevalidate?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if response should be cached based on Cache-Control headers
|
|
14
|
+
*/
|
|
15
|
+
export declare function shouldCacheResponse(response: Response, requestCtx?: Pick<RequestContext, "_payloadVisitorTheme" | "_payloadDeferred" | "_payloadVisitorLocation">): CacheDirectives | null;
|
|
16
|
+
/**
|
|
17
|
+
* Whether this cache will store the response the current render produces, as
|
|
18
|
+
* far as the render can tell: the middleware runs it (a MISS or a stale
|
|
19
|
+
* refresh) and the response stub already opts in. payloadInitialTheme
|
|
20
|
+
* (rsc/full-payload.ts) then renders the no-cookie default theme (#978). A
|
|
21
|
+
* Cache-Control written after next() is not on the stub yet; for that render
|
|
22
|
+
* shouldCacheResponse refuses a payload marked `_payloadVisitorTheme`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function documentCacheStoresRender(reqCtx: Pick<RequestContext, "_documentCacheRender" | "res">): boolean;
|