@rangojs/router 0.0.0-experimental.124 → 0.0.0-experimental.126

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 (235) hide show
  1. package/README.md +6 -4
  2. package/dist/bin/rango.js +3 -4
  3. package/dist/vite/index.js +315 -68
  4. package/package.json +19 -18
  5. package/skills/breadcrumbs/SKILL.md +60 -0
  6. package/skills/hooks/SKILL.md +2 -2
  7. package/skills/route/SKILL.md +6 -0
  8. package/skills/server-actions/SKILL.md +25 -1
  9. package/skills/testing/SKILL.md +17 -17
  10. package/skills/testing/cache-prerender.md +29 -3
  11. package/skills/testing/flight.md +13 -10
  12. package/skills/testing/render-handler.md +3 -0
  13. package/skills/testing/server-tree.md +1 -1
  14. package/skills/testing/setup.md +1 -1
  15. package/src/__internal.ts +0 -65
  16. package/src/browser/action-coordinator.ts +1 -1
  17. package/src/browser/action-fence.ts +10 -0
  18. package/src/browser/event-controller.ts +1 -83
  19. package/src/browser/navigation-store-handle.ts +3 -4
  20. package/src/browser/navigation-store.ts +0 -39
  21. package/src/browser/navigation-transaction.ts +0 -32
  22. package/src/browser/partial-update.ts +23 -84
  23. package/src/browser/prefetch/cache.ts +6 -45
  24. package/src/browser/prefetch/queue.ts +6 -3
  25. package/src/browser/rango-state.ts +2 -23
  26. package/src/browser/react/Link.tsx +0 -2
  27. package/src/browser/react/NavigationProvider.tsx +2 -1
  28. package/src/browser/react/ScrollRestoration.tsx +10 -6
  29. package/src/browser/react/filter-segment-order.ts +0 -2
  30. package/src/browser/react/index.ts +0 -45
  31. package/src/browser/react/location-state-shared.ts +0 -13
  32. package/src/browser/react/location-state.ts +0 -1
  33. package/src/browser/react/use-action.ts +6 -15
  34. package/src/browser/react/use-handle.ts +0 -5
  35. package/src/browser/react/use-link-status.ts +0 -4
  36. package/src/browser/react/use-navigation.ts +0 -3
  37. package/src/browser/react/use-params.ts +0 -2
  38. package/src/browser/react/use-router.ts +2 -1
  39. package/src/browser/react/use-search-params.ts +0 -5
  40. package/src/browser/react/use-segments.ts +0 -13
  41. package/src/browser/rsc-router.tsx +10 -3
  42. package/src/browser/server-action-bridge.ts +51 -3
  43. package/src/browser/types.ts +23 -5
  44. package/src/browser/validate-redirect-origin.ts +43 -16
  45. package/src/build/index.ts +8 -9
  46. package/src/build/route-trie.ts +46 -11
  47. package/src/build/route-types/param-extraction.ts +6 -3
  48. package/src/build/route-types/router-processing.ts +0 -8
  49. package/src/cache/cache-policy.ts +0 -54
  50. package/src/cache/cache-runtime.ts +48 -24
  51. package/src/cache/cache-scope.ts +0 -27
  52. package/src/cache/cache-tag.ts +0 -37
  53. package/src/cache/cf/cf-cache-store.ts +72 -45
  54. package/src/cache/cf/index.ts +0 -24
  55. package/src/cache/document-cache.ts +10 -36
  56. package/src/cache/handle-snapshot.ts +0 -40
  57. package/src/cache/index.ts +0 -27
  58. package/src/cache/memory-segment-store.ts +0 -52
  59. package/src/cache/profile-registry.ts +6 -30
  60. package/src/cache/read-through-swr.ts +41 -11
  61. package/src/cache/segment-codec.ts +0 -16
  62. package/src/cache/types.ts +0 -98
  63. package/src/client.rsc.tsx +4 -22
  64. package/src/client.tsx +19 -32
  65. package/src/context-var.ts +12 -0
  66. package/src/defer.ts +196 -0
  67. package/src/deps/ssr.ts +0 -1
  68. package/src/handle.ts +2 -12
  69. package/src/handles/MetaTags.tsx +0 -14
  70. package/src/handles/breadcrumbs.ts +16 -5
  71. package/src/handles/meta.ts +0 -39
  72. package/src/host/cookie-handler.ts +0 -36
  73. package/src/host/errors.ts +0 -24
  74. package/src/host/index.ts +6 -0
  75. package/src/host/pattern-matcher.ts +7 -50
  76. package/src/host/router.ts +1 -65
  77. package/src/host/testing.ts +0 -16
  78. package/src/host/types.ts +6 -2
  79. package/src/href-client.ts +0 -4
  80. package/src/index.rsc.ts +27 -2
  81. package/src/index.ts +7 -0
  82. package/src/internal-debug.ts +2 -4
  83. package/src/loader.rsc.ts +4 -15
  84. package/src/loader.ts +3 -9
  85. package/src/network-error-thrower.tsx +1 -6
  86. package/src/outlet-provider.tsx +1 -5
  87. package/src/prerender/param-hash.ts +10 -11
  88. package/src/prerender/store.ts +23 -30
  89. package/src/prerender.ts +34 -0
  90. package/src/redirect-origin.ts +100 -0
  91. package/src/root-error-boundary.tsx +1 -19
  92. package/src/route-content-wrapper.tsx +1 -44
  93. package/src/route-definition/dsl-helpers.ts +7 -19
  94. package/src/route-definition/helpers-types.ts +3 -3
  95. package/src/route-definition/redirect.ts +43 -9
  96. package/src/route-definition/resolve-handler-use.ts +6 -0
  97. package/src/route-map-builder.ts +0 -16
  98. package/src/router/content-negotiation.ts +0 -13
  99. package/src/router/error-handling.ts +12 -16
  100. package/src/router/find-match.ts +4 -31
  101. package/src/router/intercept-resolution.ts +10 -1
  102. package/src/router/lazy-includes.ts +1 -57
  103. package/src/router/loader-resolution.ts +25 -23
  104. package/src/router/logging.ts +0 -6
  105. package/src/router/manifest.ts +1 -25
  106. package/src/router/match-api.ts +0 -20
  107. package/src/router/match-context.ts +0 -22
  108. package/src/router/match-handlers.ts +0 -43
  109. package/src/router/match-middleware/background-revalidation.ts +0 -7
  110. package/src/router/match-middleware/cache-lookup.ts +96 -179
  111. package/src/router/match-middleware/cache-store.ts +0 -31
  112. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  113. package/src/router/match-middleware/segment-resolution.ts +0 -22
  114. package/src/router/match-pipelines.ts +1 -42
  115. package/src/router/match-result.ts +1 -52
  116. package/src/router/metrics.ts +0 -34
  117. package/src/router/middleware-types.ts +0 -116
  118. package/src/router/middleware.ts +77 -60
  119. package/src/router/navigation-snapshot.ts +0 -51
  120. package/src/router/params-util.ts +23 -0
  121. package/src/router/pattern-matching.ts +5 -56
  122. package/src/router/prerender-match.ts +56 -51
  123. package/src/router/request-classification.ts +1 -38
  124. package/src/router/revalidation.ts +14 -62
  125. package/src/router/route-snapshot.ts +0 -1
  126. package/src/router/router-context.ts +0 -27
  127. package/src/router/router-interfaces.ts +10 -0
  128. package/src/router/segment-resolution/fresh.ts +25 -57
  129. package/src/router/segment-resolution/helpers.ts +34 -0
  130. package/src/router/segment-resolution/loader-cache.ts +35 -23
  131. package/src/router/segment-resolution/revalidation.ts +188 -283
  132. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  133. package/src/router/segment-resolution.ts +4 -1
  134. package/src/router/segment-wrappers.ts +0 -3
  135. package/src/router/telemetry-otel.ts +0 -20
  136. package/src/router/telemetry.ts +0 -22
  137. package/src/router/timeout.ts +0 -20
  138. package/src/router/trie-matching.ts +66 -45
  139. package/src/router/types.ts +1 -63
  140. package/src/router/url-params.ts +0 -5
  141. package/src/router.ts +8 -11
  142. package/src/rsc/handler-context.ts +1 -0
  143. package/src/rsc/handler.ts +20 -4
  144. package/src/rsc/helpers.ts +71 -3
  145. package/src/rsc/json-route-result.ts +38 -0
  146. package/src/rsc/origin-guard.ts +9 -15
  147. package/src/rsc/progressive-enhancement.ts +10 -1
  148. package/src/rsc/redirect-guard.ts +99 -0
  149. package/src/rsc/response-route-handler.ts +23 -18
  150. package/src/rsc/rsc-rendering.ts +2 -7
  151. package/src/rsc/runtime-warnings.ts +14 -0
  152. package/src/rsc/server-action.ts +34 -29
  153. package/src/rsc/types.ts +6 -3
  154. package/src/search-params.ts +0 -16
  155. package/src/segment-loader-promise.ts +14 -2
  156. package/src/segment-system.tsx +79 -88
  157. package/src/server/handle-store.ts +7 -24
  158. package/src/server/loader-registry.ts +5 -24
  159. package/src/server/request-context.ts +29 -92
  160. package/src/ssr/index.tsx +14 -14
  161. package/src/static-handler.ts +2 -27
  162. package/src/testing/cache-status.ts +44 -48
  163. package/src/testing/collect-handle.ts +1 -24
  164. package/src/testing/dispatch.ts +43 -6
  165. package/src/testing/e2e/index.ts +1 -22
  166. package/src/testing/e2e/matchers.ts +0 -16
  167. package/src/testing/flight-matchers.ts +0 -13
  168. package/src/testing/flight-normalize.ts +3 -30
  169. package/src/testing/flight.ts +46 -48
  170. package/src/testing/generated-routes.ts +1 -41
  171. package/src/testing/index.ts +1 -21
  172. package/src/testing/internal/context.ts +3 -45
  173. package/src/testing/internal/seed-vars.ts +0 -26
  174. package/src/testing/render-handler.ts +31 -61
  175. package/src/testing/render-route.tsx +75 -103
  176. package/src/testing/run-loader.ts +0 -96
  177. package/src/testing/run-middleware.ts +0 -26
  178. package/src/theme/ThemeProvider.tsx +0 -52
  179. package/src/theme/ThemeScript.tsx +0 -6
  180. package/src/theme/constants.ts +0 -12
  181. package/src/theme/index.ts +0 -7
  182. package/src/theme/theme-context.ts +1 -5
  183. package/src/theme/theme-script.ts +0 -14
  184. package/src/theme/use-theme.ts +0 -3
  185. package/src/types/boundaries.ts +0 -35
  186. package/src/types/error-types.ts +25 -89
  187. package/src/types/global-namespace.ts +4 -14
  188. package/src/types/handler-context.ts +28 -9
  189. package/src/types/index.ts +0 -10
  190. package/src/types/request-scope.ts +0 -19
  191. package/src/types/route-config.ts +6 -50
  192. package/src/types/route-entry.ts +0 -6
  193. package/src/types/segments.ts +0 -13
  194. package/src/urls/include-helper.ts +0 -4
  195. package/src/urls/index.ts +0 -6
  196. package/src/urls/path-helper-types.ts +2 -2
  197. package/src/urls/path-helper.ts +0 -54
  198. package/src/urls/urls-function.ts +0 -13
  199. package/src/use-loader.tsx +0 -186
  200. package/src/vite/discovery/bundle-postprocess.ts +2 -1
  201. package/src/vite/discovery/discover-routers.ts +28 -18
  202. package/src/vite/discovery/prerender-collection.ts +2 -4
  203. package/src/vite/discovery/state.ts +5 -0
  204. package/src/vite/discovery/virtual-module-codegen.ts +1 -11
  205. package/src/vite/plugin-types.ts +35 -9
  206. package/src/vite/plugins/cjs-to-esm.ts +0 -11
  207. package/src/vite/plugins/client-ref-dedup.ts +0 -11
  208. package/src/vite/plugins/client-ref-hashing.ts +0 -10
  209. package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
  210. package/src/vite/plugins/expose-action-id.ts +2 -73
  211. package/src/vite/plugins/expose-id-utils.ts +0 -55
  212. package/src/vite/plugins/expose-ids/export-analysis.ts +0 -38
  213. package/src/vite/plugins/expose-ids/handler-transform.ts +0 -15
  214. package/src/vite/plugins/expose-ids/loader-transform.ts +0 -15
  215. package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
  216. package/src/vite/plugins/expose-internal-ids.ts +10 -0
  217. package/src/vite/plugins/performance-tracks.ts +0 -3
  218. package/src/vite/plugins/refresh-cmd.ts +1 -1
  219. package/src/vite/plugins/use-cache-transform.ts +21 -46
  220. package/src/vite/plugins/version-injector.ts +0 -20
  221. package/src/vite/plugins/version-plugin.ts +1 -49
  222. package/src/vite/plugins/virtual-entries.ts +0 -15
  223. package/src/vite/rango.ts +2 -108
  224. package/src/vite/router-discovery.ts +9 -1
  225. package/src/vite/utils/ast-handler-extract.ts +0 -16
  226. package/src/vite/utils/bundle-analysis.ts +6 -13
  227. package/src/vite/utils/client-chunks.ts +0 -6
  228. package/src/vite/utils/forward-user-plugins.ts +0 -22
  229. package/src/vite/utils/manifest-utils.ts +0 -4
  230. package/src/vite/utils/package-resolution.ts +1 -73
  231. package/src/vite/utils/prerender-utils.ts +0 -35
  232. package/src/vite/utils/shared-utils.ts +3 -35
  233. package/src/browser/shallow.ts +0 -40
  234. package/src/handles/index.ts +0 -7
  235. package/src/router/middleware-cookies.ts +0 -55
