@rangojs/router 0.0.0-experimental.1b930379 → 0.0.0-experimental.1fa245e2

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 (136) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +76 -18
  3. package/dist/bin/rango.js +138 -50
  4. package/dist/vite/index.js +558 -319
  5. package/package.json +16 -15
  6. package/skills/cache-guide/SKILL.md +32 -0
  7. package/skills/caching/SKILL.md +45 -4
  8. package/skills/links/SKILL.md +3 -1
  9. package/skills/loader/SKILL.md +53 -43
  10. package/skills/middleware/SKILL.md +2 -0
  11. package/skills/parallel/SKILL.md +126 -0
  12. package/skills/prerender/SKILL.md +110 -68
  13. package/skills/route/SKILL.md +31 -0
  14. package/skills/router-setup/SKILL.md +87 -2
  15. package/skills/typesafety/SKILL.md +10 -0
  16. package/src/__internal.ts +1 -1
  17. package/src/browser/app-version.ts +14 -0
  18. package/src/browser/event-controller.ts +5 -0
  19. package/src/browser/navigation-bridge.ts +19 -13
  20. package/src/browser/navigation-client.ts +115 -58
  21. package/src/browser/navigation-store.ts +43 -8
  22. package/src/browser/navigation-transaction.ts +11 -9
  23. package/src/browser/partial-update.ts +80 -15
  24. package/src/browser/prefetch/cache.ts +57 -5
  25. package/src/browser/prefetch/fetch.ts +38 -23
  26. package/src/browser/prefetch/queue.ts +92 -20
  27. package/src/browser/prefetch/resource-ready.ts +77 -0
  28. package/src/browser/react/Link.tsx +53 -9
  29. package/src/browser/react/NavigationProvider.tsx +40 -4
  30. package/src/browser/react/context.ts +7 -2
  31. package/src/browser/react/use-handle.ts +9 -58
  32. package/src/browser/react/use-router.ts +21 -8
  33. package/src/browser/rsc-router.tsx +134 -59
  34. package/src/browser/scroll-restoration.ts +41 -42
  35. package/src/browser/segment-reconciler.ts +6 -1
  36. package/src/browser/server-action-bridge.ts +8 -6
  37. package/src/browser/types.ts +36 -5
  38. package/src/build/generate-manifest.ts +6 -6
  39. package/src/build/generate-route-types.ts +3 -0
  40. package/src/build/route-types/include-resolution.ts +8 -1
  41. package/src/build/route-types/router-processing.ts +223 -74
  42. package/src/build/route-types/scan-filter.ts +8 -1
  43. package/src/cache/cache-runtime.ts +15 -11
  44. package/src/cache/cache-scope.ts +48 -7
  45. package/src/cache/cf/cf-cache-store.ts +453 -11
  46. package/src/cache/cf/index.ts +5 -1
  47. package/src/cache/document-cache.ts +17 -7
  48. package/src/cache/index.ts +1 -0
  49. package/src/cache/taint.ts +55 -0
  50. package/src/client.tsx +2 -56
  51. package/src/context-var.ts +72 -2
  52. package/src/debug.ts +2 -2
  53. package/src/handle.ts +40 -0
  54. package/src/index.rsc.ts +3 -1
  55. package/src/index.ts +8 -0
  56. package/src/prerender/store.ts +5 -4
  57. package/src/prerender.ts +138 -77
  58. package/src/reverse.ts +22 -1
  59. package/src/route-definition/dsl-helpers.ts +73 -25
  60. package/src/route-definition/helpers-types.ts +10 -6
  61. package/src/route-definition/index.ts +3 -0
  62. package/src/route-definition/redirect.ts +11 -3
  63. package/src/route-definition/resolve-handler-use.ts +149 -0
  64. package/src/route-map-builder.ts +7 -1
  65. package/src/route-types.ts +11 -0
  66. package/src/router/content-negotiation.ts +100 -1
  67. package/src/router/find-match.ts +4 -2
  68. package/src/router/handler-context.ts +79 -23
  69. package/src/router/intercept-resolution.ts +11 -4
  70. package/src/router/lazy-includes.ts +4 -1
  71. package/src/router/loader-resolution.ts +122 -10
  72. package/src/router/logging.ts +5 -2
  73. package/src/router/manifest.ts +9 -3
  74. package/src/router/match-api.ts +124 -189
  75. package/src/router/match-middleware/background-revalidation.ts +30 -2
  76. package/src/router/match-middleware/cache-lookup.ts +88 -16
  77. package/src/router/match-middleware/cache-store.ts +53 -10
  78. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  79. package/src/router/match-middleware/segment-resolution.ts +61 -5
  80. package/src/router/match-result.ts +22 -6
  81. package/src/router/metrics.ts +6 -1
  82. package/src/router/middleware-types.ts +6 -8
  83. package/src/router/middleware.ts +4 -6
  84. package/src/router/navigation-snapshot.ts +182 -0
  85. package/src/router/prerender-match.ts +110 -10
  86. package/src/router/preview-match.ts +30 -102
  87. package/src/router/request-classification.ts +310 -0
  88. package/src/router/route-snapshot.ts +245 -0
  89. package/src/router/router-context.ts +6 -1
  90. package/src/router/router-interfaces.ts +36 -4
  91. package/src/router/router-options.ts +37 -11
  92. package/src/router/segment-resolution/fresh.ts +183 -20
  93. package/src/router/segment-resolution/helpers.ts +29 -24
  94. package/src/router/segment-resolution/loader-cache.ts +1 -0
  95. package/src/router/segment-resolution/revalidation.ts +412 -297
  96. package/src/router/segment-wrappers.ts +2 -0
  97. package/src/router/types.ts +1 -0
  98. package/src/router.ts +59 -6
  99. package/src/rsc/handler.ts +460 -368
  100. package/src/rsc/manifest-init.ts +5 -1
  101. package/src/rsc/progressive-enhancement.ts +4 -0
  102. package/src/rsc/rsc-rendering.ts +5 -0
  103. package/src/rsc/server-action.ts +2 -0
  104. package/src/rsc/ssr-setup.ts +2 -2
  105. package/src/rsc/types.ts +8 -1
  106. package/src/segment-system.tsx +140 -4
  107. package/src/server/context.ts +140 -14
  108. package/src/server/loader-registry.ts +9 -8
  109. package/src/server/request-context.ts +144 -18
  110. package/src/ssr/index.tsx +4 -0
  111. package/src/static-handler.ts +18 -6
  112. package/src/types/cache-types.ts +4 -4
  113. package/src/types/handler-context.ts +137 -33
  114. package/src/types/loader-types.ts +36 -9
  115. package/src/types/route-entry.ts +8 -1
  116. package/src/types/segments.ts +2 -0
  117. package/src/urls/path-helper-types.ts +9 -2
  118. package/src/urls/path-helper.ts +48 -13
  119. package/src/urls/pattern-types.ts +12 -0
  120. package/src/urls/response-types.ts +16 -6
  121. package/src/use-loader.tsx +73 -4
  122. package/src/vite/discovery/bundle-postprocess.ts +30 -33
  123. package/src/vite/discovery/discover-routers.ts +5 -1
  124. package/src/vite/discovery/prerender-collection.ts +14 -1
  125. package/src/vite/discovery/state.ts +13 -6
  126. package/src/vite/index.ts +4 -0
  127. package/src/vite/plugin-types.ts +51 -79
  128. package/src/vite/plugins/expose-action-id.ts +1 -3
  129. package/src/vite/plugins/performance-tracks.ts +88 -0
  130. package/src/vite/plugins/refresh-cmd.ts +88 -26
  131. package/src/vite/plugins/version-plugin.ts +13 -1
  132. package/src/vite/rango.ts +163 -211
  133. package/src/vite/router-discovery.ts +153 -42
  134. package/src/vite/utils/banner.ts +3 -3
  135. package/src/vite/utils/prerender-utils.ts +18 -0
  136. 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,
