@rangojs/router 0.22.0 → 0.23.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 +8 -3
- 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/navigation-transaction.d.ts +21 -7
- package/dist/types/browser/partial-update.d.ts +34 -5
- package/dist/types/browser/react/NavigationProvider.d.ts +13 -3
- 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 +19 -9
- 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 +16 -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/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/errors.d.ts +5 -0
- package/dist/types/handles/deferred-resolution.d.ts +2 -1
- package/dist/types/handles/pushed-by.d.ts +23 -0
- package/dist/types/loader-store.d.ts +8 -0
- package/dist/types/prefetch-markers.d.ts +11 -0
- package/dist/types/route-definition/helpers-types.d.ts +27 -0
- package/dist/types/router/is-action.d.ts +2 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +3 -2
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +241 -0
- 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 +14 -1
- 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 +3 -3
- 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/run-loader.d.ts +2 -1
- 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 +38 -0
- package/dist/types/testing/vitest.d.ts +11 -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/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 +11 -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 +843 -309
- package/package.json +2 -2
- package/skills/caching/SKILL.md +42 -5
- package/skills/catalog.json +2 -2
- package/skills/client-urls/SKILL.md +113 -24
- package/skills/cloudflare/SKILL.md +14 -9
- package/skills/hooks/SKILL.md +11 -3
- package/skills/links/SKILL.md +24 -0
- package/skills/loader/SKILL.md +192 -1
- 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 +13 -0
- package/skills/prerender/SKILL.md +22 -8
- package/skills/rango/SKILL.md +12 -6
- package/skills/route/SKILL.md +139 -0
- package/skills/testing/SKILL.md +3 -2
- package/skills/testing/client-components.md +1 -1
- package/skills/testing/predicates.md +67 -32
- package/skills/testing/serve-shell-request.md +88 -18
- package/skills/testing/setup.md +2 -2
- package/skills/typesafety/route-types.md +2 -2
- package/skills/view-transitions/SKILL.md +26 -0
- package/src/browser/defer.ts +82 -0
- package/src/browser/document-revealed.ts +52 -0
- package/src/browser/event-controller.ts +43 -32
- package/src/browser/navigation-bridge.ts +64 -14
- 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 +528 -135
- package/src/browser/prefetch/fetch.ts +2 -1
- package/src/browser/react/NavigationProvider.tsx +47 -28
- package/src/browser/react/filter-segment-order.ts +13 -2
- package/src/browser/response-adapter.ts +20 -0
- package/src/browser/rsc-router.tsx +17 -45
- package/src/browser/server-action-bridge.ts +19 -63
- package/src/browser/types.ts +19 -9
- 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 +37 -10
- 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.ts +22 -1
- 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/errors.ts +15 -0
- package/src/handles/deferred-resolution.ts +28 -5
- package/src/handles/pushed-by.ts +122 -0
- package/src/loader-store.ts +18 -7
- package/src/prefetch-markers.ts +13 -0
- 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/router/intercept-resolution.ts +6 -4
- package/src/router/is-action.ts +2 -1
- package/src/router/loader-resolution.ts +83 -4
- package/src/router/match-api.ts +36 -1
- package/src/router/match-middleware/background-revalidation.ts +11 -1
- package/src/router/match-middleware/cache-lookup.ts +29 -6
- package/src/router/match-middleware/cache-store.ts +17 -1
- package/src/router/match-result.ts +14 -2
- package/src/router/navigation-snapshot.ts +2 -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/prefetch-deferral.ts +543 -0
- package/src/router/segment-resolution/revalidation.ts +169 -60
- package/src/rsc/rsc-rendering.ts +50 -7
- package/src/rsc/shell-capture.ts +2 -1
- 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/handle-store.ts +104 -8
- package/src/server/loader-registry.ts +6 -1
- package/src/server/request-context.ts +21 -1
- package/src/server.ts +4 -0
- package/src/testing/action-form.ts +2 -11
- package/src/testing/e2e/page-helpers.ts +3 -1
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +6 -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/run-loader.ts +2 -1
- package/src/testing/run-revalidate.ts +142 -0
- package/src/testing/run-transition-when.ts +7 -8
- package/src/testing/serve-shell-request.ts +116 -6
- package/src/testing/vitest.ts +67 -1
- 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/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 +20 -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/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 +93 -32
- 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,12 @@ 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
|
+
}
|
|
216
219
|
function findTsFiles(dir, filter) {
|
|
217
220
|
const results = [];
|
|
218
221
|
let entries;
|
|
@@ -227,8 +230,9 @@ function findTsFiles(dir, filter) {
|
|
|
227
230
|
for (const entry of entries) {
|
|
228
231
|
const fullPath = join(dir, entry.name);
|
|
229
232
|
if (entry.isDirectory()) {
|
|
230
|
-
if (entry.name
|
|
233
|
+
if (isUniversallySkippedScanDir(entry.name) || entry.name === "build") {
|
|
231
234
|
continue;
|
|
235
|
+
}
|
|
232
236
|
results.push(...findTsFiles(fullPath, filter));
|
|
233
237
|
} else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
|
|
234
238
|
if (filter && !filter(fullPath)) continue;
|
|
@@ -1032,7 +1036,7 @@ function isRoutableSourceFile(name) {
|
|
|
1032
1036
|
return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
|
|
1033
1037
|
}
|
|
1034
1038
|
function isExcludedScanDir(name) {
|
|
1035
|
-
return name
|
|
1039
|
+
return isUniversallySkippedScanDir(name) || name === "__tests__" || name === "__mocks__";
|
|
1036
1040
|
}
|
|
1037
1041
|
function findCallSiteFilesRecursive(dir, pattern, patternG, stopAtMatchDir, filter, results) {
|
|
1038
1042
|
let entries;
|
|
@@ -1443,6 +1447,7 @@ var init_router_processing = __esm({
|
|
|
1443
1447
|
"src/build/route-types/router-processing.ts"() {
|
|
1444
1448
|
"use strict";
|
|
1445
1449
|
init_codegen();
|
|
1450
|
+
init_scan_filter();
|
|
1446
1451
|
init_source_scan();
|
|
1447
1452
|
init_include_resolution();
|
|
1448
1453
|
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;
|
|
@@ -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 { 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
|
|
@@ -64,12 +89,16 @@ export type UpdateMode = {
|
|
|
64
89
|
/** Source URL for intercept restore (popstate cache miss) */
|
|
65
90
|
interceptSourceUrl?: string;
|
|
66
91
|
/**
|
|
67
|
-
* The
|
|
68
|
-
*
|
|
92
|
+
* The optimistic clientUrls() destination the bridge presented for
|
|
93
|
+
* this navigation. Transition-lane commits add
|
|
69
94
|
* OPTIMISTIC_COMMIT_TRANSITION_TYPE so router <ViewTransition>
|
|
70
|
-
* boundaries do not animate the identical repaint
|
|
95
|
+
* boundaries do not animate the identical repaint, and `clear()` runs
|
|
96
|
+
* once the canonical tree is handed to React: `useOutlet().pending`
|
|
97
|
+
* ends with that commit, not with a `prefetch: false` fill after it.
|
|
71
98
|
*/
|
|
72
|
-
|
|
99
|
+
presentation?: {
|
|
100
|
+
clear(): void;
|
|
101
|
+
};
|
|
73
102
|
/**
|
|
74
103
|
* A router.refresh() (or cross-tab refresh) of the current URL:
|
|
75
104
|
* 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
|
*/
|
|
@@ -69,8 +76,11 @@ export interface NavigationProviderProps {
|
|
|
69
76
|
* `settled` resolves once the stream has ended and React has revealed every
|
|
70
77
|
* boundary. Until then location state is `undefined`, as SSR rendered it;
|
|
71
78
|
* then one transition gives the entry's state and changes
|
|
72
|
-
* HydrationBarrierContext, and the store is released after that commit
|
|
73
|
-
*
|
|
79
|
+
* HydrationBarrierContext, and the store is released after that commit
|
|
80
|
+
* (handle data lands in that release notification). A navigation committed
|
|
81
|
+
* earlier releases the store before its update, for the whole hold when the
|
|
82
|
+
* navigation is held: an old-page boundary hydrating meanwhile reads
|
|
83
|
+
* the destination's values and can mismatch.
|
|
74
84
|
* Absent for a provider mounted on the client.
|
|
75
85
|
*/
|
|
76
86
|
hydration?: {
|
|
@@ -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.
|
|
@@ -277,7 +277,12 @@ export interface HistoryEntryMemory {
|
|
|
277
277
|
export interface NavigationUpdate {
|
|
278
278
|
root: ReactNode | Promise<ReactNode>;
|
|
279
279
|
metadata: RscMetadata;
|
|
280
|
-
/**
|
|
280
|
+
/**
|
|
281
|
+
* The scroll decision of the navigation transaction this update commits,
|
|
282
|
+
* applied after React commits it. Absent on every update that is not a
|
|
283
|
+
* navigation's (server action, error, `prefetch: false` fill): such an
|
|
284
|
+
* update says nothing about scroll, and leaves a pending decision alone.
|
|
285
|
+
*/
|
|
281
286
|
scroll?: {
|
|
282
287
|
/** For back/forward: restore saved position */
|
|
283
288
|
restore?: boolean;
|
|
@@ -537,6 +542,12 @@ export interface NavigationStore {
|
|
|
537
542
|
* probe and write into one historyCache scan for the per-yield streaming path.
|
|
538
543
|
*/
|
|
539
544
|
updateCacheHandleDataIfOwned(historyKey: string, handleData: HandleData, ownerInstance: number, stale?: boolean, handlesPending?: boolean): void;
|
|
545
|
+
/**
|
|
546
|
+
* The history keys whose entries show the page `historyKey`'s entry shows:
|
|
547
|
+
* that entry and the copies a shallow navigation made of it, which share its
|
|
548
|
+
* segments array. `[historyKey]` when it has no entry.
|
|
549
|
+
*/
|
|
550
|
+
getPageHistoryKeys(historyKey: string): string[];
|
|
540
551
|
markHistoryCacheStale(): void;
|
|
541
552
|
markCacheAsStaleAndBroadcast(): void;
|
|
542
553
|
clearHistoryCache(): void;
|
|
@@ -558,13 +569,6 @@ export interface FetchPartialOptions {
|
|
|
558
569
|
signal?: AbortSignal;
|
|
559
570
|
/** If true, this is a stale cache revalidation request - server should force revalidators */
|
|
560
571
|
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
572
|
interceptSourceUrl?: string;
|
|
569
573
|
/** RSC version for cache invalidation detection */
|
|
570
574
|
version?: string;
|
|
@@ -572,6 +576,12 @@ export interface FetchPartialOptions {
|
|
|
572
576
|
routerId?: string;
|
|
573
577
|
/** If true, this is an HMR refetch - server should invalidate manifest cache */
|
|
574
578
|
hmr?: boolean;
|
|
579
|
+
/**
|
|
580
|
+
* The fill request of an adopted prefetch that carried deferred segments
|
|
581
|
+
* (`prefetch: false`): marked `_rsc_fill`, never answered from or written
|
|
582
|
+
* to a prefetch cache or the HTTP cache, and it cancels no prefetch.
|
|
583
|
+
*/
|
|
584
|
+
fill?: boolean;
|
|
575
585
|
}
|
|
576
586
|
/**
|
|
577
587
|
* Result of a partial fetch including stream completion tracking
|
|
@@ -644,7 +654,7 @@ export interface NavigationBridgeConfig {
|
|
|
644
654
|
export type { ResolvedSegment };
|
|
645
655
|
/**
|
|
646
656
|
* Token for tracking an active stream.
|
|
647
|
-
* Call end() when the stream completes.
|
|
657
|
+
* Call end() when the stream completes. Only the first call counts.
|
|
648
658
|
*/
|
|
649
659
|
export interface StreamingToken {
|
|
650
660
|
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,21 @@ 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
|
+
* Recursively find .ts/.tsx files under a directory, skipping the directories
|
|
29
|
+
* isUniversallySkippedScanDir() names, `build`, and .gen. files.
|
|
16
30
|
*/
|
|
17
31
|
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
|
|
@@ -2,4 +2,4 @@ import type { ClientUrlBuilder, ClientUrlPatterns } from "./types.js";
|
|
|
2
2
|
import type { ExtractRoutes } from "../urls/type-extraction.js";
|
|
3
3
|
import type { ClientUrlItems } from "./types.js";
|
|
4
4
|
export declare function clientUrls<const TItems extends ClientUrlItems>(builder: ClientUrlBuilder<TItems>): ClientUrlPatterns<ExtractRoutes<TItems>>;
|
|
5
|
-
export type {
|
|
5
|
+
export type { ClientTransitionConfig, ClientUrlBuilder, ClientUrlHelpers, ClientUrlInterceptRecord, ClientUrlItem, ClientUrlItemInput, ClientUrlItems, ClientLayoutFn, ClientPathOptions, ClientUrlLoaderRecord, ClientPathFn, ClientUrlPatterns, ClientUrlRouteRecord, ClientUrlUse, } from "./types.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The value the build leaves in place of a clientUrls() `revalidate()`
|
|
3
|
+
* predicate in the browser and SSR copies of a "use client" module
|
|
4
|
+
* (vite/plugins/client-urls-revalidate-hoist.ts): the predicate itself moves
|
|
5
|
+
* to a server module, registered under the same content key
|
|
6
|
+
* (revalidate-registry.ts). The projection carries the key; the materialized
|
|
7
|
+
* loader stub calls the registered predicate.
|
|
8
|
+
*/
|
|
9
|
+
export declare const HOISTED_REVALIDATE_KEY = "$$rangoRevalidate";
|
|
10
|
+
export interface HoistedRevalidateRef {
|
|
11
|
+
readonly $$rangoRevalidate: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function isHoistedRevalidateRef(value: unknown): value is HoistedRevalidateRef;
|
|
@@ -46,41 +46,4 @@ export declare function registerClientUrlGroup(definition: ClientUrlPatterns, mo
|
|
|
46
46
|
export declare function beginClientUrlNavigation(targetUrl: URL, signal: AbortSignal,
|
|
47
47
|
/** Builds the entry state; called only when the group presents the target. */
|
|
48
48
|
buildState?: () => unknown, decideTransition?: (destination: ClientUrlDestination) => boolean): ClientUrlNavigationPresentation | null;
|
|
49
|
-
/**
|
|
50
|
-
* Run the held clientUrls route's per-loader revalidate() predicates and
|
|
51
|
-
* encode their decisions for the request header. Predicates are CLIENT code
|
|
52
|
-
* (declared in the "use client" definition module); only decisions cross the
|
|
53
|
-
* wire — the synthesized per-loader revalidate() on every materialized stub
|
|
54
|
-
* (server-projection.ts) reads them back by loader $$id.
|
|
55
|
-
*
|
|
56
|
-
* Decisions exist only for the loaders the client currently HOLDS: the local
|
|
57
|
-
* match of currentUrl. They matter when the server would re-evaluate those
|
|
58
|
-
* held loader segments — same-route param/search navs, actions, and stale
|
|
59
|
-
* restores. Cross-route targets render new segments unconditionally, so a
|
|
60
|
-
* decision would be ignored; we still compute against the current route since
|
|
61
|
-
* only its held segments are addressable.
|
|
62
|
-
*
|
|
63
|
-
* Returns null when no group is active, the current location is not a client
|
|
64
|
-
* route, or no predicate produced a decision that differs from the locked
|
|
65
|
-
* default — the server then applies defaults, which is also the behavior for
|
|
66
|
-
* requests that cannot carry decisions (no-JS, PE, prefetch, document loads).
|
|
67
|
-
*/
|
|
68
|
-
export declare function collectClientRevalidationDecisions(options: {
|
|
69
|
-
currentUrl: URL;
|
|
70
|
-
nextUrl: URL;
|
|
71
|
-
/**
|
|
72
|
-
* True only when the decisions ride the action POST itself — the one
|
|
73
|
-
* request the server evaluates with actionContext (locked default true).
|
|
74
|
-
* Action-triggered refetch GETs (partial-update terminals) pass false:
|
|
75
|
-
* the server gives those navigation defaults, and the delta gate below
|
|
76
|
-
* must diff against the default the SERVER will use, or a force decision
|
|
77
|
-
* on the refetch would be silently swallowed as "equals default".
|
|
78
|
-
*/
|
|
79
|
-
actionRequest: boolean;
|
|
80
|
-
/** Action TRUTH for the predicates' isAction() matcher; may be true on
|
|
81
|
-
* refetch GETs where actionRequest is false. */
|
|
82
|
-
isAction: boolean;
|
|
83
|
-
actionId?: string;
|
|
84
|
-
stale: boolean;
|
|
85
|
-
}): string | null;
|
|
86
49
|
export declare function clearClientUrlNavigationRegistry(): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ShouldRevalidateFn } from "../types.js";
|
|
2
|
+
export declare function registerClientUrlRevalidators(fns: Readonly<Record<string, ShouldRevalidateFn<any, any>>>): void;
|
|
3
|
+
export declare function getClientUrlRevalidator(key: string): ShouldRevalidateFn<any, any> | undefined;
|
|
4
|
+
export declare function clearClientUrlRevalidators(): void;
|