@rangojs/router 0.0.0-experimental.20 → 0.0.0-experimental.204030a9

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 (293) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +242 -55
  3. package/dist/bin/rango.js +277 -99
  4. package/dist/vite/index.js +2929 -1132
  5. package/dist/vite/index.js.bak +5448 -0
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +68 -21
  8. package/skills/breadcrumbs/SKILL.md +252 -0
  9. package/skills/bundle-analysis/SKILL.md +159 -0
  10. package/skills/cache-guide/SKILL.md +243 -21
  11. package/skills/caching/SKILL.md +159 -10
  12. package/skills/composability/SKILL.md +27 -2
  13. package/skills/document-cache/SKILL.md +78 -55
  14. package/skills/handler-use/SKILL.md +364 -0
  15. package/skills/hooks/SKILL.md +262 -51
  16. package/skills/host-router/SKILL.md +243 -0
  17. package/skills/i18n/SKILL.md +276 -0
  18. package/skills/intercept/SKILL.md +46 -4
  19. package/skills/layout/SKILL.md +28 -7
  20. package/skills/links/SKILL.md +249 -17
  21. package/skills/loader/SKILL.md +291 -31
  22. package/skills/middleware/SKILL.md +49 -12
  23. package/skills/migrate-nextjs/SKILL.md +562 -0
  24. package/skills/migrate-react-router/SKILL.md +769 -0
  25. package/skills/mime-routes/SKILL.md +27 -0
  26. package/skills/observability/SKILL.md +137 -0
  27. package/skills/parallel/SKILL.md +197 -6
  28. package/skills/prerender/SKILL.md +125 -102
  29. package/skills/rango/SKILL.md +242 -23
  30. package/skills/react-compiler/SKILL.md +168 -0
  31. package/skills/response-routes/SKILL.md +66 -9
  32. package/skills/route/SKILL.md +91 -8
  33. package/skills/router-setup/SKILL.md +98 -8
  34. package/skills/server-actions/SKILL.md +751 -0
  35. package/skills/streams-and-websockets/SKILL.md +283 -0
  36. package/skills/testing/SKILL.md +511 -188
  37. package/skills/typesafety/SKILL.md +354 -50
  38. package/skills/use-cache/SKILL.md +34 -5
  39. package/skills/view-transitions/SKILL.md +294 -0
  40. package/src/__augment-tests__/augment.ts +81 -0
  41. package/src/__augment-tests__/augmented.check.ts +117 -0
  42. package/src/__internal.ts +92 -0
  43. package/src/browser/action-coordinator.ts +53 -36
  44. package/src/browser/app-shell.ts +52 -0
  45. package/src/browser/app-version.ts +14 -0
  46. package/src/browser/event-controller.ts +91 -70
  47. package/src/browser/history-state.ts +21 -0
  48. package/src/browser/index.ts +3 -3
  49. package/src/browser/link-interceptor.ts +4 -0
  50. package/src/browser/navigation-bridge.ts +183 -18
  51. package/src/browser/navigation-client.ts +187 -57
  52. package/src/browser/navigation-store.ts +75 -17
  53. package/src/browser/navigation-transaction.ts +21 -37
  54. package/src/browser/partial-update.ts +143 -40
  55. package/src/browser/prefetch/cache.ts +275 -28
  56. package/src/browser/prefetch/fetch.ts +191 -46
  57. package/src/browser/prefetch/policy.ts +6 -0
  58. package/src/browser/prefetch/queue.ts +123 -20
  59. package/src/browser/prefetch/resource-ready.ts +77 -0
  60. package/src/browser/rango-state.ts +53 -13
  61. package/src/browser/react/Link.tsx +98 -14
  62. package/src/browser/react/NavigationProvider.tsx +110 -33
  63. package/src/browser/react/context.ts +7 -2
  64. package/src/browser/react/filter-segment-order.ts +51 -7
  65. package/src/browser/react/index.ts +3 -0
  66. package/src/browser/react/location-state-shared.ts +175 -4
  67. package/src/browser/react/location-state.ts +39 -13
  68. package/src/browser/react/use-handle.ts +23 -64
  69. package/src/browser/react/use-navigation.ts +22 -2
  70. package/src/browser/react/use-params.ts +20 -8
  71. package/src/browser/react/use-reverse.ts +106 -0
  72. package/src/browser/react/use-router.ts +43 -10
  73. package/src/browser/react/use-segments.ts +11 -8
  74. package/src/browser/response-adapter.ts +25 -0
  75. package/src/browser/rsc-router.tsx +200 -75
  76. package/src/browser/scroll-restoration.ts +46 -39
  77. package/src/browser/segment-reconciler.ts +36 -9
  78. package/src/browser/segment-structure-assert.ts +2 -2
  79. package/src/browser/server-action-bridge.ts +31 -36
  80. package/src/browser/types.ts +81 -5
  81. package/src/build/collect-fallback-refs.ts +107 -0
  82. package/src/build/generate-manifest.ts +65 -40
  83. package/src/build/generate-route-types.ts +5 -0
  84. package/src/build/index.ts +2 -0
  85. package/src/build/route-trie.ts +69 -26
  86. package/src/build/route-types/codegen.ts +4 -4
  87. package/src/build/route-types/include-resolution.ts +9 -2
  88. package/src/build/route-types/per-module-writer.ts +7 -4
  89. package/src/build/route-types/router-processing.ts +278 -88
  90. package/src/build/route-types/scan-filter.ts +9 -2
  91. package/src/build/route-types/source-scan.ts +118 -0
  92. package/src/build/runtime-discovery.ts +9 -20
  93. package/src/cache/cache-runtime.ts +15 -11
  94. package/src/cache/cache-scope.ts +76 -49
  95. package/src/cache/cf/cf-cache-store.ts +501 -18
  96. package/src/cache/cf/index.ts +5 -1
  97. package/src/cache/document-cache.ts +17 -7
  98. package/src/cache/index.ts +1 -0
  99. package/src/cache/taint.ts +55 -0
  100. package/src/client.rsc.tsx +5 -1
  101. package/src/client.tsx +95 -284
  102. package/src/context-var.ts +72 -2
  103. package/src/debug.ts +2 -2
  104. package/src/decode-loader-results.ts +36 -0
  105. package/src/errors.ts +30 -1
  106. package/src/handle.ts +65 -12
  107. package/src/handles/breadcrumbs.ts +66 -0
  108. package/src/handles/index.ts +1 -0
  109. package/src/host/index.ts +2 -5
  110. package/src/host/router.ts +129 -57
  111. package/src/host/types.ts +31 -2
  112. package/src/host/utils.ts +1 -1
  113. package/src/href-client.ts +140 -20
  114. package/src/index.rsc.ts +15 -40
  115. package/src/index.ts +92 -76
  116. package/src/loader-store.ts +500 -0
  117. package/src/loader.rsc.ts +2 -5
  118. package/src/loader.ts +3 -10
  119. package/src/missing-id-error.ts +68 -0
  120. package/src/outlet-context.ts +1 -1
  121. package/src/prerender/store.ts +57 -15
  122. package/src/prerender.ts +141 -80
  123. package/src/response-utils.ts +37 -0
  124. package/src/reverse.ts +65 -15
  125. package/src/route-content-wrapper.tsx +6 -28
  126. package/src/route-definition/dsl-helpers.ts +435 -260
  127. package/src/route-definition/helper-factories.ts +29 -139
  128. package/src/route-definition/helpers-types.ts +110 -34
  129. package/src/route-definition/index.ts +3 -3
  130. package/src/route-definition/redirect.ts +11 -3
  131. package/src/route-definition/resolve-handler-use.ts +155 -0
  132. package/src/route-definition/use-item-types.ts +32 -0
  133. package/src/route-map-builder.ts +7 -1
  134. package/src/route-types.ts +37 -41
  135. package/src/router/basename.ts +14 -0
  136. package/src/router/content-negotiation.ts +113 -1
  137. package/src/router/error-handling.ts +1 -1
  138. package/src/router/find-match.ts +4 -2
  139. package/src/router/handler-context.ts +105 -39
  140. package/src/router/intercept-resolution.ts +15 -22
  141. package/src/router/lazy-includes.ts +12 -9
  142. package/src/router/loader-resolution.ts +175 -23
  143. package/src/router/logging.ts +5 -2
  144. package/src/router/manifest.ts +31 -16
  145. package/src/router/match-api.ts +129 -193
  146. package/src/router/match-handlers.ts +63 -20
  147. package/src/router/match-middleware/background-revalidation.ts +30 -2
  148. package/src/router/match-middleware/cache-lookup.ts +136 -106
  149. package/src/router/match-middleware/cache-store.ts +54 -10
  150. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  151. package/src/router/match-middleware/segment-resolution.ts +61 -5
  152. package/src/router/match-result.ts +124 -18
  153. package/src/router/metrics.ts +239 -14
  154. package/src/router/middleware-types.ts +61 -31
  155. package/src/router/middleware.ts +226 -124
  156. package/src/router/navigation-snapshot.ts +182 -0
  157. package/src/router/pattern-matching.ts +118 -19
  158. package/src/router/prerender-match.ts +114 -10
  159. package/src/router/preview-match.ts +32 -102
  160. package/src/router/request-classification.ts +286 -0
  161. package/src/router/revalidation.ts +85 -9
  162. package/src/router/route-snapshot.ts +245 -0
  163. package/src/router/router-context.ts +6 -1
  164. package/src/router/router-interfaces.ts +91 -29
  165. package/src/router/router-options.ts +89 -19
  166. package/src/router/router-registry.ts +2 -5
  167. package/src/router/segment-resolution/fresh.ts +240 -23
  168. package/src/router/segment-resolution/helpers.ts +30 -25
  169. package/src/router/segment-resolution/loader-cache.ts +1 -0
  170. package/src/router/segment-resolution/revalidation.ts +483 -289
  171. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  172. package/src/router/segment-wrappers.ts +2 -0
  173. package/src/router/substitute-pattern-params.ts +56 -0
  174. package/src/router/telemetry.ts +99 -0
  175. package/src/router/trie-matching.ts +38 -15
  176. package/src/router/types.ts +9 -0
  177. package/src/router/url-params.ts +49 -0
  178. package/src/router.ts +120 -32
  179. package/src/rsc/handler-context.ts +2 -2
  180. package/src/rsc/handler.ts +524 -370
  181. package/src/rsc/helpers.ts +91 -43
  182. package/src/rsc/index.ts +1 -21
  183. package/src/rsc/loader-fetch.ts +23 -3
  184. package/src/rsc/manifest-init.ts +5 -1
  185. package/src/rsc/origin-guard.ts +28 -10
  186. package/src/rsc/progressive-enhancement.ts +39 -10
  187. package/src/rsc/response-route-handler.ts +46 -53
  188. package/src/rsc/rsc-rendering.ts +69 -89
  189. package/src/rsc/runtime-warnings.ts +9 -10
  190. package/src/rsc/server-action.ts +39 -47
  191. package/src/rsc/ssr-setup.ts +144 -0
  192. package/src/rsc/types.ts +19 -3
  193. package/src/search-params.ts +20 -17
  194. package/src/segment-content-promise.ts +67 -0
  195. package/src/segment-loader-promise.ts +122 -0
  196. package/src/segment-system.tsx +219 -67
  197. package/src/serialize.ts +243 -0
  198. package/src/server/context.ts +285 -63
  199. package/src/server/cookie-store.ts +28 -4
  200. package/src/server/handle-store.ts +19 -0
  201. package/src/server/loader-registry.ts +9 -8
  202. package/src/server/request-context.ts +228 -65
  203. package/src/server.ts +6 -0
  204. package/src/ssr/index.tsx +9 -1
  205. package/src/static-handler.ts +19 -7
  206. package/src/testing/cache-status.ts +166 -0
  207. package/src/testing/collect-handle.ts +63 -0
  208. package/src/testing/dispatch.ts +440 -0
  209. package/src/testing/dom.entry.ts +22 -0
  210. package/src/testing/e2e/fixture.ts +154 -0
  211. package/src/testing/e2e/index.ts +149 -0
  212. package/src/testing/e2e/matchers.ts +51 -0
  213. package/src/testing/e2e/page-helpers.ts +272 -0
  214. package/src/testing/e2e/parity.ts +306 -0
  215. package/src/testing/e2e/server.ts +183 -0
  216. package/src/testing/flight-matchers.ts +104 -0
  217. package/src/testing/flight-runtime.d.ts +21 -0
  218. package/src/testing/flight.entry.ts +22 -0
  219. package/src/testing/flight.ts +182 -0
  220. package/src/testing/generated-routes.ts +223 -0
  221. package/src/testing/index.ts +98 -0
  222. package/src/testing/internal/context.ts +151 -0
  223. package/src/testing/render-route.tsx +536 -0
  224. package/src/testing/run-loader.ts +296 -0
  225. package/src/testing/run-middleware.ts +170 -0
  226. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  227. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  228. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  229. package/src/testing/vitest-stubs/version.ts +5 -0
  230. package/src/testing/vitest.ts +112 -0
  231. package/src/theme/index.ts +4 -13
  232. package/src/types/cache-types.ts +4 -4
  233. package/src/types/global-namespace.ts +39 -26
  234. package/src/types/handler-context.ts +197 -79
  235. package/src/types/index.ts +1 -0
  236. package/src/types/loader-types.ts +41 -15
  237. package/src/types/request-scope.ts +126 -0
  238. package/src/types/route-config.ts +17 -8
  239. package/src/types/route-entry.ts +19 -1
  240. package/src/types/segments.ts +37 -6
  241. package/src/urls/include-helper.ts +34 -67
  242. package/src/urls/index.ts +0 -3
  243. package/src/urls/path-helper-types.ts +50 -9
  244. package/src/urls/path-helper.ts +63 -63
  245. package/src/urls/pattern-types.ts +48 -19
  246. package/src/urls/response-types.ts +25 -22
  247. package/src/urls/type-extraction.ts +26 -116
  248. package/src/urls/urls-function.ts +1 -5
  249. package/src/use-loader.tsx +487 -44
  250. package/src/vite/debug.ts +185 -0
  251. package/src/vite/discovery/bundle-postprocess.ts +63 -91
  252. package/src/vite/discovery/discover-routers.ts +106 -53
  253. package/src/vite/discovery/discovery-errors.ts +194 -0
  254. package/src/vite/discovery/gate-state.ts +171 -0
  255. package/src/vite/discovery/prerender-collection.ts +222 -107
  256. package/src/vite/discovery/route-types-writer.ts +40 -84
  257. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  258. package/src/vite/discovery/state.ts +50 -13
  259. package/src/vite/discovery/virtual-module-codegen.ts +13 -23
  260. package/src/vite/index.ts +10 -3
  261. package/src/vite/plugin-types.ts +111 -72
  262. package/src/vite/plugins/cjs-to-esm.ts +8 -7
  263. package/src/vite/plugins/client-ref-dedup.ts +16 -0
  264. package/src/vite/plugins/client-ref-hashing.ts +28 -5
  265. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  266. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  267. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  268. package/src/vite/plugins/expose-action-id.ts +55 -33
  269. package/src/vite/plugins/expose-id-utils.ts +24 -8
  270. package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
  271. package/src/vite/plugins/expose-ids/handler-transform.ts +12 -35
  272. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  273. package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
  274. package/src/vite/plugins/expose-internal-ids.ts +544 -317
  275. package/src/vite/plugins/performance-tracks.ts +92 -0
  276. package/src/vite/plugins/refresh-cmd.ts +127 -0
  277. package/src/vite/plugins/use-cache-transform.ts +65 -50
  278. package/src/vite/plugins/version-injector.ts +39 -23
  279. package/src/vite/plugins/version-plugin.ts +72 -3
  280. package/src/vite/plugins/virtual-entries.ts +2 -2
  281. package/src/vite/rango.ts +265 -226
  282. package/src/vite/router-discovery.ts +924 -137
  283. package/src/vite/utils/ast-handler-extract.ts +15 -15
  284. package/src/vite/utils/banner.ts +4 -4
  285. package/src/vite/utils/bundle-analysis.ts +4 -2
  286. package/src/vite/utils/client-chunks.ts +190 -0
  287. package/src/vite/utils/forward-user-plugins.ts +193 -0
  288. package/src/vite/utils/manifest-utils.ts +21 -5
  289. package/src/vite/utils/package-resolution.ts +41 -1
  290. package/src/vite/utils/prerender-utils.ts +98 -5
  291. package/src/vite/utils/shared-utils.ts +109 -27
  292. package/src/browser/action-response-classifier.ts +0 -99
  293. package/src/route-definition/route-function.ts +0 -119