@@ -1,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { Handle } from "../handle.js";
3
+ import type { HandlePush } from "../defer.js";
3
4
  import type { ContextVar } from "../context-var.js";
4
5
  import type { MiddlewareFn } from "../router/middleware.js";
5
6
  import type { Theme } from "../theme/types.js";
@@ -107,14 +108,6 @@ type StrictLocalParamsWithExtras<TEntry> =
107
108
  ? Record<string, string>
108
109
  : ExtractParamsFromEntry<TEntry, {}> & Record<string, string>;
109
110
 
110
- // HandlerContext.reverse is the only reverse surface with runtime param autofill
111
- // from the current matched request. Middleware/loaders/request context do not
112
- // have the same local-route guarantees, so they keep plain ScopedReverseFunction.
113
- //
114
- // When a handler has an explicit local route map, enforce that local route
115
- // params declared by that map are present while still allowing extra mount
116
- // params to be passed through. Global names remain autofill-friendly because
117
- // parent include() params are often unknown at the module definition site.
118
111
  type StrictLocalAutofillGlobalReverseFunction<TLocalRoutes, TGlobalRoutes> =
119
112
  ScopedReverseFunction<TLocalRoutes, TGlobalRoutes> & {
120
113
  <TName extends keyof TGlobalRoutes & string>(
@@ -282,6 +275,8 @@ export type HandlerContext<
282
275
  * For handles: Returns a push function to add data for this segment.
283
276
  * Handle data accumulates across all matched route segments.
284
277
  * Push accepts: direct value, Promise, or async callback (executed immediately).
278
+ * Or call `.defer()` to reserve the slot now and resolve it later (e.g. from a
279
+ * deep async component), with a timeout safety net — see {@link HandlePush}.
285
280
  *
286
281
  * @example
287
282
  * ```typescript
@@ -315,6 +310,13 @@ export type HandlerContext<
315
310
  * });
316
311
  * return <ProductPage />;
317
312
  * });
313
+ *
314
+ * // Handle usage - deferred (reserve the slot now, resolve from a deep component)
315
+ * route("product", (ctx) => {
316
+ * const resolve = ctx.use(Breadcrumbs).defer({ timeoutMs: 5000, else: null });
317
+ * loadCrumb(ctx.params.id).then(resolve); // resolver is push-equal
318
+ * return <ProductPage />; // auto-resolves to `else` on timeout
319
+ * });
318
320
  * ```
319
321
  */
320
322
  use: {
@@ -323,7 +325,7 @@ export type HandlerContext<
323
325
  ): Promise<T>;
324
326
  <TData, TAccumulated = TData[]>(
325
327
  handle: Handle<TData, TAccumulated>,
326
- ): (data: TData | Promise<TData> | (() => Promise<TData>)) => void;
328
+ ): HandlePush<TData>;
327
329
  };