@@ -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
 
@@ -526,6 +536,7 @@ export function createRouter<TEnv = any>(
526
536
  trackHandler,
527
537
  findNearestErrorBoundary,
528
538
  findNearestNotFoundBoundary,
539
+ notFoundComponent: notFound,
529
540
  callOnError,
530
541
  };
531
542
 
@@ -560,6 +571,7 @@ export function createRouter<TEnv = any>(
560
571
  mergedRouteMap,
561
572
  nextMountIndex: () => mountIndex++,
562
573
  getPrecomputedByPrefix,
574
+ routerId,
563
575
  };
564
576
 
565
577
  function evaluateLazyEntry(entry: RouteEntry<TEnv>): void {
@@ -613,6 +625,8 @@ export function createRouter<TEnv = any>(
613
625
  params: Record<string, string>,
614
626
  buildVars?: Record<string, any>,
615
627
  isPassthroughRoute?: boolean,
628
+ buildEnv?: TEnv,
629
+ devMode?: boolean,
616
630
  ) {
617
631
  return _matchForPrerender(
618
632
  pathname,
@@ -620,6 +634,8 @@ export function createRouter<TEnv = any>(
620
634
  prerenderDeps,
621
635
  buildVars,
622
636
  isPassthroughRoute,
637
+ buildEnv,
638
+ devMode,
623
639
  );
624
640
  }
625
641
 
@@ -627,12 +643,16 @@ export function createRouter<TEnv = any>(
627
643
  handler: Function,
628
644
  handlerId: string,
629
645
  routeName?: string,
646
+ buildEnv?: TEnv,
647
+ devMode?: boolean,
630
648
  ) {
631
649
  return _renderStaticSegment<TEnv>(
632
650
  handler,
633
651
  handlerId,
634
652
  mergedRouteMap,
635
653
  routeName,
654
+ buildEnv,
655
+ devMode,
636
656
  );
637
657
  }
638
658
 
@@ -657,8 +677,15 @@ export function createRouter<TEnv = any>(
657
677
  const router: RSCRouterInternal<TEnv, {}> = {
658
678
  __brand: RSC_ROUTER_BRAND,
659
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;
660
688
 
661
- routes(urlPatterns: UrlPatterns<TEnv>): any {
662
689
  // Store reference for runtime manifest generation
663
690
  storedUrlPatterns = urlPatterns;
664
691
  const currentMountIndex = mountIndex++;
@@ -689,7 +716,7 @@ export function createRouter<TEnv = any>(
689
716
  errorBoundary: [],
690
717
  notFoundBoundary: [],
691
718
  layout: [],
692
- parallel: [],
719
+ parallel: {},
693
720
  intercept: [],
694
721
  loader: [],
695
722
  };
@@ -706,6 +733,10 @@ export function createRouter<TEnv = any>(
706
733
  counters: {},
707
734
  mountIndex: currentMountIndex,
708
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 } : {}),
709
740
  },
710
741
  () => {
711
742
  handlerResult = urlPatterns.handler() as AllUseItems[];
@@ -725,7 +756,7 @@ export function createRouter<TEnv = any>(
725
756
  if (entry.type === "route" && entry.isPrerender) {
726
757
  if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
727
758
  prerenderRouteKeys.add(name);
728
- if (entry.prerenderDef?.options?.passthrough === true) {
759
+ if (entry.isPassthrough === true) {
729
760
  if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
730
761
  passthroughRouteKeys.add(name);
731
762
  }
@@ -751,6 +782,7 @@ export function createRouter<TEnv = any>(
751
782
  trailingSlash: trailingSlashConfig,
752
783
  handler: urlPatterns.handler,
753
784
  mountIndex: currentMountIndex,
785
+ routerId,
754
786
  cacheProfiles: resolvedCacheProfiles,
755
787
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
756
788
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -770,6 +802,7 @@ export function createRouter<TEnv = any>(
770
802
  trailingSlash: trailingSlashConfig,
771
803
  handler: urlPatterns.handler,
772
804
  mountIndex: currentMountIndex,
805
+ routerId,
773
806
  cacheProfiles: resolvedCacheProfiles,
774
807
  ...(prerenderRouteKeys ? { prerenderRouteKeys } : {}),
775
808
  ...(passthroughRouteKeys ? { passthroughRouteKeys } : {}),
@@ -813,6 +846,7 @@ export function createRouter<TEnv = any>(
813
846
  trailingSlash: trailingSlashConfig,
814
847
  handler: urlPatterns.handler,
815
848
  mountIndex: mountIndex++,
849
+ routerId,
816
850
  // Lazy evaluation fields
817
851
  lazy: true,
818
852
  lazyPatterns: lazyInclude.patterns,
@@ -851,8 +885,18 @@ export function createRouter<TEnv = any>(
851
885
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
852
886
  middleware?: MiddlewareFn<TEnv>,
853
887
  ): any {
854
- // Global middleware - no mount prefix
855
- 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
+ }
856
900
  return router;
857
901
  },
858
902
 
@@ -953,6 +997,9 @@ export function createRouter<TEnv = any>(
953
997
  // Expose source file for per-router type generation
954
998
  __sourceFile,
955
999
 
1000
+ // Expose basename for runtime manifest generation
1001
+ __basename: basename,
1002
+
956
1003
  // RSC request handler (lazily created on first call)
957
1004
  fetch: (() => {
958
1005
  // Handler is created on first call and reused
@@ -986,6 +1033,10 @@ export function createRouter<TEnv = any>(
986
1033
  };
987
1034
  })(),
988
1035
 
1036
+ // Low-level route matching for request classification
1037
+ findMatch: (pathname: string, metricsStore?: any) =>
1038
+ findMatch(pathname, metricsStore),
1039
+
989
1040
  // Debug utility for manifest inspection
990
1041
  debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
991
1042
  };
@@ -994,7 +1045,9 @@ export function createRouter<TEnv = any>(
994
1045
  RouterRegistry.set(routerId, router);
995
1046
 
996
1047
  // If urls option was provided, auto-register them
997
- if (urlsOption) {
1048
+ if (typeof urlsOption === "function") {
1049
+ return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
1050
+ } else if (urlsOption) {
998
1051
  return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
999
1052
  }
1000
1053