@@ -20,7 +20,8 @@ export interface TrieLeaf {
20
20
  sp: string;
21
21
  /** Ancestry shortCodes from root to route [M0L0, M0L0L0, M0L0L0R499] */
22
22
  a: string[];
23
- /** Optional param names (absent params get empty string value) */
23
+ /** Optional param names declared on the route. Absent params are
24
+ * omitted from the matched params record (read as `undefined`). */
24
25
  op?: string[];
25
26
  /** Constraint validation: paramName -> allowed values */
26
27
  cv?: Record<string, string[]>;
@@ -47,6 +48,8 @@ export interface TrieNode {
47
48
  s?: Record<string, TrieNode>;
48
49
  /** Param child: { n: paramName, c: child node } */
49
50
  p?: { n: string; c: TrieNode };
51
+ /** Suffix-param children keyed by suffix (e.g., ".html" → { n: "productId", c: ... }) */
52
+ xp?: Record<string, { n: string; c: TrieNode }>;
50
53
  /** Wildcard terminal: leaf + paramName */
51
54
  w?: TrieLeaf & { pn: string };
52
55
  }
@@ -96,8 +99,14 @@ export function buildRouteTrie(
96
99
  }
97
100
 
98
101
  /**
99
- * Insert a route into the trie, handling optional params by forking
100
- * the insertion path (one terminal without the param, one with).
102
+ * Insert a route into the trie. Optional params expand into two branches at
103
+ * registration time (skip-first, then present), so each terminal lives at the
104
+ * correct depth for its number of bound params and carries a branch-local
105
+ * `pa` listing only those names. The trie's single-slot `node.p` is reused
106
+ * across branches because matching ignores `node.p.n` — the leaf's `pa` is
107
+ * the source of truth for naming. Skip-first ordering lets `mergeLeaf`'s
108
+ * last-wins rule produce greedy-leftmost semantics for free at any shared
109
+ * terminal depth.
101
110
  */
102
111
  function insertRoute(
103
112
  node: TrieNode,
@@ -105,14 +114,13 @@ function insertRoute(
105
114
  index: number,
106
115
  leaf: Omit<TrieLeaf, "op" | "cv" | "pa">,
107
116
  ): void {
108
- // Collect param names, optional param names, and constraints across all segments
109
- const paramNames: string[] = [];
117
+ // op (full optional list) and cv (full constraint map) are route-level and
118
+ // identical on every terminal, so compute them once on the shared base.
110
119
  const optionalParams: string[] = [];
111
120
  const constraints: Record<string, string[]> = {};
112
121
 
113
122
  for (const seg of segments) {
114
123
  if (seg.type === "param") {
115
- paramNames.push(seg.value);
116
124
  if (seg.optional) {
117
125
  optionalParams.push(seg.value);
118
126
  }
@@ -122,21 +130,15 @@ function insertRoute(
122
130
  }
123
131
  }
124
132
 
125
- const fullLeaf: TrieLeaf = {
133
+ const leafBase: Omit<TrieLeaf, "pa"> = {
126
134
  ...leaf,
127
- ...(paramNames.length > 0 ? { pa: paramNames } : {}),
128
135
  ...(optionalParams.length > 0 ? { op: optionalParams } : {}),
129
136
  ...(Object.keys(constraints).length > 0 ? { cv: constraints } : {}),
130
137
  };
131
138
 
132
- insertSegments(node, segments, index, fullLeaf);
139
+ insertSegments(node, segments, index, leafBase, []);
133
140
  }
134
141
 
135
- /**
136
- * Recursively insert segments into the trie.
137
- * For optional params, we add a terminal at the current node (param absent)
138
- * AND continue inserting into the param child (param present).
139
- */
140
142
  /**
141
143
  * Extract ancestry map from a built trie by visiting all leaf nodes.
142
144
  * Returns { routeName: ancestryShortCodes[] } for every route in the trie.
@@ -158,6 +160,11 @@ export function extractAncestryFromTrie(
158
160
  visit(child);
159
161
  }
160
162
  }
163
+ if (node.xp) {
164
+ for (const child of Object.values(node.xp)) {
165
+ visit(child.c);
166
+ }
167
+ }
161
168
  if (node.p) {
162
169
  visit(node.p.c);
163
170
  }
@@ -211,15 +218,25 @@ function mergeLeaf(node: TrieNode, leaf: TrieLeaf): void {
211
218
  node.r = mergeLeaves(node.r, leaf);
212
219
  }
213
220
 
221
+ function buildLeaf(
222
+ leafBase: Omit<TrieLeaf, "pa">,
223
+ paramNames: string[],
224
+ ): TrieLeaf {
225
+ return paramNames.length > 0
226
+ ? { ...leafBase, pa: [...paramNames] }
227
+ : { ...leafBase };
228
+ }
229
+
214
230
  function insertSegments(
215
231
  node: TrieNode,
216
232
  segments: ParsedSegment[],
217
233
  index: number,
218
- leaf: TrieLeaf,
234
+ leafBase: Omit<TrieLeaf, "pa">,
235
+ paramNames: string[],
219
236
  ): void {
220
- // Base case: all segments consumed, add terminal
237
+ // Base case: all segments consumed, add terminal with branch-local pa
221
238
  if (index >= segments.length) {
222
- mergeLeaf(node, leaf);
239
+ mergeLeaf(node, buildLeaf(leafBase, paramNames));
223
240
  return;
224
241
  }
225
242
 
@@ -228,20 +245,46 @@ function insertSegments(
228
245
  if (segment.type === "static") {
229
246
  if (!node.s) node.s = {};
230
247
  if (!node.s[segment.value]) node.s[segment.value] = {};
231
- insertSegments(node.s[segment.value], segments, index + 1, leaf);
248
+ insertSegments(
249
+ node.s[segment.value],
250
+ segments,
251
+ index + 1,
252
+ leafBase,
253
+ paramNames,
254
+ );
232
255
  } else if (segment.type === "param") {
233
256
  if (segment.optional) {
234
- // Optional param: add terminal at current node (param absent)
235
- mergeLeaf(node, leaf);
236
- // AND continue with param child (param present)
257
+ // SKIP first: continue at the same node without binding this name.
258
+ // Skip-first ordering means the present-branch's TAKE overwrites any
259
+ // shared terminal later, giving greedy-leftmost semantics.
260
+ insertSegments(node, segments, index + 1, leafBase, paramNames);
237
261
  }
238
- if (!node.p) {
239
- node.p = { n: segment.value, c: {} };
262
+ if (segment.suffix) {
263
+ // Suffix param: keyed by suffix string (e.g., ".html")
264
+ if (!node.xp) node.xp = {};
265
+ if (!node.xp[segment.suffix]) {
266
+ node.xp[segment.suffix] = { n: segment.value, c: {} };
267
+ }
268
+ insertSegments(node.xp[segment.suffix].c, segments, index + 1, leafBase, [
269
+ ...paramNames,
270
+ segment.value,
271
+ ]);
272
+ } else {
273
+ if (!node.p) {
274
+ node.p = { n: segment.value, c: {} };
275
+ }
276
+ insertSegments(node.p.c, segments, index + 1, leafBase, [
277
+ ...paramNames,
278
+ segment.value,
279
+ ]);
240
280
  }
241
- insertSegments(node.p.c, segments, index + 1, leaf);
242
281
  } else if (segment.type === "wildcard") {
243
- // Wildcard consumes all remaining segments
244
- const wildLeaf = { ...leaf, pn: "*" };
282
+ // Wildcard consumes all remaining segments. Carry any params bound before
283
+ // the wildcard in pa so they zip correctly against paramValues at match.
284
+ const wildLeaf: TrieLeaf & { pn: string } = {
285
+ ...buildLeaf(leafBase, paramNames),
286
+ pn: "*",
287
+ };
245
288
  const existing = node.w ? ({ ...node.w } as TrieLeaf) : undefined;
246
289
  const merged = mergeLeaves(existing, wildLeaf);
247
290
  node.w = merged as TrieLeaf & { pn: string };
@@ -23,7 +23,7 @@ export function generatePerModuleTypesSource(
23
23
  const valid = routes.filter(({ name }) => {
24
24
  if (!name || /["'\\`\n\r]/.test(name)) {
25
25
  console.warn(
26
- `[rsc-router] Skipping route with invalid name: ${JSON.stringify(name)}`,
26
+ `[rango] Skipping route with invalid name: ${JSON.stringify(name)}`,
27
27
  );
28
28
  return false;
29
29
  }
@@ -42,7 +42,7 @@ export function generatePerModuleTypesSource(
42
42
  for (const { name, pattern, params, search } of valid) {
43
43
  if (deduped.has(name)) {
44
44
  console.warn(
45
- `[rsc-router] Duplicate route name "${name}" — keeping first definition`,
45
+ `[rango] Duplicate route name "${name}" — keeping first definition`,
46
46
  );
47
47
  continue;
48
48
  }
@@ -59,7 +59,7 @@ export function generatePerModuleTypesSource(
59
59
  }
60
60
 
61
61
  /**
62
- * Generates a .ts file that augments RSCRouter.GeneratedRouteMap
62
+ * Generates a .ts file that augments Rango.GeneratedRouteMap
63
63
  * with route name -> pattern mappings. This enables Handler<"routeName">
64
64
  * without circular references since the file has no imports from the app.
65
65
  */
@@ -94,7 +94,7 @@ ${objectBody}
94
94
  } as const;
95
95
 
96
96
  declare global {
97
- namespace RSCRouter {
97
+ namespace Rango {
98
98
  interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
99
99
  }
100
100
  }
@@ -357,12 +357,17 @@ function buildRouteMapFromBlock(
357
357
  /**
358
358
  * Build route map and search schemas together.
359
359
  * Internal helper used by the include resolution path.
360
+ *
361
+ * @param inlineBlock - Optional pre-extracted code block (e.g. from an inline
362
+ * builder function). When provided, variableName is ignored and the block
363
+ * is parsed directly for path()/include() calls.
360
364
  */
361
365
  export function buildCombinedRouteMapWithSearch(
362
366
  filePath: string,
363
367
  variableName?: string,
364
368
  visited?: Set<string>,
365
369
  diagnosticsOut?: UnresolvableInclude[],
370
+ inlineBlock?: string,
366
371
  ): {
367
372
  routes: Record<string, string>;
368
373
  searchSchemas: Record<string, Record<string, string>>;
@@ -371,7 +376,7 @@ export function buildCombinedRouteMapWithSearch(
371
376
  const realPath = resolve(filePath);
372
377
  const key = variableName ? `${realPath}:${variableName}` : realPath;
373
378
  if (visited.has(key)) {
374
- console.warn(`[rsc-router] Circular include detected, skipping: ${key}`);
379
+ console.warn(`[rango] Circular include detected, skipping: ${key}`);
375
380
  return { routes: {}, searchSchemas: {} };
376
381
  }
377
382
  visited.add(key);
@@ -384,7 +389,9 @@ export function buildCombinedRouteMapWithSearch(
384
389
  }
385
390
 
386
391
  let block: string;
387
- if (variableName) {
392
+ if (inlineBlock) {
393
+ block = inlineBlock;
394
+ } else if (variableName) {
388
395
  const extracted = extractUrlsBlockForVariable(source, variableName);
389
396
  if (!extracted) return { routes: {}, searchSchemas: {} };
390
397
  block = extracted;
@@ -97,7 +97,10 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
97
97
  routes = extractRoutesFromSource(source);
98
98
  }
99
99
 
100
- const genPath = filePath.replace(/\.(tsx?)$/, ".gen.ts");
100
+ // Match .ts/.tsx/.js/.jsx (same as router-processing.ts / router-transform.ts).
101
+ // Without the jsx? branch a .jsx/.js source produced genPath === filePath,
102
+ // overwriting the source file instead of writing a sibling .gen.ts.
103
+ const genPath = filePath.replace(/\.(tsx?|jsx?)$/, ".gen.ts");
101
104
 
102
105
  // When a urls() variable was found but static resolution yields zero
103
106
  // routes, write an empty placeholder so generated imports stay
@@ -106,7 +109,7 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
106
109
  if (varNames.length > 0 && !existsSync(genPath)) {
107
110
  writeFileSync(genPath, generatePerModuleTypesSource([]));
108
111
  console.log(
109
- `[rsc-router] Generated route types (placeholder) -> ${genPath}`,
112
+ `[rango] Generated route types (placeholder) -> ${genPath}`,
110
113
  );
111
114
  }
112
115
  return;
@@ -118,11 +121,11 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
118
121
  : null;
119
122
  if (existing !== genSource) {
120
123
  writeFileSync(genPath, genSource);
121
- console.log(`[rsc-router] Generated route types -> ${genPath}`);
124
+ console.log(`[rango] Generated route types -> ${genPath}`);
122
125
  }
123
126
  } catch (err) {
124
127
  console.warn(
125
- `[rsc-router] Failed to generate route types for ${filePath}: ${(err as Error).message}`,
128
+ `[rango] Failed to generate route types for ${filePath}: ${(err as Error).message}`,
126
129
  );
127
130
  }
128
131
  }