@rangojs/router 0.0.0-experimental.002d056c
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/AGENTS.md +9 -0
- package/README.md +899 -0
- package/dist/bin/rango.js +1606 -0
- package/dist/vite/index.js +5153 -0
- package/package.json +177 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +253 -0
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +182 -0
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +704 -0
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +313 -0
- package/skills/layout/SKILL.md +310 -0
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +596 -0
- package/skills/middleware/SKILL.md +339 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +305 -0
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +118 -0
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +385 -0
- package/skills/router-setup/SKILL.md +439 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +79 -0
- package/skills/typesafety/SKILL.md +623 -0
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +273 -0
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +899 -0
- package/src/browser/history-state.ts +80 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +141 -0
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +134 -0
- package/src/browser/navigation-bridge.ts +638 -0
- package/src/browser/navigation-client.ts +261 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +582 -0
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +145 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +368 -0
- package/src/browser/react/NavigationProvider.tsx +413 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +59 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +162 -0
- package/src/browser/react/location-state.ts +107 -0
- package/src/browser/react/mount-context.ts +37 -0
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +218 -0
- package/src/browser/react/use-client-cache.ts +58 -0
- package/src/browser/react/use-handle.ts +162 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +135 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +99 -0
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +171 -0
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +464 -0
- package/src/browser/scroll-restoration.ts +397 -0
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +667 -0
- package/src/browser/shallow.ts +40 -0
- package/src/browser/types.ts +547 -0
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +479 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +382 -0
- package/src/cache/cf/cf-cache-store.ts +982 -0
- package/src/cache/cf/index.ts +29 -0
- package/src/cache/document-cache.ts +369 -0
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +44 -0
- package/src/cache/memory-segment-store.ts +328 -0
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +342 -0
- package/src/client.rsc.tsx +85 -0
- package/src/client.tsx +601 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +27 -0
- package/src/context-var.ts +86 -0
- package/src/debug.ts +243 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +365 -0
- package/src/handle.ts +135 -0
- package/src/handles/MetaTags.tsx +246 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +7 -0
- package/src/handles/meta.ts +264 -0
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +222 -0
- package/src/index.rsc.ts +233 -0
- package/src/index.ts +277 -0
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +89 -0
- package/src/loader.ts +64 -0
- package/src/network-error-thrower.tsx +23 -0
- package/src/outlet-context.ts +15 -0
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +289 -0
- package/src/route-content-wrapper.tsx +196 -0
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -0
- package/src/route-map-builder.ts +281 -0
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +259 -0
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +397 -0
- package/src/router/lazy-includes.ts +236 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +269 -0
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +266 -0
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +223 -0
- package/src/router/match-middleware/cache-lookup.ts +634 -0
- package/src/router/match-middleware/cache-store.ts +295 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +306 -0
- package/src/router/match-middleware/segment-resolution.ts +193 -0
- package/src/router/match-pipelines.ts +179 -0
- package/src/router/match-result.ts +219 -0
- package/src/router/metrics.ts +282 -0
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +749 -0
- package/src/router/pattern-matching.ts +563 -0
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +289 -0
- package/src/router/router-context.ts +320 -0
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1242 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +170 -0
- package/src/router.ts +1006 -0
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +1089 -0
- package/src/rsc/helpers.ts +198 -0
- package/src/rsc/index.ts +36 -0
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +32 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +263 -0
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +454 -0
- package/src/server/context.ts +591 -0
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +308 -0
- package/src/server/loader-registry.ts +133 -0
- package/src/server/request-context.ts +920 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +51 -0
- package/src/ssr/index.tsx +365 -0
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +297 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +62 -0
- package/src/theme/index.ts +48 -0
- package/src/theme/theme-context.ts +44 -0
- package/src/theme/theme-script.ts +155 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +109 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -0
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -0
- package/src/use-loader.tsx +354 -0
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +16 -0
- package/src/vite/plugin-types.ts +48 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/plugins/expose-action-id.ts +363 -0
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/plugins/version.d.ts +12 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/utils/package-resolution.ts +121 -0
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Discovery
|
|
3
|
+
*
|
|
4
|
+
* Core discovery logic: imports the user's entry file via the RSC
|
|
5
|
+
* environment's module runner, generates manifests for each discovered
|
|
6
|
+
* router, and builds route tries for O(path_length) matching.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
buildCombinedRouteMapForRouterFile,
|
|
11
|
+
formatNestedRouterConflictError,
|
|
12
|
+
findNestedRouterConflict,
|
|
13
|
+
} from "../../build/generate-route-types.js";
|
|
14
|
+
import {
|
|
15
|
+
flattenLeafEntries,
|
|
16
|
+
buildRouteToStaticPrefix,
|
|
17
|
+
} from "../utils/manifest-utils.js";
|
|
18
|
+
import type { DiscoveryState, PrecomputedEntry } from "./state.js";
|
|
19
|
+
import {
|
|
20
|
+
expandPrerenderRoutes,
|
|
21
|
+
renderStaticHandlers,
|
|
22
|
+
} from "./prerender-collection.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Import the user's entry via RSC runner, generate manifests for each
|
|
26
|
+
* discovered router, build route tries, and optionally run prerender
|
|
27
|
+
* expansion and static handler rendering (build mode only).
|
|
28
|
+
*
|
|
29
|
+
* Returns the imported `@rangojs/router/server` module so the caller
|
|
30
|
+
* can access the RouterRegistry and manifest setters.
|
|
31
|
+
*/
|
|
32
|
+
export async function discoverRouters(
|
|
33
|
+
state: DiscoveryState,
|
|
34
|
+
rscEnv: any,
|
|
35
|
+
): Promise<any> {
|
|
36
|
+
if (!state.resolvedEntryPath) return;
|
|
37
|
+
|
|
38
|
+
// Import the entry file via RSC environment.
|
|
39
|
+
// For node preset: this is the router file (createRouter() registers in RouterRegistry).
|
|
40
|
+
// For cloudflare preset: this is the worker entry (which imports the router).
|
|
41
|
+
await rscEnv.runner.import(state.resolvedEntryPath);
|
|
42
|
+
|
|
43
|
+
// Import the router package to access the registry
|
|
44
|
+
const serverMod = await rscEnv.runner.import("@rangojs/router/server");
|
|
45
|
+
let registry: Map<string, any> = serverMod.RouterRegistry;
|
|
46
|
+
|
|
47
|
+
if (!registry || registry.size === 0) {
|
|
48
|
+
// No RSC routers found directly. Check for host routers with lazy handlers
|
|
49
|
+
// that need to be resolved to trigger sub-app createRouter() calls.
|
|
50
|
+
try {
|
|
51
|
+
const hostRegistry: Map<string, any> | undefined =
|
|
52
|
+
serverMod.HostRouterRegistry;
|
|
53
|
+
|
|
54
|
+
if (hostRegistry && hostRegistry.size > 0) {
|
|
55
|
+
console.log(
|
|
56
|
+
`[rsc-router] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
for (const [, entry] of hostRegistry) {
|
|
60
|
+
for (const route of entry.routes) {
|
|
61
|
+
if (typeof route.handler === "function") {
|
|
62
|
+
try {
|
|
63
|
+
await route.handler();
|
|
64
|
+
} catch {
|
|
65
|
+
// Lazy handler may fail in temp server context, that's OK
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (entry.fallback && typeof entry.fallback.handler === "function") {
|
|
70
|
+
try {
|
|
71
|
+
await entry.fallback.handler();
|
|
72
|
+
} catch {
|
|
73
|
+
// Fallback handler may fail in temp server context
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Re-read RouterRegistry - sub-app createRouter() calls should have populated it
|
|
79
|
+
const freshServerMod = await rscEnv.runner.import(
|
|
80
|
+
"@rangojs/router/server",
|
|
81
|
+
);
|
|
82
|
+
const freshRegistry: Map<string, any> = freshServerMod.RouterRegistry;
|
|
83
|
+
|
|
84
|
+
if (freshRegistry && freshRegistry.size > 0) {
|
|
85
|
+
// Update references so the manifest generation below uses the fresh data
|
|
86
|
+
Object.assign(serverMod, freshServerMod);
|
|
87
|
+
registry = freshRegistry;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Host-router discovery is best-effort; skip if unavailable
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If still no routers after host router resolution, fail
|
|
95
|
+
if (!registry || registry.size === 0) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Import build utilities for manifest generation
|
|
103
|
+
const buildMod = await rscEnv.runner.import("@rangojs/router/build");
|
|
104
|
+
const generateManifestFull = buildMod.generateManifestFull;
|
|
105
|
+
|
|
106
|
+
const nestedRouterConflict = findNestedRouterConflict(
|
|
107
|
+
[...registry.values()]
|
|
108
|
+
.map((router) => router.__sourceFile)
|
|
109
|
+
.filter(
|
|
110
|
+
(sourceFile): sourceFile is string => typeof sourceFile === "string",
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
if (nestedRouterConflict) {
|
|
114
|
+
throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Build into local variables first. Only commit to state after the
|
|
118
|
+
// full pass succeeds, so a failed re-discovery preserves the last
|
|
119
|
+
// known-good state instead of leaving it partially wiped.
|
|
120
|
+
const newMergedRouteManifest: Record<string, string> = {};
|
|
121
|
+
const newMergedPrecomputedEntries: PrecomputedEntry[] = [];
|
|
122
|
+
const newPerRouterManifests: typeof state.perRouterManifests = [];
|
|
123
|
+
const newPerRouterManifestDataMap = new Map<string, any>();
|
|
124
|
+
const newPerRouterPrecomputedMap = new Map<string, PrecomputedEntry[]>();
|
|
125
|
+
const newPerRouterTrieMap = new Map<string, any>();
|
|
126
|
+
let mergedRouteAncestry: Record<string, string[]> = {};
|
|
127
|
+
let mergedRouteTrailingSlash: Record<string, string> = {};
|
|
128
|
+
|
|
129
|
+
let routerMountIndex = 0;
|
|
130
|
+
// Collect all manifests for trie building (avoid re-running generateManifest)
|
|
131
|
+
const allManifests: Array<{ id: string; manifest: any }> = [];
|
|
132
|
+
|
|
133
|
+
for (const [id, router] of registry) {
|
|
134
|
+
if (!router.urlpatterns || !generateManifestFull) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const manifest = generateManifestFull(router.urlpatterns, routerMountIndex);
|
|
139
|
+
routerMountIndex++;
|
|
140
|
+
allManifests.push({ id, manifest });
|
|
141
|
+
const routeCount = Object.keys(manifest.routeManifest).length;
|
|
142
|
+
const staticRoutes = Object.values(manifest.routeManifest).filter(
|
|
143
|
+
(p: any) => !p.includes(":") && !p.includes("*"),
|
|
144
|
+
).length;
|
|
145
|
+
const dynamicRoutes = routeCount - staticRoutes;
|
|
146
|
+
|
|
147
|
+
// Merge into the combined manifest
|
|
148
|
+
Object.assign(newMergedRouteManifest, manifest.routeManifest);
|
|
149
|
+
|
|
150
|
+
// Compute factory-only prefixes: dot-prefixed groups in the runtime
|
|
151
|
+
// manifest that the static parser cannot see. These are routes created
|
|
152
|
+
// by factory functions (e.g. createDocsPatterns()) and should always be
|
|
153
|
+
// supplemented on file change since HMR won't re-discover them.
|
|
154
|
+
let factoryOnlyPrefixes: Set<string> | undefined;
|
|
155
|
+
if (router.__sourceFile) {
|
|
156
|
+
const staticParsed = buildCombinedRouteMapForRouterFile(
|
|
157
|
+
router.__sourceFile,
|
|
158
|
+
);
|
|
159
|
+
const staticNames = new Set(Object.keys(staticParsed.routes));
|
|
160
|
+
factoryOnlyPrefixes = new Set<string>();
|
|
161
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
162
|
+
if (staticNames.has(name)) continue;
|
|
163
|
+
const dotIdx = name.indexOf(".");
|
|
164
|
+
if (dotIdx <= 0) continue;
|
|
165
|
+
const prefix = name.substring(0, dotIdx + 1);
|
|
166
|
+
if ([...staticNames].some((n) => n.startsWith(prefix))) continue;
|
|
167
|
+
factoryOnlyPrefixes.add(prefix);
|
|
168
|
+
}
|
|
169
|
+
if (factoryOnlyPrefixes.size === 0) factoryOnlyPrefixes = undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
newPerRouterManifests.push({
|
|
173
|
+
id,
|
|
174
|
+
routeManifest: manifest.routeManifest,
|
|
175
|
+
routeSearchSchemas: manifest.routeSearchSchemas,
|
|
176
|
+
sourceFile: router.__sourceFile,
|
|
177
|
+
factoryOnlyPrefixes,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Merge ancestry (internal field, used only for trie building)
|
|
181
|
+
if (manifest._routeAncestry) {
|
|
182
|
+
Object.assign(mergedRouteAncestry, manifest._routeAncestry);
|
|
183
|
+
}
|
|
184
|
+
// Merge trailing slash config
|
|
185
|
+
if (manifest.routeTrailingSlash) {
|
|
186
|
+
Object.assign(mergedRouteTrailingSlash, manifest.routeTrailingSlash);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Flatten prefix tree leaf nodes into precomputed entries.
|
|
190
|
+
// Leaf nodes (no children) can have their routes used directly by
|
|
191
|
+
// evaluateLazyEntry() without running the handler at runtime.
|
|
192
|
+
flattenLeafEntries(
|
|
193
|
+
manifest.prefixTree,
|
|
194
|
+
manifest.routeManifest,
|
|
195
|
+
newMergedPrecomputedEntries,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// Store per-router manifest and precomputed entries for isolated virtual modules.
|
|
199
|
+
newPerRouterManifestDataMap.set(id, manifest.routeManifest);
|
|
200
|
+
const routerPrecomputed: PrecomputedEntry[] = [];
|
|
201
|
+
flattenLeafEntries(
|
|
202
|
+
manifest.prefixTree,
|
|
203
|
+
manifest.routeManifest,
|
|
204
|
+
routerPrecomputed,
|
|
205
|
+
);
|
|
206
|
+
newPerRouterPrecomputedMap.set(id, routerPrecomputed);
|
|
207
|
+
|
|
208
|
+
console.log(
|
|
209
|
+
`[rsc-router] Router "${id}" -> ${routeCount} routes ` +
|
|
210
|
+
`(${staticRoutes} static, ${dynamicRoutes} dynamic)`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Warn if multiple routers use auto-generated IDs (router_0, router_1, ...).
|
|
215
|
+
// Auto-IDs are assigned by counter and depend on module evaluation order,
|
|
216
|
+
// which can differ between build time and runtime (especially with dynamic
|
|
217
|
+
// imports in host routers). This causes per-router data to be loaded into
|
|
218
|
+
// the wrong router at runtime.
|
|
219
|
+
if (registry.size > 1) {
|
|
220
|
+
const autoIds = [...registry.keys()].filter((id) =>
|
|
221
|
+
/^router_\d+$/.test(id),
|
|
222
|
+
);
|
|
223
|
+
if (autoIds.length > 1) {
|
|
224
|
+
console.warn(
|
|
225
|
+
`[rsc-router] WARNING: ${autoIds.length} routers use auto-generated IDs (${autoIds.join(", ")}). ` +
|
|
226
|
+
`In multi-router setups, each createRouter() must have an explicit \`id\` option ` +
|
|
227
|
+
`to ensure per-router manifest data is matched correctly at runtime. ` +
|
|
228
|
+
`Example: createRouter({ id: "site", ... })`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Build route trie from merged manifest + ancestry
|
|
234
|
+
let newMergedRouteTrie: any = null;
|
|
235
|
+
if (Object.keys(newMergedRouteManifest).length > 0) {
|
|
236
|
+
const buildRouteTrie = buildMod.buildRouteTrie;
|
|
237
|
+
if (buildRouteTrie && mergedRouteAncestry) {
|
|
238
|
+
// Build routeToStaticPrefix from saved manifests
|
|
239
|
+
const routeToStaticPrefix: Record<string, string> = {};
|
|
240
|
+
for (const { manifest } of allManifests) {
|
|
241
|
+
// Root-level routes have empty static prefix
|
|
242
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
243
|
+
if (!(name in routeToStaticPrefix)) {
|
|
244
|
+
routeToStaticPrefix[name] = "";
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
buildRouteToStaticPrefix(manifest.prefixTree, routeToStaticPrefix);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Collect prerender route names and response type routes from all manifests
|
|
251
|
+
const prerenderRouteNames = new Set<string>();
|
|
252
|
+
const passthroughRouteNames = new Set<string>();
|
|
253
|
+
const mergedResponseTypeRoutes: Record<string, string> = {};
|
|
254
|
+
for (const { manifest } of allManifests) {
|
|
255
|
+
if (manifest.prerenderRoutes) {
|
|
256
|
+
for (const name of manifest.prerenderRoutes) {
|
|
257
|
+
prerenderRouteNames.add(name);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (manifest.passthroughRoutes) {
|
|
261
|
+
for (const name of manifest.passthroughRoutes) {
|
|
262
|
+
passthroughRouteNames.add(name);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (manifest.responseTypeRoutes) {
|
|
266
|
+
Object.assign(mergedResponseTypeRoutes, manifest.responseTypeRoutes);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
newMergedRouteTrie = buildRouteTrie(
|
|
271
|
+
newMergedRouteManifest,
|
|
272
|
+
mergedRouteAncestry,
|
|
273
|
+
routeToStaticPrefix,
|
|
274
|
+
Object.keys(mergedRouteTrailingSlash).length > 0
|
|
275
|
+
? mergedRouteTrailingSlash
|
|
276
|
+
: undefined,
|
|
277
|
+
prerenderRouteNames.size > 0 ? prerenderRouteNames : undefined,
|
|
278
|
+
passthroughRouteNames.size > 0 ? passthroughRouteNames : undefined,
|
|
279
|
+
Object.keys(mergedResponseTypeRoutes).length > 0
|
|
280
|
+
? mergedResponseTypeRoutes
|
|
281
|
+
: undefined,
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Build per-router tries for multi-router isolation.
|
|
285
|
+
for (const { id, manifest } of allManifests) {
|
|
286
|
+
if (
|
|
287
|
+
!manifest._routeAncestry ||
|
|
288
|
+
Object.keys(manifest._routeAncestry).length === 0
|
|
289
|
+
)
|
|
290
|
+
continue;
|
|
291
|
+
const perRouterStaticPrefix: Record<string, string> = {};
|
|
292
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
293
|
+
perRouterStaticPrefix[name] = "";
|
|
294
|
+
}
|
|
295
|
+
buildRouteToStaticPrefix(manifest.prefixTree, perRouterStaticPrefix);
|
|
296
|
+
|
|
297
|
+
const perRouterPrerenderNames = manifest.prerenderRoutes
|
|
298
|
+
? new Set<string>(manifest.prerenderRoutes)
|
|
299
|
+
: undefined;
|
|
300
|
+
const perRouterPassthroughNames = manifest.passthroughRoutes
|
|
301
|
+
? new Set<string>(manifest.passthroughRoutes)
|
|
302
|
+
: undefined;
|
|
303
|
+
|
|
304
|
+
const perRouterTrie = buildRouteTrie(
|
|
305
|
+
manifest.routeManifest,
|
|
306
|
+
manifest._routeAncestry,
|
|
307
|
+
perRouterStaticPrefix,
|
|
308
|
+
manifest.routeTrailingSlash &&
|
|
309
|
+
Object.keys(manifest.routeTrailingSlash).length > 0
|
|
310
|
+
? manifest.routeTrailingSlash
|
|
311
|
+
: undefined,
|
|
312
|
+
perRouterPrerenderNames && perRouterPrerenderNames.size > 0
|
|
313
|
+
? perRouterPrerenderNames
|
|
314
|
+
: undefined,
|
|
315
|
+
perRouterPassthroughNames && perRouterPassthroughNames.size > 0
|
|
316
|
+
? perRouterPassthroughNames
|
|
317
|
+
: undefined,
|
|
318
|
+
manifest.responseTypeRoutes &&
|
|
319
|
+
Object.keys(manifest.responseTypeRoutes).length > 0
|
|
320
|
+
? manifest.responseTypeRoutes
|
|
321
|
+
: undefined,
|
|
322
|
+
);
|
|
323
|
+
newPerRouterTrieMap.set(id, perRouterTrie);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Commit all local state to the shared discovery state atomically.
|
|
329
|
+
// This ensures a failed re-discovery (e.g. from a transient module
|
|
330
|
+
// evaluation error) preserves the last known-good state.
|
|
331
|
+
state.mergedRouteManifest = newMergedRouteManifest;
|
|
332
|
+
state.mergedPrecomputedEntries = newMergedPrecomputedEntries;
|
|
333
|
+
state.perRouterManifests = newPerRouterManifests;
|
|
334
|
+
state.perRouterManifestDataMap = newPerRouterManifestDataMap;
|
|
335
|
+
state.perRouterPrecomputedMap = newPerRouterPrecomputedMap;
|
|
336
|
+
state.perRouterTrieMap = newPerRouterTrieMap;
|
|
337
|
+
state.mergedRouteTrie = newMergedRouteTrie;
|
|
338
|
+
|
|
339
|
+
// Expand prerender routes and render static handlers (build mode only)
|
|
340
|
+
await expandPrerenderRoutes(state, rscEnv, registry, allManifests);
|
|
341
|
+
await renderStaticHandlers(state, rscEnv, registry);
|
|
342
|
+
|
|
343
|
+
return serverMod;
|
|
344
|
+
}
|