@rangojs/router 0.0.0-experimental.28 → 0.0.0-experimental.289231ba

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 (159) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +78 -19
  3. package/dist/bin/rango.js +138 -50
  4. package/dist/vite/index.js +853 -435
  5. package/package.json +17 -16
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +32 -0
  8. package/skills/caching/SKILL.md +45 -4
  9. package/skills/handler-use/SKILL.md +362 -0
  10. package/skills/hooks/SKILL.md +22 -4
  11. package/skills/intercept/SKILL.md +20 -0
  12. package/skills/layout/SKILL.md +22 -0
  13. package/skills/links/SKILL.md +3 -1
  14. package/skills/loader/SKILL.md +71 -21
  15. package/skills/middleware/SKILL.md +34 -3
  16. package/skills/migrate-nextjs/SKILL.md +560 -0
  17. package/skills/migrate-react-router/SKILL.md +764 -0
  18. package/skills/parallel/SKILL.md +185 -0
  19. package/skills/prerender/SKILL.md +110 -68
  20. package/skills/rango/SKILL.md +24 -22
  21. package/skills/route/SKILL.md +56 -2
  22. package/skills/router-setup/SKILL.md +92 -2
  23. package/skills/typesafety/SKILL.md +33 -21
  24. package/src/__internal.ts +92 -0
  25. package/src/browser/app-version.ts +14 -0
  26. package/src/browser/event-controller.ts +5 -0
  27. package/src/browser/link-interceptor.ts +4 -0
  28. package/src/browser/navigation-bridge.ts +125 -16
  29. package/src/browser/navigation-client.ts +154 -44
  30. package/src/browser/navigation-store.ts +43 -8
  31. package/src/browser/navigation-transaction.ts +11 -9
  32. package/src/browser/partial-update.ts +94 -17
  33. package/src/browser/prefetch/cache.ts +176 -27
  34. package/src/browser/prefetch/fetch.ts +110 -41
  35. package/src/browser/prefetch/policy.ts +6 -0
  36. package/src/browser/prefetch/queue.ts +92 -20
  37. package/src/browser/prefetch/resource-ready.ts +77 -0
  38. package/src/browser/react/Link.tsx +88 -9
  39. package/src/browser/react/NavigationProvider.tsx +40 -4
  40. package/src/browser/react/context.ts +7 -2
  41. package/src/browser/react/use-handle.ts +9 -58
  42. package/src/browser/react/use-navigation.ts +22 -2
  43. package/src/browser/react/use-router.ts +21 -8
  44. package/src/browser/rsc-router.tsx +143 -60
  45. package/src/browser/scroll-restoration.ts +41 -42
  46. package/src/browser/segment-reconciler.ts +36 -9
  47. package/src/browser/server-action-bridge.ts +8 -6
  48. package/src/browser/types.ts +60 -5
  49. package/src/build/generate-manifest.ts +6 -6
  50. package/src/build/generate-route-types.ts +3 -0
  51. package/src/build/route-trie.ts +50 -24
  52. package/src/build/route-types/include-resolution.ts +8 -1
  53. package/src/build/route-types/router-processing.ts +223 -74
  54. package/src/build/route-types/scan-filter.ts +8 -1
  55. package/src/cache/cache-runtime.ts +15 -11
  56. package/src/cache/cache-scope.ts +48 -7
  57. package/src/cache/cf/cf-cache-store.ts +453 -11
  58. package/src/cache/cf/index.ts +5 -1
  59. package/src/cache/document-cache.ts +17 -7
  60. package/src/cache/index.ts +1 -0
  61. package/src/cache/taint.ts +55 -0
  62. package/src/client.rsc.tsx +2 -0
  63. package/src/client.tsx +85 -230
  64. package/src/context-var.ts +72 -2
  65. package/src/debug.ts +2 -2
  66. package/src/handle.ts +40 -0
  67. package/src/handles/breadcrumbs.ts +66 -0
  68. package/src/handles/index.ts +1 -0
  69. package/src/index.rsc.ts +6 -36
  70. package/src/index.ts +50 -43
  71. package/src/prerender/store.ts +5 -4
  72. package/src/prerender.ts +138 -77
  73. package/src/reverse.ts +25 -1
  74. package/src/route-definition/dsl-helpers.ts +224 -37
  75. package/src/route-definition/helpers-types.ts +67 -19
  76. package/src/route-definition/index.ts +3 -0
  77. package/src/route-definition/redirect.ts +11 -3
  78. package/src/route-definition/resolve-handler-use.ts +149 -0
  79. package/src/route-map-builder.ts +7 -1
  80. package/src/route-types.ts +18 -0
  81. package/src/router/content-negotiation.ts +100 -1
  82. package/src/router/find-match.ts +4 -2
  83. package/src/router/handler-context.ts +111 -25
  84. package/src/router/intercept-resolution.ts +11 -4
  85. package/src/router/lazy-includes.ts +9 -6
  86. package/src/router/loader-resolution.ts +156 -21
  87. package/src/router/logging.ts +5 -2
  88. package/src/router/manifest.ts +31 -16
  89. package/src/router/match-api.ts +125 -190
  90. package/src/router/match-middleware/background-revalidation.ts +30 -2
  91. package/src/router/match-middleware/cache-lookup.ts +94 -17
  92. package/src/router/match-middleware/cache-store.ts +53 -10
  93. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  94. package/src/router/match-middleware/segment-resolution.ts +61 -5
  95. package/src/router/match-result.ts +104 -10
  96. package/src/router/metrics.ts +6 -1
  97. package/src/router/middleware-types.ts +40 -12
  98. package/src/router/middleware.ts +43 -79
  99. package/src/router/navigation-snapshot.ts +182 -0
  100. package/src/router/prerender-match.ts +114 -10
  101. package/src/router/preview-match.ts +30 -102
  102. package/src/router/request-classification.ts +310 -0
  103. package/src/router/route-snapshot.ts +245 -0
  104. package/src/router/router-context.ts +6 -1
  105. package/src/router/router-interfaces.ts +44 -5
  106. package/src/router/router-options.ts +49 -18
  107. package/src/router/segment-resolution/fresh.ts +198 -20
  108. package/src/router/segment-resolution/helpers.ts +30 -25
  109. package/src/router/segment-resolution/loader-cache.ts +1 -0
  110. package/src/router/segment-resolution/revalidation.ts +438 -300
  111. package/src/router/segment-wrappers.ts +2 -0
  112. package/src/router/types.ts +1 -0
  113. package/src/router.ts +73 -13
  114. package/src/rsc/handler.ts +472 -372
  115. package/src/rsc/loader-fetch.ts +23 -3
  116. package/src/rsc/manifest-init.ts +5 -1
  117. package/src/rsc/progressive-enhancement.ts +14 -2
  118. package/src/rsc/rsc-rendering.ts +13 -1
  119. package/src/rsc/server-action.ts +8 -0
  120. package/src/rsc/ssr-setup.ts +2 -2
  121. package/src/rsc/types.ts +11 -1
  122. package/src/segment-content-promise.ts +67 -0
  123. package/src/segment-loader-promise.ts +122 -0
  124. package/src/segment-system.tsx +109 -23
  125. package/src/server/context.ts +166 -17
  126. package/src/server/handle-store.ts +19 -0
  127. package/src/server/loader-registry.ts +9 -8
  128. package/src/server/request-context.ts +204 -28
  129. package/src/ssr/index.tsx +4 -0
  130. package/src/static-handler.ts +18 -6
  131. package/src/types/cache-types.ts +4 -4
  132. package/src/types/handler-context.ts +149 -49
  133. package/src/types/loader-types.ts +36 -9
  134. package/src/types/route-entry.ts +19 -1
  135. package/src/types/segments.ts +2 -0
  136. package/src/urls/include-helper.ts +24 -14
  137. package/src/urls/path-helper-types.ts +39 -6
  138. package/src/urls/path-helper.ts +48 -13
  139. package/src/urls/pattern-types.ts +12 -0
  140. package/src/urls/response-types.ts +16 -6
  141. package/src/use-loader.tsx +77 -5
  142. package/src/vite/discovery/bundle-postprocess.ts +30 -33
  143. package/src/vite/discovery/discover-routers.ts +5 -1
  144. package/src/vite/discovery/prerender-collection.ts +128 -74
  145. package/src/vite/discovery/state.ts +13 -6
  146. package/src/vite/index.ts +4 -0
  147. package/src/vite/plugin-types.ts +51 -79
  148. package/src/vite/plugins/expose-action-id.ts +1 -3
  149. package/src/vite/plugins/expose-id-utils.ts +12 -0
  150. package/src/vite/plugins/expose-ids/handler-transform.ts +30 -0
  151. package/src/vite/plugins/expose-internal-ids.ts +257 -40
  152. package/src/vite/plugins/performance-tracks.ts +88 -0
  153. package/src/vite/plugins/refresh-cmd.ts +88 -26
  154. package/src/vite/plugins/version-plugin.ts +13 -1
  155. package/src/vite/rango.ts +163 -211
  156. package/src/vite/router-discovery.ts +178 -45
  157. package/src/vite/utils/banner.ts +3 -3
  158. package/src/vite/utils/prerender-utils.ts +37 -5
  159. package/src/vite/utils/shared-utils.ts +3 -2