328
330
  /**
329
331
  * Current theme (from cookie or default).
@@ -430,6 +432,18 @@ export type InternalHandlerContext<
430
432
  _responseType?: string;
431
433
  /** Route name for cache key scoping (prevents cross-route collisions). */
432
434
  _routeName?: string;
435
+ /**
436
+ * @internal Loader-cache override table: loaderId -> memoized data promise.
437
+ * A single stable ctx.use interceptor consults this instead of chaining one
438
+ * wrapper per cached loader (avoids O(N) dispatch). See loader-cache.ts.
439
+ */
440
+ _loaderCacheOverrides?: Map<string, Promise<any>>;
441
+ /**
442
+ * @internal ctx.use captured before the loader-cache interceptor was installed.
443
+ * The cache-miss execute runs the loader through this, bypassing the override
444
+ * table (so a loader cannot await its own in-flight memoized promise).
445
+ */
446
+ _loaderCacheOriginalUse?: (item: any) => any;
433
447
  };
434
448
 
435
449
  /**
@@ -621,6 +635,10 @@ export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
621
635
  * namespace import (`import * as CartActions`), any export of that module —
622
636
  * and `false` otherwise (including plain navigation with no action).
623
637
  *
638
+ * Called with NO arguments it answers "is this request an action at all?":
639
+ * `true` for any action, `false` on plain navigation. Use the bare form when
640
+ * you want to revalidate on every action regardless of which one fired.
641
+ *
624
642
  * Prefer this over hand-written `actionId` substring matches: it resolves the
625
643
  * action's stable `path#export` id from the imported reference, so a rename is
626
644
  * a type error in one place instead of silent drift across consumers. It
@@ -635,6 +653,7 @@ export type ShouldRevalidateFn<TParams = GenericParams, TEnv = any> = (args: {
635
653
  * import { addToCart, removeFromCart } from "./actions/cart";
636
654
  * import * as CartActions from "./actions/cart";
637
655
  *
656
+ * revalidate((ctx) => ctx.isAction() || undefined); // any action
638
657
  * revalidate((ctx) => ctx.isAction(addToCart) || undefined); // one action
639
658
  * revalidate((ctx) => ctx.isAction(addToCart, removeFromCart) || undefined); // several
640
659
  * revalidate((ctx) => ctx.isAction(CartActions) || undefined); // any in the module
@@ -1,14 +1,11 @@
1
- // Global namespace (must be imported for side effects: `declare global`)
2
1
  export type {
3
2
  GetRegisteredRoutes,
4
3
  DefaultHandlerRouteMap,
5
4
  DefaultReverseRouteMap,
6
5
  DefaultEnv,
7
6
  } from "./global-namespace.js";
8
- // Ensure the global namespace declaration is evaluated
9
7
  import "./global-namespace.js";
10
8
 
11
- // Route configuration
12
9
  export type {
13
10
  DocumentProps,
14
11
  ExtractParams,
@@ -19,7 +16,6 @@ export type {
19
16
  ResolvedRouteMap,
20
17
  } from "./route-config.js";
21
18
 
22
- // Boundaries (error/notFound)
23
19
  export type {
24
20
  ErrorInfo,
25
21
  ErrorBoundaryFallbackProps,
@@ -32,7 +28,6 @@ export type {
32
28
  } from "./boundaries.js";
33
29
  export { isLoaderDataResult } from "./boundaries.js";
34
30
 
35
- // Handler context and related types
36
31
  export type {
37
32
  MiddlewareFn,
38
33
  ScopedRouteMap,
@@ -50,7 +45,6 @@ export type {
50
45
  Middleware,
51
46
  } from "./handler-context.js";
52
47
 
53
- // Segments
54
48
  export type {
55
49
  ViewTransitionClass,
56
50
  TransitionConfig,
@@ -61,10 +55,8 @@ export type {
61
55
  MatchResult,
62
56
  } from "./segments.js";
63
57
 
64
- // Route entries
65
58
  export type { LazyIncludeContext, RouteEntry } from "./route-entry.js";
66
59
 
67
- // Loader types
68
60
  export type {
69
61
  LoaderContext,
70
62
  LoaderFn,
@@ -73,7 +65,6 @@ export type {
73
65
  LoaderDefinition,
74
66
  } from "./loader-types.js";
75
67
 
76
- // Cache types
77
68
  export type {
78
69
  CacheContext,
79
70
  CacheOptions,
@@ -81,7 +72,6 @@ export type {
81
72
  EntryCacheConfig,
82
73
  } from "./cache-types.js";
83
74
 
84
- // Error handling types
85
75
  export type {
86
76
  ErrorPhase,
87
77
  OnErrorContext,
@@ -1,22 +1,3 @@
1
- /**
2
- * RequestScope: the fields every user-facing context shares.
3
- *
4
- * A handler, middleware, loader, response handler, and the ALS-bound
5
- * RequestContext are all different phases of the same request, and they
6
- * all carry the same set of request-scoped capabilities: the raw Request,
7
- * the parsed URL pair (`url` is cleaned of internal `_rsc*` params,
8
- * `originalUrl` retains them), pathname/searchParams, platform bindings
9
- * (`env`), and two escape hatches for work that outlives the response
10
- * (`waitUntil`) or needs the raw Cloudflare runtime object
11
- * (`executionContext`).
12
- *
13
- * Each public context type intersects `RequestScope<TEnv>` with its own
14
- * phase-specific fields (e.g. `params`/`reverse` on HandlerContext,
15
- * `headers`/`header()` on MiddlewareContext). That keeps platform surface
16
- * in one place and lets the next runtime escape hatch we need land in
17
- * one file instead of four.
18
- */
19
-
20
1
  import type { DefaultEnv } from "./global-namespace.js";
