@rangojs/router 0.26.6 → 0.28.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.
Files changed (234) hide show
  1. package/dist/bin/rango.js +1 -1
  2. package/dist/types/__internal.d.ts +7 -1
  3. package/dist/types/browser/action-coordinator.d.ts +0 -4
  4. package/dist/types/browser/action-fence.d.ts +11 -3
  5. package/dist/types/browser/event-controller.d.ts +20 -1
  6. package/dist/types/browser/history-state.d.ts +7 -9
  7. package/dist/types/browser/intercept-utils.d.ts +23 -0
  8. package/dist/types/browser/navigation-store.d.ts +8 -6
  9. package/dist/types/browser/react/filter-segment-order.d.ts +2 -2
  10. package/dist/types/browser/rsc-router.d.ts +1 -1
  11. package/dist/types/browser/segment-reconciler.d.ts +6 -4
  12. package/dist/types/browser/types.d.ts +2 -1
  13. package/dist/types/browser/wire-protocol.d.ts +25 -0
  14. package/dist/types/cache/cache-key-utils.d.ts +11 -5
  15. package/dist/types/cache/cache-scope.d.ts +34 -22
  16. package/dist/types/cache/cf/cf-cache-constants.d.ts +2 -2
  17. package/dist/types/cache/cf/cf-cache-store.d.ts +47 -65
  18. package/dist/types/cache/cf/cf-kv-utils.d.ts +1 -1
  19. package/dist/types/cache/handle-snapshot.d.ts +9 -4
  20. package/dist/types/cache/segment-codec.d.ts +14 -0
  21. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  22. package/dist/types/cache/tag-invalidation.d.ts +10 -0
  23. package/dist/types/cache/taint.d.ts +5 -3
  24. package/dist/types/cache/types.d.ts +7 -3
  25. package/dist/types/cache/vercel/vercel-cache-store.d.ts +8 -6
  26. package/dist/types/prefetch-markers.d.ts +4 -6
  27. package/dist/types/prerender/store.d.ts +31 -0
  28. package/dist/types/prerender/warm-request.d.ts +3 -3
  29. package/dist/types/prerender.d.ts +2 -2
  30. package/dist/types/route-name.d.ts +5 -0
  31. package/dist/types/router/error-handling.d.ts +4 -4
  32. package/dist/types/router/instrument.d.ts +4 -3
  33. package/dist/types/router/intercept-resolution.d.ts +25 -9
  34. package/dist/types/router/match-context.d.ts +12 -11
  35. package/dist/types/router/match-handlers.d.ts +2 -6
  36. package/dist/types/router/match-middleware/background-revalidation.d.ts +10 -20
  37. package/dist/types/router/match-middleware/cache-lookup.d.ts +35 -87
  38. package/dist/types/router/match-middleware/cache-store.d.ts +2 -2
  39. package/dist/types/router/match-middleware/segment-resolution.d.ts +8 -6
  40. package/dist/types/router/prerender-match.d.ts +21 -6
  41. package/dist/types/router/preview-match.d.ts +2 -7
  42. package/dist/types/router/request-classification.d.ts +5 -0
  43. package/dist/types/router/revalidation.d.ts +6 -1
  44. package/dist/types/router/router-context.d.ts +9 -63
  45. package/dist/types/router/router-interfaces.d.ts +8 -14
  46. package/dist/types/router/segment-resolution/loader-cache.d.ts +3 -3
  47. package/dist/types/router/segment-resolution/loader-mask.d.ts +4 -4
  48. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +20 -18
  49. package/dist/types/router/segment-resolution/resolution-pass.d.ts +93 -0
  50. package/dist/types/router/segment-resolution/revalidation.d.ts +82 -31
  51. package/dist/types/router/segment-resolution.d.ts +1 -2
  52. package/dist/types/router/segment-wrappers.d.ts +11 -48
  53. package/dist/types/router/telemetry.d.ts +2 -0
  54. package/dist/types/router/types.d.ts +10 -0
  55. package/dist/types/rsc/full-payload.d.ts +2 -2
  56. package/dist/types/rsc/handler-context.d.ts +6 -6
  57. package/dist/types/rsc/json-route-result.d.ts +5 -9
  58. package/dist/types/rsc/request-stages.d.ts +203 -0
  59. package/dist/types/rsc/response-cache-serve.d.ts +7 -12
  60. package/dist/types/rsc/response-route-handler.d.ts +2 -2
  61. package/dist/types/rsc/routine-plan.d.ts +1 -1
  62. package/dist/types/rsc/server-action.d.ts +2 -2
  63. package/dist/types/rsc/shell-capture-constants.d.ts +2 -2
  64. package/dist/types/rsc/shell-capture.d.ts +132 -15
  65. package/dist/types/rsc/shell-serve.d.ts +37 -12
  66. package/dist/types/server/context.d.ts +9 -8
  67. package/dist/types/server/handle-store.d.ts +16 -0
  68. package/dist/types/server/render-pass.d.ts +72 -0
  69. package/dist/types/server/request-context.d.ts +24 -104
  70. package/dist/types/server/rewrite-trail.d.ts +2 -2
  71. package/dist/types/testing/dispatch.d.ts +35 -18
  72. package/dist/types/testing/serve-shell-request.d.ts +7 -0
  73. package/dist/types/types/cache-types.d.ts +6 -3
  74. package/dist/types/types/error-types.d.ts +9 -1
  75. package/dist/types/types/handler-context.d.ts +18 -7
  76. package/dist/types/types/segments.d.ts +1 -1
  77. package/dist/types/vite/discovery/build-discovery-phase.d.ts +40 -0
  78. package/dist/types/vite/discovery/build-env.d.ts +22 -0
  79. package/dist/types/vite/discovery/bundle-scan-phase.d.ts +12 -0
  80. package/dist/types/vite/discovery/dev-prerender-cache.d.ts +3 -2
  81. package/dist/types/vite/discovery/dev-server-phase.d.ts +26 -0
  82. package/dist/types/vite/discovery/discovery-errors.d.ts +1 -1
  83. package/dist/types/vite/discovery/state.d.ts +12 -0
  84. package/dist/types/vite/plugins/version-plugin.d.ts +1 -1
  85. package/dist/types/vite/plugins/virtual-entries.d.ts +1 -1
  86. package/dist/types/vite/router-discovery.d.ts +8 -47
  87. package/dist/types/vite/temp-rsc-server.d.ts +39 -0
  88. package/dist/types/vite/utils/prerender-utils.d.ts +9 -0
  89. package/dist/types/wire-params.d.ts +34 -0
  90. package/dist/vite/index.js +3809 -3710
  91. package/package.json +1 -1
  92. package/skills/cache-guide/SKILL.md +8 -5
  93. package/skills/caching/SKILL.md +37 -18
  94. package/skills/client-urls/SKILL.md +2 -1
  95. package/skills/document-cache/SKILL.md +18 -1
  96. package/skills/handler-use/SKILL.md +1 -1
  97. package/skills/intercept/SKILL.md +53 -13
  98. package/skills/layout/SKILL.md +11 -7
  99. package/skills/loader/SKILL.md +30 -13
  100. package/skills/middleware/SKILL.md +19 -1
  101. package/skills/migrate-nextjs/SKILL.md +5 -4
  102. package/skills/parallel/SKILL.md +5 -4
  103. package/skills/ppr/SKILL.md +19 -3
  104. package/skills/prerender/SKILL.md +39 -15
  105. package/skills/rango/SKILL.md +23 -11
  106. package/skills/server-actions/SKILL.md +51 -6
  107. package/skills/testing/predicates.md +1 -1
  108. package/skills/testing/response-routes.md +6 -4
  109. package/skills/testing/serve-shell-request.md +7 -7
  110. package/skills/use-cache/SKILL.md +46 -8
  111. package/skills/ux-architecture/SKILL.md +3 -2
  112. package/src/__internal.ts +7 -1
  113. package/src/browser/action-coordinator.ts +2 -13
  114. package/src/browser/action-fence.ts +11 -3
  115. package/src/browser/connection-warmup.ts +3 -1
  116. package/src/browser/event-controller.ts +42 -3
  117. package/src/browser/history-state.ts +15 -13
  118. package/src/browser/intercept-utils.ts +51 -0
  119. package/src/browser/navigation-bridge.ts +34 -30
  120. package/src/browser/navigation-client.ts +21 -33
  121. package/src/browser/navigation-store.ts +25 -27
  122. package/src/browser/navigation-transaction.ts +7 -11
  123. package/src/browser/partial-update.ts +8 -0
  124. package/src/browser/prefetch/cache.ts +2 -1
  125. package/src/browser/prefetch/fetch.ts +8 -16
  126. package/src/browser/prefetch/queue.ts +4 -4
  127. package/src/browser/react/NavigationProvider.tsx +2 -1
  128. package/src/browser/react/filter-segment-order.ts +2 -2
  129. package/src/browser/rsc-router.tsx +17 -2
  130. package/src/browser/segment-reconciler.ts +66 -53
  131. package/src/browser/server-action-bridge.ts +265 -127
  132. package/src/browser/types.ts +2 -1
  133. package/src/browser/wire-protocol.ts +41 -0
  134. package/src/cache/cache-key-utils.ts +11 -5
  135. package/src/cache/cache-runtime.ts +110 -50
  136. package/src/cache/cache-scope.ts +110 -64
  137. package/src/cache/cf/cf-cache-constants.ts +2 -2
  138. package/src/cache/cf/cf-cache-store.ts +486 -874
  139. package/src/cache/cf/cf-kv-utils.ts +1 -1
  140. package/src/cache/document-cache.ts +42 -15
  141. package/src/cache/handle-snapshot.ts +19 -7
  142. package/src/cache/segment-codec.ts +55 -0
  143. package/src/cache/shell-snapshot.ts +2 -2
  144. package/src/cache/tag-invalidation.ts +21 -2
  145. package/src/cache/taint.ts +5 -3
  146. package/src/cache/types.ts +7 -3
  147. package/src/cache/vercel/vercel-cache-store.ts +243 -310
  148. package/src/handles/pushed-by.ts +1 -1
  149. package/src/prefetch-markers.ts +4 -7
  150. package/src/prerender/store.ts +76 -0
  151. package/src/prerender/warm-request.ts +8 -4
  152. package/src/prerender.ts +2 -2
  153. package/src/route-name.ts +8 -0
  154. package/src/router/error-handling.ts +4 -4
  155. package/src/router/instrument.ts +4 -3
  156. package/src/router/intercept-resolution.ts +77 -75
  157. package/src/router/loader-resolution.ts +5 -4
  158. package/src/router/match-api.ts +4 -5
  159. package/src/router/match-context.ts +33 -12
  160. package/src/router/match-handlers.ts +8 -20
  161. package/src/router/match-middleware/background-revalidation.ts +41 -53
  162. package/src/router/match-middleware/cache-lookup.ts +680 -720
  163. package/src/router/match-middleware/cache-store.ts +14 -12
  164. package/src/router/match-middleware/intercept-resolution.ts +3 -23
  165. package/src/router/match-middleware/segment-resolution.ts +34 -61
  166. package/src/router/match-result.ts +1 -20
  167. package/src/router/middleware.ts +69 -11
  168. package/src/router/navigation-snapshot.ts +4 -3
  169. package/src/router/prerender-match.ts +100 -44
  170. package/src/router/preview-match.ts +6 -41
  171. package/src/router/request-classification.ts +13 -7
  172. package/src/router/revalidation.ts +33 -7
  173. package/src/router/route-snapshot.ts +2 -5
  174. package/src/router/router-context.ts +14 -117
  175. package/src/router/router-interfaces.ts +8 -14
  176. package/src/router/segment-resolution/loader-cache.ts +14 -9
  177. package/src/router/segment-resolution/loader-mask.ts +5 -5
  178. package/src/router/segment-resolution/prefetch-deferral.ts +30 -27
  179. package/src/router/segment-resolution/resolution-pass.ts +137 -0
  180. package/src/router/segment-resolution/revalidation.ts +897 -776
  181. package/src/router/segment-resolution.ts +4 -13
  182. package/src/router/segment-wrappers.ts +51 -269
  183. package/src/router/telemetry.ts +5 -0
  184. package/src/router/types.ts +10 -0
  185. package/src/router.ts +12 -13
  186. package/src/rsc/full-payload.ts +6 -5
  187. package/src/rsc/handler-context.ts +8 -14
  188. package/src/rsc/handler.ts +126 -507
  189. package/src/rsc/json-route-result.ts +5 -9
  190. package/src/rsc/loader-fetch.ts +6 -5
  191. package/src/rsc/progressive-enhancement.ts +5 -0
  192. package/src/rsc/request-stages.ts +757 -0
  193. package/src/rsc/response-cache-serve.ts +10 -14
  194. package/src/rsc/response-route-handler.ts +13 -5
  195. package/src/rsc/rewrite-passes.ts +2 -1
  196. package/src/rsc/routine-plan.ts +1 -1
  197. package/src/rsc/rsc-rendering.ts +172 -349
  198. package/src/rsc/server-action.ts +87 -113
  199. package/src/rsc/shell-capture-constants.ts +3 -1
  200. package/src/rsc/shell-capture.ts +212 -169
  201. package/src/rsc/shell-serve.ts +121 -18
  202. package/src/rsc/ssr-setup.ts +5 -4
  203. package/src/segment-system.tsx +3 -3
  204. package/src/server/context.ts +22 -25
  205. package/src/server/handle-store.ts +55 -0
  206. package/src/server/render-pass.ts +291 -0
  207. package/src/server/request-context.ts +26 -115
  208. package/src/server/rewrite-trail.ts +6 -4
  209. package/src/ssr/index.tsx +1 -1
  210. package/src/ssr/ssr-root.tsx +1 -0
  211. package/src/testing/dispatch.ts +223 -710
  212. package/src/testing/e2e/page-helpers.ts +2 -2
  213. package/src/testing/serve-shell-request.ts +37 -32
  214. package/src/types/cache-types.ts +6 -3
  215. package/src/types/error-types.ts +9 -1
  216. package/src/types/handler-context.ts +21 -7
  217. package/src/types/segments.ts +1 -1
  218. package/src/vite/discovery/build-discovery-phase.ts +204 -0
  219. package/src/vite/discovery/build-env.ts +148 -0
  220. package/src/vite/discovery/bundle-scan-phase.ts +128 -0
  221. package/src/vite/discovery/dev-prerender-cache.ts +8 -3
  222. package/src/vite/discovery/dev-server-phase.ts +1776 -0
  223. package/src/vite/discovery/discover-routers.ts +1 -1
  224. package/src/vite/discovery/discovery-errors.ts +1 -1
  225. package/src/vite/discovery/prerender-collection.ts +24 -39
  226. package/src/vite/discovery/state.ts +15 -0
  227. package/src/vite/plugins/version-plugin.ts +1 -1
  228. package/src/vite/plugins/virtual-entries.ts +1 -1
  229. package/src/vite/router-discovery.ts +29 -2428
  230. package/src/vite/temp-rsc-server.ts +223 -0
  231. package/src/vite/utils/prerender-utils.ts +47 -0
  232. package/src/wire-params.ts +35 -0
  233. package/dist/types/router/segment-resolution/fresh.d.ts +0 -72
  234. package/src/router/segment-resolution/fresh.ts +0 -945