@@ -204,6 +204,7 @@ export function createSegmentWrappers<TEnv = any>(
204
204
  interceptResult: { intercept: InterceptEntry; entry: EntryData } | null,
205
205
  localRouteName: string,
206
206
  pathname: string,
207
+ stale?: boolean,
207
208
  ): ReturnType<typeof _resolveAllSegmentsWithRevalidation> {
208
209
  return _resolveAllSegmentsWithRevalidation(
209
210
  entries,
@@ -221,6 +222,7 @@ export function createSegmentWrappers<TEnv = any>(
221
222
  localRouteName,
222
223
  pathname,
223
224
  segmentDeps,
225
+ stale,
224
226
  );
225
227
  }
226
228
 
@@ -96,6 +96,7 @@ export interface SegmentResolutionDeps<TEnv = any> {
96
96
  findNearestNotFoundBoundary: (
97
97
  entry: EntryData | null,
98
98
  ) => ReactNode | NotFoundBoundaryHandler | null;
99
+ notFoundComponent?: ReactNode | ((props: { pathname: string }) => ReactNode);
99
100
  callOnError: (error: unknown, phase: ErrorPhase, context: any) => void;
100
101
  }
101
102
 
package/src/router.ts CHANGED
@@ -19,6 +19,8 @@ import {
19
19
  import MapRootLayout from "./server/root-layout.js";
20
20
  import type { AllUseItems } from "./route-types.js";
21
21
  import type { UrlPatterns } from "./urls.js";
22
+ import type { UrlBuilder } from "./urls/pattern-types.js";
23
+ import { urls } from "./urls.js";
22
24
  import {
23
25
  EntryData,
24
26
  InterceptSelectorContext,
@@ -133,6 +135,7 @@ export function createRouter<TEnv = any>(
133
135
  const {
134
136
  id: userProvidedId,
135
137
  $$id: injectedId,
138
+ basename: basenameOption,
136
139
  debugPerformance = false,
137
140
  document: documentOption,
138
141
  defaultErrorBoundary,
@@ -147,7 +150,7 @@ export function createRouter<TEnv = any>(
147
150
  $$sourceFile: injectedSourceFile,
148
151
  nonce,
149
152
  version,
150
- prefetchCacheControl: prefetchCacheControlOption,
153
+ prefetchCacheTTL: prefetchCacheTTLOption,
151
154
  warmup: warmupOption,
152
155
  allowDebugManifest: allowDebugManifestOption = false,
153
156
  telemetry: telemetrySink,
@@ -158,6 +161,13 @@ export function createRouter<TEnv = any>(
158
161
  originCheck: originCheckOption,
159
162
  } = options;
160
163
 
164
+ // Normalize basename: ensure leading slash, strip trailing slash.
165
+ // A bare "/" is equivalent to no basename.
166
+ const basename =
167
+ basenameOption && basenameOption.replace(/^\/+|\/+$/g, "")
168
+ ? "/" + basenameOption.replace(/^\/+|\/+$/g, "")
169
+ : undefined;
170
+
161
171
  // Resolve telemetry sink (no-op when not configured)
162
172
  const telemetry = resolveSink(telemetrySink);
163
173
 
@@ -200,11 +210,17 @@ export function createRouter<TEnv = any>(
200
210
  const routerId =
201
211
  userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
202
212
 
203
- // Resolve prefetch cache control (default: 'private, max-age=300')
204
- const prefetchCacheControl =
205
- prefetchCacheControlOption !== undefined
206
- ? prefetchCacheControlOption
207
- : "private, max-age=300";
213
+ // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes)
214
+ // Clamp to a non-negative integer for valid Cache-Control max-age.
215
+ const rawTTL =
216
+ prefetchCacheTTLOption !== undefined ? prefetchCacheTTLOption : 300;
217
+ const prefetchCacheTTLSeconds =
218
+ rawTTL === false ? 0 : Math.max(0, Math.floor(rawTTL));
219
+ const prefetchCacheTTL = prefetchCacheTTLSeconds * 1000;
220
+ const prefetchCacheControl: string | false =
221
+ prefetchCacheTTLSeconds === 0
222
+ ? false
223
+ : `private, max-age=${prefetchCacheTTLSeconds}`;
208
224
 
209
225
  // Resolve warmup enabled flag (default: true)
210
226
  const warmupEnabled = warmupOption !== false;
@@ -520,6 +536,7 @@ export function createRouter<TEnv = any>(
520
536
  trackHandler,
521
537
  findNearestErrorBoundary,
522
538
  findNearestNotFoundBoundary,
539
+ notFoundComponent: notFound,
523
540
  callOnError,
524
541
  };
525
542
 
@@ -554,6 +571,7 @@ export function createRouter<TEnv = any>(
554
571
  mergedRouteMap,
555
572
  nextMountIndex: () => mountIndex++,
556
573
  getPrecomputedByPrefix,
574
+ routerId,
557
575
  };
558
576
 
559
577
  function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
@@ -607,6 +625,8 @@ export function createRouter<TEnv = any>(
607
625
  params: Record<string, string>,
608
626
  buildVars?: Record<string, any>,
609
627
  isPassthroughRoute?: boolean,
628
+ buildEnv?: TEnv,
629
+ devMode?: boolean,
610
630
  ) {
611
631
  return _matchForPrerender(
612
632
  pathname,
@@ -614,6 +634,8 @@ export function createRouter<TEnv = any>(
614
634
  prerenderDeps,
615
635
  buildVars,
616
636
  isPassthroughRoute,
637
+ buildEnv,
638
+ devMode,
617
639
  );
618
640
  }
619
641
 
@@ -621,12 +643,16 @@ export function createRouter<TEnv = any>(
621
643
  handler: Function,
622
644
  handlerId: string,
623
645
  routeName?: string,
646
+ buildEnv?: TEnv,
647
+ devMode?: boolean,
624
648
  ) {
625
649
  return _renderStaticSegment<TEnv>(
626
650
  handler,
627
651
  handlerId,
628
652
  mergedRouteMap,
629
653
  routeName,
654
+ buildEnv,
655
+ devMode,
630
656
  );
631
657
  }
632
658
 
@@ -651,8 +677,15 @@ export function createRouter<TEnv = any>(
651
677
  const router: RSCRouterInternal<TEnv, {}> = {
652
678
  __brand: RSC_ROUTER_BRAND,
653
679
  id: routerId,
680
+ basename,
681
+
682
+ routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
683
+ // Wrap builder functions in urls() automatically
684
+ const urlPatterns: UrlPatterns<TEnv> =
685
+ typeof patternsOrBuilder === "function"
686
+ ? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
687
+ : patternsOrBuilder;
654
688
 
655
- routes(urlPatterns: UrlPatterns<TEnv>): any {
656
689
  // Store reference for runtime manifest generation
657
690
  storedUrlPatterns = urlPatterns;
658
691
  const currentMountIndex = mountIndex++;
@@ -683,7 +716,7 @@ export function createRouter<TEnv = any>(
683
716
  errorBoundary: [],
684
717
  notFoundBoundary: [],
685
718
  layout: [],
686
- parallel: [],
719
+ parallel: {},
687
720
  intercept: [],
688
721
  loader: [],
689
722
  };
@@ -700,6 +733,10 @@ export function createRouter<TEnv = any>(
700
733
  counters: {},
701
734
  mountIndex: currentMountIndex,
702
735
  cacheProfiles: resolvedCacheProfiles,
736
+ // basename sets the initial URL prefix so all path() patterns
737
+ // are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
738
+ // No namePrefix — route names stay unprefixed.
739
+ ...(basename ? { urlPrefix: basename } : {}),
703
740
  },
704
741
  () => {
705
742
  handlerResult = urlPatterns.handler() as AllUseItems[];
@@ -719,7 +756,7 @@ export function createRouter<TEnv = any>(
719
756
  if (entry.type === "route" && entry.isPrerender) {
720
757
  if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
721
758
  prerenderRouteKeys.add(name);
722
- if (entry.prerenderDef?.options?.passthrough === true) {
759
+ if (entry.isPassthrough === true) {
723
760
  if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
724
761
  passthroughRouteKeys.add(name);
725
762
  }
@@ -745,6 +782,7 @@ export function createRouter<TEnv = any>(
745
782
  trailingSlash: trailingSlashConfig,
746
783
  handler: urlPatterns.handler,
747
784
  mountIndex: currentMountIndex,
785
+ routerId,
748
786
  cacheProfiles: resolvedCacheProfiles,
749
787
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
750
788
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -764,6 +802,7 @@ export function createRouter<TEnv = any>(
764
802
  trailingSlash: trailingSlashConfig,
765
803
  handler: urlPatterns.handler,
766
804
  mountIndex: currentMountIndex,
805
+ routerId,
767
806
  cacheProfiles: resolvedCacheProfiles,
768
807
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
769
808
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -807,6 +846,7 @@ export function createRouter<TEnv = any>(
807
846
  trailingSlash: trailingSlashConfig,
808
847
  handler: urlPatterns.handler,
809
848
  mountIndex: mountIndex++,
849
+ routerId,
810
850
  // Lazy evaluation fields
811
851
  lazy: true,
812
852
  lazyPatterns: lazyInclude.patterns,
@@ -845,8 +885,18 @@ export function createRouter<TEnv = any>(
845
885
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
846
886
  middleware?: MiddlewareFn<TEnv>,
847
887
  ): any {
848
- // Global middleware - no mount prefix
849
- addMiddleware(patternOrMiddleware, middleware, null);
888
+ // Auto-prefix pattern with basename so router-level middleware
889
+ // patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
890
+ if (basename && typeof patternOrMiddleware === "string") {
891
+ const pattern = patternOrMiddleware;
892
+ const prefixed =
893
+ pattern === "/*" || pattern === "*"
894
+ ? `${basename}/*`
895
+ : `${basename}${pattern}`;
896
+ addMiddleware(prefixed, middleware, null);
897
+ } else {
898
+ addMiddleware(patternOrMiddleware, middleware, null);
899
+ }
850
900
  return router;
851
901
  },
852
902
 
@@ -879,8 +929,9 @@ export function createRouter<TEnv = any>(
879
929
  // Expose resolved cache profiles for per-request resolution
880
930
  cacheProfiles: resolvedCacheProfiles,
881
931
 
882
- // Expose prefetch cache control for RSC handler
932
+ // Expose prefetch cache settings
883
933
  prefetchCacheControl,
934
+ prefetchCacheTTL,
884
935
 
885
936
  // Expose warmup enabled flag for handler and client
886
937
  warmupEnabled,
@@ -946,6 +997,9 @@ export function createRouter<TEnv = any>(
946
997
  // Expose source file for per-router type generation
947
998
  __sourceFile,
948
999
 
1000
+ // Expose basename for runtime manifest generation
1001
+ __basename: basename,
1002
+
949
1003
  // RSC request handler (lazily created on first call)
950
1004
  fetch: (() => {
951
1005
  // Handler is created on first call and reused
@@ -979,6 +1033,10 @@ export function createRouter<TEnv = any>(
979
1033
  };
980
1034
  })(),
981
1035
 
1036
+ // Low-level route matching for request classification
1037
+ findMatch: (pathname: string, metricsStore?: any) =>
1038
+ findMatch(pathname, metricsStore),
1039
+
982
1040
  // Debug utility for manifest inspection
983
1041
  debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
984
1042
  };
@@ -987,7 +1045,9 @@ export function createRouter<TEnv = any>(
987
1045
  RouterRegistry.set(routerId, router);
988
1046
 
989
1047
  // If urls option was provided, auto-register them
990
- if (urlsOption) {
1048
+ if (typeof urlsOption === "function") {
1049
+ return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
1050
+ } else if (urlsOption) {
991
1051
  return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
992
1052
  }
993
1053