21
2
 
22
3
  /**
@@ -7,47 +7,24 @@ export type DocumentProps = {
7
7
  children: ReactNode;
8
8
  };
9
9
 
10
- /**
11
- * Parse constraint values into a union type
12
- * "a|b|c" -> "a" | "b" | "c"
13
- */
14
10
  type ParseConstraint<T extends string> =
15
11
  T extends `${infer First}|${infer Rest}` ? First | ParseConstraint<Rest> : T;
16
12
 
17
- /**
18
- * Extract param info from a param segment
19
- *
20
- * Handles:
21
- * - :param -> { name: "param", optional: false, type: string }
22
- * - :param? -> { name: "param", optional: true, type: string }
23
- * - :param(a|b) -> { name: "param", optional: false, type: "a" | "b" }
24
- * - :param(a|b)? -> { name: "param", optional: true, type: "a" | "b" }
25
- */
26
13
  type ExtractParamInfo<T extends string> =
27
- // Optional + constrained (with optional suffix): :param(a|b)?suffix
28
14
  T extends `${infer Name}(${infer Constraint})?${string}`
29
15
  ? { name: Name; optional: true; type: ParseConstraint<Constraint> }
30
- : // Constrained (with optional suffix): :param(a|b)suffix
31
- T extends `${infer Name}(${infer Constraint})${string}`
16
+ : T extends `${infer Name}(${infer Constraint})${string}`
32
17
  ? { name: Name; optional: false; type: ParseConstraint<Constraint> }
