@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
|
@@ -42,6 +42,30 @@ import {
|
|
|
42
42
|
|
|
43
43
|
const debug = createRangoDebugger(NS.discovery);
|
|
44
44
|
|
|
45
|
+
const SERVER_MODULE_ID = "@rangojs/router/server";
|
|
46
|
+
|
|
47
|
+
/** Passes discoverRouters runs before giving up on a runner that keeps reloading. */
|
|
48
|
+
const MAX_DISCOVERY_PASSES = 3;
|
|
49
|
+
|
|
50
|
+
/** A discovery pass result: the runner reloaded mid-pass, redo it. */
|
|
51
|
+
const RUNNER_RELOADED = Symbol("rango.discovery.runnerReloaded");
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether the runner's `@rangojs/router/server` is no longer `serverMod`. A
|
|
55
|
+
* Vite module runner full reload clears its evaluated-module cache, so the
|
|
56
|
+
* next import evaluates a fresh copy with empty module-level registries.
|
|
57
|
+
*/
|
|
58
|
+
async function runnerReloadedSince(
|
|
59
|
+
rscEnv: any,
|
|
60
|
+
serverMod: unknown,
|
|
61
|
+
): Promise<boolean> {
|
|
62
|
+
try {
|
|
63
|
+
return (await rscEnv.runner.import(SERVER_MODULE_ID)) !== serverMod;
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
45
69
|
/**
|
|
46
70
|
* Import the user's entry via RSC runner, generate manifests for each
|
|
47
71
|
* discovered router, build route tries, and optionally run prerender
|
|
@@ -49,25 +73,70 @@ const debug = createRangoDebugger(NS.discovery);
|
|
|
49
73
|
*
|
|
50
74
|
* Returns the imported `@rangojs/router/server` module so the caller
|
|
51
75
|
* can access the RouterRegistry and manifest setters.
|
|
76
|
+
*
|
|
77
|
+
* A pass reads the router registry and installs clientUrls projections on ONE
|
|
78
|
+
* `@rangojs/router/server` instance, and checks that the runner still serves
|
|
79
|
+
* it. A runner full reload during the pass (a watched-file change at boot)
|
|
80
|
+
* splits the realm: a router module bound to the old instance registers there
|
|
81
|
+
* while urls modules re-evaluate against a fresh one, so include() looks its
|
|
82
|
+
* projection up in the fresh, empty Map ("include() could not resolve the
|
|
83
|
+
* server projection"). Such a pass is redone, at most
|
|
84
|
+
* MAX_DISCOVERY_PASSES times; the redo evaluates the entry in one realm.
|
|
52
85
|
*/
|
|
53
86
|
export async function discoverRouters(
|
|
54
87
|
state: DiscoveryState,
|
|
55
88
|
rscEnv: any,
|
|
56
89
|
ssrEnv?: any,
|
|
57
90
|
): Promise<any> {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
const entryPath = state.resolvedEntryPath;
|
|
92
|
+
if (!entryPath) return;
|
|
93
|
+
|
|
94
|
+
for (let pass = 1; ; pass++) {
|
|
95
|
+
// Imported BEFORE the entry so recorded clientUrls projections can be
|
|
96
|
+
// refreshed first: routers re-created by the entry import materialize
|
|
97
|
+
// whatever projection is installed at that moment, which on HMR
|
|
98
|
+
// re-discovery must be the CURRENT module contents, not the previous
|
|
99
|
+
// pass's snapshot (see refreshRecordedClientUrlProjections). It is also
|
|
100
|
+
// the realm baseline of the reload checks; #637 read the registry off a
|
|
101
|
+
// pre-entry copy without one.
|
|
102
|
+
const serverMod = await timed(
|
|
103
|
+
debug,
|
|
104
|
+
"inner: import @rangojs/router/server",
|
|
105
|
+
() => rscEnv.runner.import(SERVER_MODULE_ID),
|
|
106
|
+
);
|
|
107
|
+
let result: unknown;
|
|
108
|
+
try {
|
|
109
|
+
result = await discoverRoutersPass(
|
|
110
|
+
state,
|
|
111
|
+
rscEnv,
|
|
112
|
+
ssrEnv,
|
|
113
|
+
entryPath,
|
|
114
|
+
serverMod,
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!(await runnerReloadedSince(rscEnv, serverMod))) throw error;
|
|
118
|
+
result = RUNNER_RELOADED;
|
|
119
|
+
}
|
|
120
|
+
if (result !== RUNNER_RELOADED) return result;
|
|
121
|
+
if (pass === MAX_DISCOVERY_PASSES) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`[rango] Route discovery did not settle: the RSC module runner reloaded during ${MAX_DISCOVERY_PASSES} consecutive discovery passes.`,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
debug?.(
|
|
127
|
+
"inner: module runner reloaded mid-pass, redoing discovery (pass %d)",
|
|
128
|
+
pass + 1,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function discoverRoutersPass(
|
|
134
|
+
state: DiscoveryState,
|
|
135
|
+
rscEnv: any,
|
|
136
|
+
ssrEnv: any,
|
|
137
|
+
entryPath: string,
|
|
138
|
+
serverMod: any,
|
|
139
|
+
): Promise<any> {
|
|
71
140
|
await timed(debug, "inner: refresh recorded client URL projections", () =>
|
|
72
141
|
refreshRecordedClientUrlProjections(state, ssrEnv, serverMod),
|
|
73
142
|
);
|
|
@@ -76,10 +145,11 @@ export async function discoverRouters(
|
|
|
76
145
|
// For node preset: this is the router file (createRouter() registers in RouterRegistry).
|
|
77
146
|
// For cloudflare preset: this is the worker entry (which imports the router).
|
|
78
147
|
await timed(debug, "inner: import entry", () =>
|
|
79
|
-
rscEnv.runner.import(
|
|
148
|
+
rscEnv.runner.import(entryPath),
|
|
80
149
|
);
|
|
150
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) return RUNNER_RELOADED;
|
|
81
151
|
|
|
82
|
-
|
|
152
|
+
const registry: Map<string, any> = serverMod.RouterRegistry;
|
|
83
153
|
|
|
84
154
|
if (!registry || registry.size === 0) {
|
|
85
155
|
// No RSC routers found directly. Check for host routers with lazy handlers
|
|
@@ -105,16 +175,10 @@ export async function discoverRouters(
|
|
|
105
175
|
debug?.("caught error while resolving %s: %O", context, error);
|
|
106
176
|
}
|
|
107
177
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const freshRegistry: Map<string, any> = freshServerMod.RouterRegistry;
|
|
113
|
-
|
|
114
|
-
if (freshRegistry && freshRegistry.size > 0) {
|
|
115
|
-
// Update references so the manifest generation below uses the fresh data
|
|
116
|
-
Object.assign(serverMod, freshServerMod);
|
|
117
|
-
registry = freshRegistry;
|
|
178
|
+
// Sub-app createRouter() calls populate the same live registry, unless
|
|
179
|
+
// a reload moved them to a fresh realm.
|
|
180
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) {
|
|
181
|
+
return RUNNER_RELOADED;
|
|
118
182
|
}
|
|
119
183
|
}
|
|
120
184
|
} catch (error) {
|
|
@@ -125,7 +189,7 @@ export async function discoverRouters(
|
|
|
125
189
|
|
|
126
190
|
// If still no routers after host router resolution, fail
|
|
127
191
|
if (!registry || registry.size === 0) {
|
|
128
|
-
throw new DiscoveryError(
|
|
192
|
+
throw new DiscoveryError(entryPath, discoveryErrors);
|
|
129
193
|
}
|
|
130
194
|
}
|
|
131
195
|
|
|
@@ -351,6 +415,10 @@ export async function discoverRouters(
|
|
|
351
415
|
}
|
|
352
416
|
}
|
|
353
417
|
|
|
418
|
+
// A reload after the entry import leaves this pass's projections and
|
|
419
|
+
// manifests on a realm the runner no longer serves.
|
|
420
|
+
if (await runnerReloadedSince(rscEnv, serverMod)) return RUNNER_RELOADED;
|
|
421
|
+
|
|
354
422
|
// Commit all local state to the shared discovery state atomically.
|
|
355
423
|
// This ensures a failed re-discovery (e.g. from a transient module
|
|
356
424
|
// evaluation error) preserves the last known-good state.
|
|
@@ -196,14 +196,38 @@ export interface DiscoveryState {
|
|
|
196
196
|
buildEnvDispose?: (() => Promise<void> | void) | null;
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
|
-
* Set when the most recent HMR re-discovery
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* rediscovery trigger
|
|
199
|
+
* Set when the most recent dev discovery failed: an HMR re-discovery, or the
|
|
200
|
+
* cold discovery on the Node RSC runner or the Cloudflare temp runner.
|
|
201
|
+
* Cleared on the next successful discovery. While set, the route-file
|
|
202
|
+
* watcher treats any in-scan source change as a rediscovery trigger
|
|
203
|
+
* (recovery mode).
|
|
203
204
|
*/
|
|
204
205
|
lastDiscoveryError?: { message: string; at: number } | null;
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
/** Record a failed dev discovery (lastDiscoveryError): recovery mode. */
|
|
209
|
+
export function recordDiscoveryFailure(
|
|
210
|
+
state: Pick<DiscoveryState, "lastDiscoveryError">,
|
|
211
|
+
err: unknown,
|
|
212
|
+
): void {
|
|
213
|
+
state.lastDiscoveryError = {
|
|
214
|
+
message: (err as { message?: string } | null)?.message ?? String(err),
|
|
215
|
+
at: Date.now(),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whether the route-file watcher can re-run runtime discovery: a committed
|
|
221
|
+
* manifest, or a recorded failure. A failed cold discovery commits none, and
|
|
222
|
+
* without its recorded failure the dev server stayed broken until a restart,
|
|
223
|
+
* on the Node runner and on Cloudflare alike.
|
|
224
|
+
*/
|
|
225
|
+
export function canRefreshRuntimeDiscovery(
|
|
226
|
+
state: Pick<DiscoveryState, "perRouterManifests" | "lastDiscoveryError">,
|
|
227
|
+
): boolean {
|
|
228
|
+
return state.perRouterManifests.length > 0 || !!state.lastDiscoveryError;
|
|
229
|
+
}
|
|
230
|
+
|
|
207
231
|
export function createDiscoveryState(
|
|
208
232
|
entryPath: string | undefined,
|
|
209
233
|
opts: PluginOptions | undefined,
|
|
@@ -46,6 +46,22 @@ function devDiscoveryBootstrap(state: DiscoveryState): string[] {
|
|
|
46
46
|
return [`globalThis.__RANGO_DEV_DISCOVERY_EPOCH = ${epoch};`];
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/** Clear, then install every projection in state.clientUrlProjectionMap. */
|
|
50
|
+
function clientUrlProjectionReplay(state: DiscoveryState): string[] {
|
|
51
|
+
// Sorted: the map fills in transform order, which varies between runs,
|
|
52
|
+
// and this module's bytes feed cache versions (build-versions.ts).
|
|
53
|
+
const projections = [...(state.clientUrlProjectionMap ?? [])].sort(
|
|
54
|
+
([a], [b]) => compareStrings(a, b),
|
|
55
|
+
);
|
|
56
|
+
return [
|
|
57
|
+
`clearClientUrlProjections();`,
|
|
58
|
+
...projections.map(
|
|
59
|
+
([referenceId, projection]) =>
|
|
60
|
+
`setClientUrlProjection(${JSON.stringify(referenceId)}, ${jsonParseExpression(projection)});`,
|
|
61
|
+
),
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
/**
|
|
50
66
|
* Generate the code for the main virtual:rsc-router/routes-manifest module.
|
|
51
67
|
*/
|
|
@@ -110,19 +126,7 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
|
|
|
110
126
|
TRANSITION_WHEN_VALIDATION,
|
|
111
127
|
];
|
|
112
128
|
|
|
113
|
-
if (hasClientUrlModules)
|
|
114
|
-
lines.push(`clearClientUrlProjections();`);
|
|
115
|
-
// Sorted: the map fills in transform order, which varies between runs,
|
|
116
|
-
// and this module's bytes feed cache versions (build-versions.ts).
|
|
117
|
-
const projections = [...(state.clientUrlProjectionMap ?? [])].sort(
|
|
118
|
-
([a], [b]) => compareStrings(a, b),
|
|
119
|
-
);
|
|
120
|
-
for (const [referenceId, projection] of projections) {
|
|
121
|
-
lines.push(
|
|
122
|
-
`setClientUrlProjection(${JSON.stringify(referenceId)}, ${jsonParseExpression(projection)});`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
129
|
+
if (hasClientUrlModules) lines.push(...clientUrlProjectionReplay(state));
|
|
126
130
|
|
|
127
131
|
if (varIdx > 0) {
|
|
128
132
|
lines.push(
|
|
@@ -197,13 +201,14 @@ export function generateRoutesManifestModule(state: DiscoveryState): string {
|
|
|
197
201
|
return lines.join("\n");
|
|
198
202
|
}
|
|
199
203
|
|
|
204
|
+
// No manifest: discovery has not committed one (a failed cold pass commits
|
|
205
|
+
// nothing). The projections the failed pass computed still replay, so the
|
|
206
|
+
// realm serving requests can resolve include()s of clientUrls() modules.
|
|
200
207
|
const lines: string[] = [
|
|
201
|
-
`import { ${hasClientUrlModules ? "clearClientUrlProjections, " : ""}enableTransitionWhenValidation } from "@rangojs/router/server";`,
|
|
208
|
+
`import { ${hasClientUrlModules ? "clearClientUrlProjections, setClientUrlProjection, " : ""}enableTransitionWhenValidation } from "@rangojs/router/server";`,
|
|
202
209
|
TRANSITION_WHEN_VALIDATION,
|
|
203
210
|
];
|
|
204
|
-
if (hasClientUrlModules)
|
|
205
|
-
lines.push(`clearClientUrlProjections();`);
|
|
206
|
-
}
|
|
211
|
+
if (hasClientUrlModules) lines.push(...clientUrlProjectionReplay(state));
|
|
207
212
|
if (!state.isBuildMode) {
|
|
208
213
|
const origin =
|
|
209
214
|
state.devServerOrigin ||
|