@@ -0,0 +1,223 @@
1
+ /**
2
+ * The discovery temp RSC server: a minimal Vite server whose module runner
3
+ * imports the user's router files. Shared by dev discovery
4
+ * (discovery/dev-server-phase.ts) and build discovery
5
+ * (discovery/build-discovery-phase.ts).
6
+ *
7
+ * Sits in src/vite/, not src/vite/discovery/: the loader hook URL below
8
+ * resolves against this module's import.meta.url, and the published bundle
9
+ * (dist/vite/index.js) ships the hook at the same relative path.
10
+ */
11
+
12
+ import type { ViteDevServer } from "vite";
13
+ import { createServer as createViteServer } from "vite";
14
+ import { register } from "node:module";
15
+ import { createVersionPlugin } from "./plugins/version-plugin.js";
16
+ import { getVirtualEntrySSR } from "./plugins/virtual-entries.js";
17
+ import { createVirtualStubPlugin } from "./plugins/virtual-stub-plugin.js";
18
+ import { createCloudflareProtocolStubPlugin } from "./plugins/cloudflare-protocol-stub.js";
19
+ import {
20
+ exposeInternalIds,
21
+ exposeRouterId,
22
+ } from "./plugins/expose-internal-ids.js";
23
+ import { hashClientRefs } from "./plugins/client-ref-hashing.js";
24
+ import { hashServerRefs } from "./plugins/server-ref-hashing.js";
25
+ import { defineEncryptionKeyExpr } from "./encryption-key.js";
26
+ import type { DiscoveryState } from "./discovery/state.js";
27
+ import { recordClientUrlsModule } from "./discovery/client-urls-projection.js";
28
+ import { transitionWhenHoistPlugin } from "./plugins/transition-when-hoist.js";
29
+ import { clientUrlsRevalidateHoistPlugin } from "./plugins/client-urls-revalidate-hoist.js";
30
+
31
+ // ============================================================================
32
+ // Node ESM Loader Hook Registration
33
+ // ============================================================================
34
+
35
+ /**
36
+ * Registers a Node ESM loader hook that resolves `cloudflare:*` specifiers
37
+ * to a data: URL stub. Defense-in-depth alongside the Vite transform in
38
+ * `cloudflare-protocol-stub.ts`:
39
+ *
40
+ * - The Vite transform catches `cloudflare:*` imports in modules that flow
41
+ * through Vite's plugin pipeline. That's the vast majority of cases.
42
+ * - The Node loader catches imports in modules that Vite/Rollup externalize
43
+ * (e.g. the `partyserver` package, which has a top-level
44
+ * `import { DurableObject, env } from "cloudflare:workers"` and ships
45
+ * shapes plugin-rsc marks as external). Externalized modules are loaded
46
+ * via Node's native ESM loader, which rejects URL schemes.
47
+ *
48
+ * Registration is process-global and one-shot. The hook only intercepts
49
+ * `cloudflare:*` specifiers; everything else passes through via
50
+ * `nextResolve()`. It runs in a separate worker thread (Node ESM loader
51
+ * architecture), so it can't read the `globalThis[BUILD_ENV_GLOBAL_KEY]`
52
+ * bridge that the Vite transform uses — the stubs served here always
53
+ * return `env = {}`. That's fine because externalized libraries don't
54
+ * typically access `env` at module top level; user source (where real
55
+ * `env` matters at build time) flows through the Vite transform.
56
+ */
57
+ let loaderHookRegistered = false;
58
+ function ensureCloudflareProtocolLoaderRegistered(): void {
59
+ if (loaderHookRegistered) return;
60
+ loaderHookRegistered = true;
61
+ try {
62
+ register(
63
+ new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url),
64
+ );
65
+ } catch (err: any) {
66
+ // register() requires Node 18.19+ / 20.6+. Older Node still has the
67
+ // Vite transform as primary defense.
68
+ console.warn(
69
+ `[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`,
70
+ );
71
+ }
72
+ }
73
+
74
+ // ============================================================================
75
+ // Temp Server Factory
76
+ // ============================================================================
77
+
78
+ /**
79
+ * Create a minimal Vite server for router discovery.
80
+ *
81
+ * Both dev-mode prerender and build-mode discovery need a temp RSC server
82
+ * to import user router files via module runner. This factory centralizes
83
+ * the shared config and the mode-specific differences:
84
+ * - Dev: path-based IDs (no forceBuild), separate cacheDir
85
+ * - Build: hashed IDs (forceBuild), hashClientRefs for production bundles
86
+ *
87
+ * Returns the ViteDevServer instance. Callers access .environments.rsc as needed.
88
+ * @internal Exported for tests.
89
+ */
90
+ export async function createTempRscServer(
91
+ state: DiscoveryState,
92
+ options: {
93
+ forceBuild?: boolean;
94
+ cacheDir?: string;
95
+ /**
96
+ * Serve the REAL rango SSR entry (getVirtualEntrySSR) for
97
+ * "virtual:entry-ssr" instead of the discovery stub, so the dev
98
+ * /__rsc_shell endpoint can drive captureShellHTML in this server's SSR
99
+ * realm. Dev-correct by construction: the entry's bootstrap resolves to
100
+ * plugin-rsc's stable virtual browser-entry URL, which the MAIN dev
101
+ * server serves to the browser. Loaded lazily — discovery never imports
102
+ * the SSR entry, so the temp server stays as light as before until a
103
+ * shell capture actually runs.
104
+ */
105
+ realSsrEntry?: boolean;
106
+ } = {},
107
+ ): Promise<ViteDevServer> {
108
+ // Install the Node ESM loader hook before any module evaluation so
109
+ // `cloudflare:*` specifiers in externalized/loader-delegated modules
110
+ // (e.g. packages plugin-rsc marks as external) resolve to stubs
111
+ // instead of crashing Node's native loader.
112
+ ensureCloudflareProtocolLoaderRegistered();
113
+ const { default: rsc } = await import("@vitejs/plugin-rsc");
114
+ // Mirror the user's resolution config + plugins so discovery (and the
115
+ // prerender/static rendering that shares this runner) resolves modules the
116
+ // same way the real environment does. Falls back to the legacy alias-only
117
+ // behavior if configResolved hasn't populated the parity slice yet.
118
+ const runnerConfig = state.userRunnerConfig;
119
+ const resolveConfig = runnerConfig?.resolve ?? {
120
+ alias: state.userResolveAlias,
121
+ };
122
+ const oxcConfig = runnerConfig?.oxc ?? {
123
+ jsx: { runtime: "automatic", importSource: "react" },
124
+ };
125
+ return createViteServer({
126
+ root: state.projectRoot,
127
+ configFile: false,
128
+ server: {
129
+ middlewareMode: true,
130
+ // Build mode: no file watching. buildStart installs the per-router tries
131
+ // into this realm and runShellPrerenderPhase reuses it after the bundles
132
+ // are written. A watched write in between (writeRouteTypesFiles' own
133
+ // <router>.named-routes.gen.ts, which every router file imports) can
134
+ // make Vite full-reload the RSC runner; the shell phase then matches in
135
+ // a fresh realm with no tries and a root path("/*") wins (#947).
136
+ ...(options.forceBuild ? { watch: null } : {}),
137
+ },
138
+ appType: "custom",
139
+ logLevel: "silent",
140
+ resolve: resolveConfig,
141
+ ...(runnerConfig?.define ? { define: runnerConfig.define } : {}),
142
+ oxc: oxcConfig as any,
143
+ ...(options.cacheDir && { cacheDir: options.cacheDir }),
144
+ plugins: [
145
+ rsc({
146
+ entries: {
147
+ client: "virtual:entry-client",
148
+ ssr: "virtual:entry-ssr",
149
+ rsc: state.resolvedEntryPath!,
150
+ },
151
+ // The temp server renders Static/Prerender output and encrypts inline-
152
+ // action bound args. Give it the SAME key as the main build/dev runtime
153
+ // (defineEncryptionKeyExpr is process-cached) so those args decrypt at
154
+ // invocation. Unconditional, NOT build-only: under Cloudflare/workerd dev
155
+ // the RSC env has no module runner, so prerender is rendered by THIS temp
156
+ // server (via /__rsc_prerender), and the action decrypts in the main
157
+ // runtime with the rango.ts key -- gating on forceBuild left dev encrypting
158
+ // with the temp server's own random key, failing decryptActionBoundArgs.
159
+ // (hashServerRefs stays build-only: dev keeps dev-style ids the dev runtime
160
+ // resolves directly.)
161
+ defineEncryptionKey: defineEncryptionKeyExpr(),
162
+ }),
163
+ // hashClientRefs/hashServerRefs only in build mode — production bundles
164
+ // need hashed refs. hashServerRefs is the server-side analog: it rewrites
165
+ // registerServerReference dev-style ids to production hashes so a
166
+ // server-created action embedded in prerendered/static Flight resolves
167
+ // against the production manifest on a build-time-cache hit.
168
+ ...(options.forceBuild
169
+ ? [hashClientRefs(state.projectRoot), hashServerRefs(state.projectRoot)]
170
+ : []),
171
+ createVersionPlugin(),
172
+ // Before the stub plugin, so "virtual:entry-ssr" resolves to the real
173
+ // SSR entry when the shell endpoint needs it (see the option doc).
174
+ ...(options.realSsrEntry
175
+ ? [
176
+ {
177
+ name: "@rangojs/router:temp-real-ssr-entry",
178
+ enforce: "pre" as const,
179
+ resolveId(id: string) {
180
+ return id === "virtual:entry-ssr"
181
+ ? "\0rango-temp-real-ssr-entry"
182
+ : null;
183
+ },
184
+ load(id: string) {
185
+ return id === "\0rango-temp-real-ssr-entry"
186
+ ? getVirtualEntrySSR(
187
+ state.opts?.headScripts,
188
+ state.opts?.progressiveChunkSize,
189
+ )
190
+ : null;
191
+ },
192
+ } satisfies import("vite").Plugin,
193
+ ]
194
+ : []),
195
+ createVirtualStubPlugin(),
196
+ createCloudflareProtocolStubPlugin(),
197
+ // Inline transition({ when }) literals become client references here
198
+ // too, or discovery would see (and reject) the plain function.
199
+ transitionWhenHoistPlugin(),
200
+ // clientUrls() revalidate() predicates move to the server here too:
201
+ // discovery serializes the SSR copy's markers and the RSC realm
202
+ // registers the predicates the materialized stubs call. The index is
203
+ // the main plugin's, so its group modules import the files assigned here.
204
+ ...clientUrlsRevalidateHoistPlugin(state.clientUrlRevalidate),
205
+ // Dev prerender must use dev-mode IDs (path-based) to match the workerd
206
+ // runtime. forceBuild produces hashed IDs for production bundle consistency.
207
+ exposeInternalIds(options.forceBuild ? { forceBuild: true } : undefined),
208
+ exposeRouterId(),
209
+ {
210
+ name: "@rangojs/router:client-urls-source-tracking",
211
+ enforce: "pre",
212
+ transform(code, id) {
213
+ recordClientUrlsModule(state, code, id);
214
+ },
215
+ },
216
+ // Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
217
+ // to resolveId/load (plus transform for import rewriters, see
218
+ // IMPORT_REWRITE_PLUGINS) and placed last so framework resolution runs first;
219
+ // Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
220
+ ...state.userResolvePlugins,
221
+ ],
222
+ });
223
+ }
@@ -10,6 +10,8 @@ import {
10
10
  import { resolve } from "node:path";
11
11
 
12
12
  import { escapeRegExp } from "../../regex-escape.js";
13
+ import { localRouteName, publicRouteName } from "../../route-name.js";
14
+ import type { LiveIntercept } from "../../router/prerender-match.js";
13
15
  import { substitutePatternParams } from "../../router/substitute-pattern-params.js";
14
16
  import { encodePathRemainder } from "../../router/url-params.js";
15
17
 
@@ -216,6 +218,51 @@ export function resolvePrerenderError(
216
218
  throw error;
217
219
  }
218
220
 
221
+ /**
222
+ * Warn once per router, route and slot (`warned` holds the keys already
223
+ * warned) that an intercept over a Prerender() route renders live: the build
224
+ * did not bake it (matchForPrerender `liveIntercepts`), so its handler runs
225
+ * per request and one that needs BuildContext fails there. A route in an
226
+ * unnamed include() has an internal key; the warning names its URL instead.
227
+ */
228
+ export function warnLiveIntercepts(
229
+ warned: Set<string>,
230
+ routerId: string,
231
+ routeName: string,
232
+ urlPath: string,
233
+ liveIntercepts: readonly LiveIntercept[] | undefined,
234
+ ): void {
235
+ for (const { slot, reason } of liveIntercepts ?? []) {
236
+ const key = `${routerId} ${routeName} ${slot}`;
237
+ if (warned.has(key)) continue;
238
+ warned.add(key);
239
+ const local = localRouteName(routeName);
240
+ const [why, fix] = {
241
+ "same-slot": [
242
+ `two intercepts on one layout fill ${slot}`,
243
+ "give each intercept its own slot",
244
+ ],
245
+ "handler-response": [
246
+ `its handler returned a Response for ${urlPath}`,
247
+ "return a node from its handler at build time",
248
+ ],
249
+ "layout-response": [
250
+ `its layout returned a Response for ${urlPath}`,
251
+ "return a node from its layout at build time",
252
+ ],
253
+ "local-name": [
254
+ `it targets "${local}", the route's name inside its include()`,
255
+ `declare it inside the include() as ".${local}"`,
256
+ ],
257
+ }[reason];
258
+ console.warn(
259
+ `[rango] Prerender route "${publicRouteName(routeName) ?? urlPath}": intercept ${slot} is not pre-rendered: ${why}. ` +
260
+ `A navigation that selects it renders it live, and its handler runs per request without BuildContext. ` +
261
+ `To pre-render it, ${fix}.`,
262
+ );
263
+ }
264
+ }
265
+
219
266
  /** Build scratch space, relative to the project root. Never shipped. */
220
267
  export const RANGO_BUILD_DIR = "node_modules/.rangojs-router-build";
221
268
 
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The router's `_rsc_*` query parameter names, shared by the browser and the
3
+ * server graph (dependency free): the one module that spells them
4
+ * (tools/check-internals.mjs rule rsc-param-literal). The browser writes the
5
+ * partial-request set through browser/wire-protocol.ts writePartialParams.
6
+ */
7
+ export const WIRE = {
8
+ /** A navigation or prefetch: `true`. */
9
+ partial: "_rsc_partial",
10
+ /** The mounted segment ids, comma-joined. */
11
+ segments: "_rsc_segments",
12
+ /** A JS server action's id, in place of `partial`. */
13
+ action: "_rsc_action",
14
+ /** The client's build version (version-mismatch reload). */
15
+ version: "_rsc_v",
16
+ /** The client's router id (app-switch reload). */
17
+ routerId: "_rsc_rid",
18
+ /** The rewrite target of the page on screen (#1144). */
19
+ rewriteTarget: "_rsc_rt",
20
+ /** A stale request: `true` (router/navigation-snapshot.ts). */
21
+ stale: "_rsc_stale",
22
+ /** A fill request (docs/design/prefetch-false.md): `1`. */
23
+ fill: "_rsc_fill",
24
+ /** A loader fetch's loader id (rsc/loader-fetch.ts). */
25
+ loader: "_rsc_loader",
26
+ /** A loader fetch's params, JSON: a query param, or a form field on a POST. */
27
+ loaderParams: "_rsc_loader_params",
28
+ /** The forced-MISS marker of a degraded PPR shell reload (rsc/shell-serve.ts). */
29
+ shellMiss: "_rsc_shell",
30
+ /** A connection warmup HEAD request (browser/connection-warmup.ts). */
31
+ warmup: "_rsc_warmup",
32
+ } as const;
33
+
34
+ /** The prefix every name in WIRE starts with. */
35
+ export const WIRE_PREFIX = "_rsc_";
@@ -1,72 +0,0 @@
1
- /**
2
- * Fresh Path Segment Resolution
3
- *
4
- * Functions for resolving segments during a full (non-revalidation) request.
5
- * Handles loaders, layouts, routes, parallels, orphan layouts, and error boundaries.
6
- */
7
- import { type EntryData } from "../../server/context";
8
- import type { HandlerContext, ResolvedSegment } from "../../types";
9
- import type { SegmentResolutionDeps } from "../types.js";
10
- /**
11
- * Resolve loaders for an entry and emit segments.
12
- * Loaders are run lazily via ctx.use() and memoized for parallel execution.
13
- */
14
- export declare function resolveLoaders<TEnv>(entry: EntryData, ctx: HandlerContext<any, TEnv>, belongsToRoute: boolean, deps: SegmentResolutionDeps<TEnv>, shortCodeOverride?: string): Promise<ResolvedSegment[]>;
15
- /**
16
- * Options for segment resolution.
17
- */
18
- export interface ResolveSegmentOptions {
19
- /** When true, skip resolveLoaders() calls (used for pre-rendering) */
20
- skipLoaders?: boolean;
21
- /**
22
- * When true, a thrown render error is re-thrown instead of being converted
23
- * into an error-boundary segment. Set only by the pre-render path so a
24
- * build-time render failure (and a `throw new Skip()` inside a render fn)
25
- * surfaces to the build instead of being silently baked into a frozen error
26
- * page served as a 200 (issue #587). The live request path leaves this unset,
27
- * so error boundaries keep catching at request time.
28
- */
29
- throwOnError?: boolean;
30
- /**
31
- * The matched route's full entry chain. resolveAllSegments defaults it to
32
- * its `entries`; withCacheLookup passes it when it resolves only the entries
33
- * above a cache() boundary. An orphan list can hold an entry of the chain: a
34
- * bare cache() marker sits in its layout's layout[] (it wraps that layout's
35
- * routes) and is the parent of the routes after it. For those routes it
36
- * resolves once, as a chain entry, below the cache() header latch (issue
37
- * #918: resolved twice on a MISS, once and discarded on a HIT).
38
- */
39
- chain?: readonly EntryData[];
40
- /**
41
- * The matched chain entry being resolved: where the sync path catches a
42
- * handler error, so a streamed handler (or slot owned by a routeless layout)
43
- * recovers into the same boundary. resolveSegment sets it for the entry it
44
- * resolves; nested resolutions keep the outer value.
45
- */
46
- boundaryEntry?: EntryData;
47
- }
48
- /**
49
- * Resolve segments from EntryData.
50
- * Executes middlewares, loaders, parallels, and handlers in correct order.
51
- * Returns array: [main segment, ...orphan layout segments]
52
- */
53
- export declare function resolveSegment<TEnv>(entry: EntryData, routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, loaderPromises: Map<string, Promise<any>>, deps: SegmentResolutionDeps<TEnv>, isRouteEntry?: boolean, options?: ResolveSegmentOptions): Promise<ResolvedSegment[]>;
54
- /**
55
- * Resolve orphan layout with its middlewares, loaders, and parallels.
56
- */
57
- export declare function resolveOrphanLayout<TEnv>(orphan: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, loaderPromises: Map<string, Promise<any>>, belongsToRoute: boolean, deps: SegmentResolutionDeps<TEnv>, options?: ResolveSegmentOptions, routeKey?: string,
58
- /** Parent route entry — its loaders are inherited by the layout so
59
- * parallel slots inside this layout can access them via useLoader(). */
60
- parentRouteEntry?: EntryData): Promise<ResolvedSegment[]>;
61
- /**
62
- * Resolve parallel EntryData with its loaders and slot handlers.
63
- */
64
- export declare function resolveParallelEntry<TEnv>(parallelEntry: EntryData, params: Record<string, string>, context: HandlerContext<any, TEnv>, belongsToRoute: boolean, parentShortCode: string, deps: SegmentResolutionDeps<TEnv>, options?: ResolveSegmentOptions, routeKey?: string, slotNames?: `@${string}`[], includeLoaders?: boolean): Promise<ResolvedSegment[]>;
65
- /**
66
- * Resolve all segments for a route (used for single-cache-per-request pattern).
67
- */
68
- export declare function resolveAllSegments<TEnv>(entries: EntryData[], routeKey: string, params: Record<string, string>, context: HandlerContext<any, TEnv>, loaderPromises: Map<string, Promise<any>>, deps: SegmentResolutionDeps<TEnv>, options?: ResolveSegmentOptions): Promise<ResolvedSegment[]>;
69
- /**
70
- * Resolve only loader segments for all entries (used when serving cached non-loader segments).
71
- */
72
- export declare function resolveLoadersOnly<TEnv>(entries: EntryData[], context: HandlerContext<any, TEnv>, deps: SegmentResolutionDeps<TEnv>): Promise<ResolvedSegment[]>;