33
- : // Optional (with optional suffix): :param?suffix
34
- T extends `${infer Name}?${string}`
18
+ : T extends `${infer Name}?${string}`
35
19
  ? { name: Name; optional: true; type: string }
36
- : // Param with dot-suffix: :param.html
37
- T extends `${infer Name}.${string}`
20
+ : T extends `${infer Name}.${string}`
38
21
  ? { name: Name; optional: false; type: string }
39
- : // Param with dash-suffix: :param-slug
40
- T extends `${infer Name}-${string}`
22
+ : T extends `${infer Name}-${string}`
41
23
  ? { name: Name; optional: false; type: string }
42
- : // Param with tilde-suffix: :param~v2
43
- T extends `${infer Name}~${string}`
24
+ : T extends `${infer Name}~${string}`
44
25
  ? { name: Name; optional: false; type: string }
45
- : // Required: :param (no suffix)
46
- { name: T; optional: false; type: string };
26
+ : { name: T; optional: false; type: string };
47
27
 
48
- /**
49
- * Build param object from info
50
- */
51
28
  type ParamFromInfo<Info> = Info extends {
52
29
  name: infer N extends string;
53
30
  optional: true;
@@ -62,10 +39,6 @@ type ParamFromInfo<Info> = Info extends {
62
39
  ? { [K in N]: V }
63
40
  : never;
64
41
 
65
- /**
66
- * Merge two param objects preserving optionality
67
- * Uses Pick to preserve the modifiers from source types
68
- */
69
42
  type MergeParams<A, B> = Pick<A, keyof A> & Pick<B, keyof B> extends infer O
70
43
  ? { [K in keyof O]: O[K] }
71
44
  : never;
@@ -109,17 +82,11 @@ export type ExtractParams<
109
82
  */
110
83
  export type TrailingSlashMode = "never" | "always" | "ignore";
111
84
 
112
- /**
113
- * Route configuration object (alternative to string path)
114
- */
115
85
  export type RouteConfig = {
116
86
  path: string;
117
87
  trailingSlash?: TrailingSlashMode;
118
88
  };
119
89
 
120
- /**
121
- * Route definition options (global defaults)
122
- */
123
90
  export type RouteDefinitionOptions = {
124
91
  trailingSlash?: TrailingSlashMode;
125
92
  };
@@ -128,11 +95,6 @@ export type RouteDefinition = {
128
95
  [key: string]: string | RouteConfig | RouteDefinition;
129
96
  };
130
97
 
131
- /**
132
- * Recursively flatten nested routes with depth limit to prevent infinite recursion
133
- * Transforms: { products: { detail: "/product/:slug" } } => { "products.detail": "/product/:slug" }
134
- * Also handles RouteConfig objects: { api: { path: "/api" } } => { "api": "/api" }
135
- */
136
98
  type FlattenRoutes<
137
99
  T extends RouteDefinition,
138
100
  Prefix extends string = "",
@@ -153,18 +115,12 @@ type FlattenRoutes<
153
115
  : never;
154
116
  }[keyof T];
155
117
 
156
- /**
157
- * Union to intersection helper
158
- */
159
118
  type UnionToIntersection<U> = (
160
119
  U extends unknown ? (k: U) => void : never
161
120
  ) extends (k: infer I) => void
162
121
  ? I
163
122
  : never;
164
123
 
165
- /**
166
- * Resolved route map - flattened route definitions with full paths
167
- */
168
124
  export type ResolvedRouteMap<T extends RouteDefinition> = UnionToIntersection<
169
125
  FlattenRoutes<T>
170
126
  >;
@@ -1,9 +1,6 @@
1
1
  import type { AllUseItems } from "../route-types.js";
2
2
  import type { TrailingSlashMode, ResolvedRouteMap } from "./route-config.js";
3
3
 
4
- /**
5
- * Context captured for lazy include evaluation
6
- */
7
4
  export interface LazyIncludeContext {
8
5
  urlPrefix: string;
9
6
  namePrefix: string | undefined;
@@ -25,9 +22,6 @@ export interface LazyIncludeContext {
25
22
  includeScope?: string;
26
23
  }
27
24
 
28
- /**
29
- * Internal route entry stored in router
30
- */
31
25
  export interface RouteEntry<TEnv = any> {
32
26
  prefix: string;
33
27
  /**
@@ -41,14 +41,6 @@ export interface TransitionConfig {
41
41
  /**
42
42
  * Resolved segment with component
43
43
  *
44
- * Segment types:
45
- * - layout: Wraps child content via <Outlet />
46
- * - route: The leaf content for a URL
47
- * - parallel: Named slots rendered via <ParallelOutlet name="@slot" />
48
- * - loader: Data segment (no visual rendering, carries loaderData)
49
- * - error: Error fallback segment (replaces failed segment with error UI)
50
- * - notFound: Not found fallback segment (replaces segment when data not found)
51
- *
52
44
  * @internal This type is an implementation detail and may change without notice.
53
45
  */
54
46
  export interface ResolvedSegment {
@@ -89,11 +81,6 @@ export interface ResolvedSegment {
89
81
  _handlerRan?: boolean;
90
82
  }
91
83
 
92
- /**
93
- * Segment metadata (without component)
94
- *
95
- * @internal This type is an implementation detail and may change without notice.
96
- */
97
84
  export interface SegmentMetadata {
98
85
  id: string;
99
86
  type: "layout" | "route" | "parallel" | "loader" | "error" | "notFound";
@@ -37,10 +37,8 @@ export function processItems(items: readonly AllUseItems[]): AllUseItems[] {
37
37
  if (!item) continue;
38
38
 
39
39
  if (item.type === "include") {
40
- // All includes are lazy; the router expands them on first matching request.
41
40
  result.push(item);
42
41
  } else if (item.type === "layout" && (item as any).uses) {
43
- // Process nested items in layout
44
42
  const layoutItem = item as any;
45
43
  layoutItem.uses = processItems(layoutItem.uses);
46
44
  result.push(layoutItem);
@@ -141,8 +139,6 @@ export function createIncludeHelper<TEnv>(): IncludeFn<TEnv> {
141
139
  ? (parentRootScoped ?? false)
142
140
  : parentRootScoped;
143
141
 
144
- // All includes are lazy - patterns are evaluated on first matching request
145
- // This improves cold start time significantly for large route sets
146
142
  return {
147
143
  type: "include",
148
144
  name,
package/src/urls/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- // Response types and symbols
2
1
  export {
3
2
  RESPONSE_TYPE,
4
3
  type ResponseHandler,
@@ -8,7 +7,6 @@ export {
8
7
  type ResponseHandlerContext,
9
8
  } from "./response-types.js";
10
9
 
11
- // Pattern types
12
10
  export type {
13
11
  UnnamedRoute,
14
12
  LocalOnlyInclude,
@@ -17,7 +15,6 @@ export type {
17
15
  IncludeOptions,
18
16
  } from "./pattern-types.js";
19
17
 
20
- // Type extraction utilities
21
18
  export type {
22
19
  ExtractRoutes,
23
20
  ExtractResponses,
@@ -25,7 +22,6 @@ export type {
25
22
  RouteResponse,
26
23
  } from "./type-extraction.js";
27
24
 
28
- // Path helper types
29
25
  export type {
30
26
  PathFn,
31
27
  ResponsePathFn,
@@ -35,10 +31,8 @@ export type {
35
31
  PathHelpers,
36
32
  } from "./path-helper-types.js";
37
33
 
38
- // Main entry point
39
34
  export { urls } from "./urls-function.js";
40
35
 
41
- // Re-exports from route-types
42
36
  export type {
43
37
  AllUseItems,
44
38
  IncludeItem,
@@ -348,9 +348,9 @@ export type PathHelpers<TEnv> = {
348
348
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
349
349
  children: () => TChildren,
350
350
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
351
- (options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
351
+ (options: PartialCacheOptions<TEnv> | false): TypedCacheItem<{}, {}>;
352
352
  <const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
353
- options: PartialCacheOptions | false,
353
+ options: PartialCacheOptions<TEnv> | false,
354
354
  use: () => TChildren,
355
355
  ): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
356
356
  };
@@ -39,10 +39,6 @@ import {
39
39
  runAndValidateUseItems,
40
40
  } from "../route-definition/dsl-helpers.js";
41
41
 
42
- /**
43
- * Apply URL prefix to a pattern
44
- * Handles edge cases like "/" patterns and double slashes
45
- */
46
42
  function applyUrlPrefix(prefix: string, pattern: string): string {
47
43
  if (!prefix) return pattern;
48
44
  if (pattern === "/") return prefix;
@@ -52,29 +48,17 @@ function applyUrlPrefix(prefix: string, pattern: string): string {
52
48
  return prefix + pattern;
53
49
  }
54
50
 
55
- /**
56
- * Apply name prefix to a route name
57
- */
58
51
  function applyNamePrefix(prefix: string | undefined, name: string): string {
59
52
  if (!prefix) return name;
60
53
  return `${prefix}.${name}`;
61
54
  }
62
55
 
63
- /**
64
- * Resolve response type from path options (set by path.json(), path.text(), etc.)
65
- */
66
56
  function resolveResponseType(
67
57
  options: PathOptions | undefined,
68
58
  ): string | undefined {
69
59
  return options?.[RESPONSE_TYPE];
70
60
  }
71
61
 
72
- /**
73
- * Create path() helper
74
- *
75
- * The path() function is the key new feature - it combines URL pattern
76
- * with handler at the definition site.
77
- */
78
62
  export function createPathHelper<TEnv>(): PathFn<TEnv> {
79
63
  return ((
80
64
  pattern: string,
@@ -91,8 +75,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
91
75
  "path() cannot be used inside parallel()",
92
76
  );
93
77
 
94
- // Walk the parent chain to prevent path() nested under another path(),
95
- // even when separated by intermediate layouts (e.g. path(layout(path())))
96
78
  {
97
79
  let ancestor = ctx.parent;
98
80
  while (ancestor) {
@@ -104,7 +86,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
104
86
  }
105
87
  }
106
88
 
107
- // Determine options and use based on argument types
108
89
  let options: PathOptions | undefined;
109
90
  let use: (() => UseItems<RouteUseItem>) | undefined;
110
91
 
@@ -117,49 +98,29 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
117
98
  use = maybeUse;
118
99
  }
119
100
 
120
- // Merge handler.use() defaults with explicit use()
121
- // Response routes (path.json, path.text, etc.) only allow middleware + cache
122
101
  const handlerUseFn = resolveHandlerUse(handler);
123
102
  const mountSite = resolveResponseType(options) ? "response" : "path";
124
103
  const mergedUse = mergeHandlerUse(handlerUseFn, use, mountSite);
125
104
 
126
- // Get prefixes from context (set by include())
127
105
  const urlPrefix = getUrlPrefix();
128
106
  const namePrefix = getNamePrefix();
129
107
 
130
- // Apply URL prefix to pattern
131
108
  const prefixedPattern = applyUrlPrefix(urlPrefix, pattern);
132
109
 
133
- // Generate route name - use provided name or generate from pattern
134
110
  const localName =
135
111
  options?.name || `$path_${pattern.replace(/[/:*?]/g, "_")}`;
136
112
  if (options?.name) {
137
113
  validateUserRouteName(options.name);
138
114
  }
139
- // Apply name prefix if set (from include())
140
115
  const routeName = applyNamePrefix(namePrefix, localName);
141
116
 
142
117
  const namespace = `${ctx.namespace}.${store.getNextIndex("route")}.${routeName}`;
143
118
 
144
- // Per-request pruning: skip registration for routes that won't be rendered.
145
- // forRoute is set by loadManifest() to the matched route name. During
146
- // evaluateLazyEntry() (route matching), forRoute is unset so all routes
147
- // register normally. We still increment counters to keep shortCodes stable
148
- // across different routes (needed for segment reconciliation on navigation).
149
- //
150
- // include() does not need its own forRoute pruning. include() creates lazy
151
- // entries that defer handler execution until route matching. When the lazy
152
- // handler eventually runs inside loadManifest(), this path() check already
153
- // covers all routes defined inside the include.
154
119
  if (ctx.forRoute && routeName !== ctx.forRoute) {
155
120
  store.getShortCode("route");
156
121
  return { type: "route" } as RouteItem;
157
122
  }
158
123
 
159
- // Ensure handler is always a function (wrap ReactNode or extract from prerender/static def)
160
- // For prerender stubs (production builds where handler code is evicted),
161
- // handler.handler is undefined — provide a notFound fallback so requests
162
- // for non-prerendered params get 404 instead of "handler is not a function".
163
124
  const wrappedHandler: Handler<any, any, TEnv> =
164
125
  typeof handler === "function"
165
126
  ? (handler as Handler<any, any, TEnv>)
@@ -190,7 +151,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
190
151
  type: "route" as const,
191
152
  parent: ctx.parent,
192
153
  handler: wrappedHandler,
193
- // Store the PREFIXED pattern for route matching
194
154
  pattern: prefixedPattern,
195
155
  ...(urlPrefix ? { mountPath: urlPrefix } : {}),
196
156
  ...(isPassthroughHandler(handler)
@@ -217,29 +177,23 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
217
177
  : {}),
218
178
  };
219
179
 
220
- // Capture namespace prefix on static handler for build-time reverse() resolution
221
180
  if (isStaticHandler(handler) && handler.$$id && ctx.namePrefix) {
222
181
  (handler as any).$$routePrefix = ctx.namePrefix;
223
182
  }
224
183
 
225
- // Check for duplicate route names (TypeScript should catch this, but runtime check too)
226
184
  invariant(
227
185
  ctx.manifest.get(routeName) === undefined,
228
186
  `Duplicate route name: ${routeName} at ${namespace}`,
229
187
  );
230
188
 
231
- // Register route entry with prefixed name
232
189
  ctx.manifest.set(routeName, entry);
233
190
 
234
- // Register root-scope flag for dot-local reverse resolution
235
191
  registerRouteRootScope(routeName, getRootScoped());
236
192
 
237
- // Also store pattern in a separate map for URL generation
238
193
  if (ctx.patterns) {
239
194
  ctx.patterns.set(routeName, prefixedPattern);
240
195
  }
241
196
 
242
- // Store pattern grouped by URL prefix for separate entry creation
243
197
  if (ctx.patternsByPrefix) {
244
198
  const urlPrefix = getUrlPrefix() || "";
245
199
  if (!ctx.patternsByPrefix.has(urlPrefix)) {
@@ -248,12 +202,10 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
248
202
  ctx.patternsByPrefix.get(urlPrefix)!.set(routeName, prefixedPattern);
249
203
  }
250
204
 
251
- // Store trailing slash config if specified
252
205
  if (options?.trailingSlash && ctx.trailingSlash) {
253
206
  ctx.trailingSlash.set(routeName, options.trailingSlash);
254
207
  }
255
208
 
256
- // Store search schema if specified
257
209
  if (options?.search) {
258
210
  if (ctx.searchSchemas) {
259
211
  ctx.searchSchemas.set(routeName, options.search);
@@ -261,7 +213,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
261
213
  registerSearchSchema(routeName, options.search);
262
214
  }
263
215
 
264
- // Run merged use callback (handler.use defaults + explicit use) if present
265
216
  if (mergedUse) {
266
217
  const result = runAndValidateUseItems(
267
218
  store,
@@ -278,10 +229,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
278
229
  }) as PathFn<TEnv>;
279
230
  }
280
231
 
281
- /**
282
- * Attach response type tag methods (.json, .text, .html, .xml, .md, .image, .stream, .any) to a path helper.
283
- * Each tag wraps the original path() call with the RESPONSE_TYPE option set.
284
- */
285
232
  export function attachPathResponseTags<TEnv>(
286
233
  pathFn: PathFn<TEnv>,
287
234
  ): PathFn<TEnv> & {
@@ -303,7 +250,6 @@ export function attachPathResponseTags<TEnv>(
303
250
  ) => {
304
251
  let options: PathOptions;
305
252
  let use: (() => any[]) | undefined;
306
-
307
253
  if (typeof optionsOrUse === "function") {
308
254
  options = { [RESPONSE_TYPE]: responseType };
309
255
  use = optionsOrUse;
@@ -34,24 +34,18 @@ export function urls<
34
34
  >(
35
35
  builder: (helpers: PathHelpers<TEnv>) => TItems,
36
36
  ): UrlPatterns<TEnv, ExtractRoutes<TItems>, ExtractResponses<TItems>> {
37
- // Create the handler function that will be called by the router
38
37
  const handler = () => {
39
38
  invariant(
40
39
  typeof builder === "function",
41
40
  "urls() expects a builder function as its argument",
42
41
  );
43
42
 
44
- // Get base helpers from the existing route-definition module
45
43
  const baseHelpers = createRouteHelpers<any, TEnv>();
46
44
 
47
- // Create the path helper (with .json, .text, .html, .xml, .image, .stream, .any tags)
48
45
  const pathHelper = attachPathResponseTags(createPathHelper<TEnv>());
49
46
 
50
- // Create the include helper
51
47
  const includeHelper = createIncludeHelper<TEnv>();
52
48
 
53
- // Combine all helpers
54
- // Note: layout and cache are cast to their typed versions - phantom types don't affect runtime
55
49
  const helpers: PathHelpers<TEnv> = {
56
50
  path: pathHelper as any,
57
51
  include: includeHelper as any,
@@ -69,20 +63,13 @@ export function urls<
69
63
  transition: baseHelpers.transition as PathHelpers<TEnv>["transition"],
70
64
  };
71
65
 
72
- // Execute builder directly - manifest.ts handles RootLayout wrapping
73
- // for inline handlers (non-Promise results).
74
- // For nested include() calls, routes inherit the outer RootLayout.
75
66
  const builderResult = builder(helpers).flat(3) as AllUseItems[];
76
67
  return processItems(builderResult);
77
68
  };
78
69
 
79
- // trailingSlash config is populated when handler() runs
80
- // We expose it via a getter that reads from the context after handler execution
81
70
  return {
82
71
  handler,
83
72
  get trailingSlash() {
84
- // Get the trailingSlash map from the current context
85
- // This will be populated after handler() is called
86
73
  const store = getContext();
87
74
  const ctx = store.context.getStore();
88
75
  if (!ctx?.trailingSlash) {