@rangojs/router 0.1.0 → 0.1.1

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 (89) hide show
  1. package/dist/bin/rango.js +11 -1
  2. package/dist/types/browser/dev-discovery.d.ts +11 -0
  3. package/dist/types/browser/navigation-store.d.ts +3 -13
  4. package/dist/types/browser/prefetch/loader.d.ts +10 -0
  5. package/dist/types/browser/prefetch/runtime.d.ts +3 -0
  6. package/dist/types/browser/types.d.ts +4 -16
  7. package/dist/types/build/generate-manifest.d.ts +6 -0
  8. package/dist/types/cache/cache-scope.d.ts +7 -5
  9. package/dist/types/cache/cf/cf-cache-store.d.ts +10 -9
  10. package/dist/types/cache/memory-segment-store.d.ts +6 -6
  11. package/dist/types/cache/shell-snapshot.d.ts +21 -8
  12. package/dist/types/cache/types.d.ts +24 -7
  13. package/dist/types/cache/vercel/vercel-cache-store.d.ts +9 -8
  14. package/dist/types/dev-discovery-protocol.d.ts +5 -0
  15. package/dist/types/prerender/store.d.ts +1 -0
  16. package/dist/types/route-map-builder.d.ts +4 -29
  17. package/dist/types/router/prerender-match.d.ts +4 -1
  18. package/dist/types/router/router-interfaces.d.ts +3 -1
  19. package/dist/types/rsc/handler-context.d.ts +1 -0
  20. package/dist/types/rsc/render-pipeline.d.ts +3 -2
  21. package/dist/types/rsc/rsc-rendering.d.ts +5 -10
  22. package/dist/types/rsc/shell-capture.d.ts +4 -8
  23. package/dist/types/rsc/types.d.ts +2 -0
  24. package/dist/types/server/context.d.ts +16 -0
  25. package/dist/types/server/request-context.d.ts +18 -8
  26. package/dist/types/server.d.ts +1 -1
  27. package/dist/types/types/route-entry.d.ts +3 -0
  28. package/dist/types/vite/discovery/state.d.ts +3 -2
  29. package/dist/types/vite/utils/manifest-utils.d.ts +1 -1
  30. package/dist/vite/index.js +194 -107
  31. package/package.json +7 -2
  32. package/skills/caching/SKILL.md +1 -1
  33. package/skills/ppr/SKILL.md +48 -4
  34. package/src/browser/dev-discovery.ts +66 -0
  35. package/src/browser/navigation-client.ts +6 -0
  36. package/src/browser/navigation-store.ts +4 -271
  37. package/src/browser/partial-update.ts +7 -14
  38. package/src/browser/prefetch/cache.ts +1 -1
  39. package/src/browser/prefetch/loader.ts +110 -0
  40. package/src/browser/prefetch/runtime.ts +7 -0
  41. package/src/browser/react/Link.tsx +7 -10
  42. package/src/browser/react/NavigationProvider.tsx +1 -1
  43. package/src/browser/react/use-router.ts +1 -1
  44. package/src/browser/rsc-router.tsx +4 -2
  45. package/src/browser/types.ts +4 -27
  46. package/src/build/generate-manifest.ts +11 -0
  47. package/src/cache/cache-scope.ts +17 -6
  48. package/src/cache/cf/cf-cache-store.ts +63 -39
  49. package/src/cache/memory-segment-store.ts +17 -6
  50. package/src/cache/shell-snapshot.ts +45 -15
  51. package/src/cache/types.ts +23 -6
  52. package/src/cache/vercel/vercel-cache-store.ts +52 -22
  53. package/src/dev-discovery-protocol.ts +11 -0
  54. package/src/prerender/build-shell-capture.ts +7 -1
  55. package/src/prerender/store.ts +5 -0
  56. package/src/route-definition/dsl-helpers.ts +7 -2
  57. package/src/route-map-builder.ts +56 -49
  58. package/src/router/handler-context.ts +13 -5
  59. package/src/router/lazy-includes.ts +1 -0
  60. package/src/router/match-api.ts +8 -4
  61. package/src/router/prerender-match.ts +19 -2
  62. package/src/router/router-interfaces.ts +4 -0
  63. package/src/router/segment-resolution/static-store.ts +36 -10
  64. package/src/router.ts +34 -3
  65. package/src/rsc/handler-context.ts +1 -0
  66. package/src/rsc/handler.ts +3 -1
  67. package/src/rsc/loader-fetch.ts +2 -2
  68. package/src/rsc/manifest-init.ts +4 -11
  69. package/src/rsc/render-pipeline.ts +10 -2
  70. package/src/rsc/rsc-rendering.ts +207 -146
  71. package/src/rsc/shell-capture.ts +34 -11
  72. package/src/rsc/types.ts +2 -0
  73. package/src/server/context.ts +28 -0
  74. package/src/server/request-context.ts +32 -10
  75. package/src/server.ts +0 -2
  76. package/src/testing/dispatch.ts +1 -0
  77. package/src/types/route-entry.ts +3 -0
  78. package/src/urls/include-helper.ts +1 -0
  79. package/src/urls/path-helper.ts +8 -4
  80. package/src/vite/discovery/bundle-postprocess.ts +10 -7
  81. package/src/vite/discovery/discover-routers.ts +7 -66
  82. package/src/vite/discovery/prerender-collection.ts +13 -2
  83. package/src/vite/discovery/state.ts +4 -4
  84. package/src/vite/discovery/virtual-module-codegen.ts +75 -42
  85. package/src/vite/plugins/version-injector.ts +0 -1
  86. package/src/vite/plugins/virtual-entries.ts +11 -1
  87. package/src/vite/router-discovery.ts +132 -22
  88. package/src/vite/utils/manifest-utils.ts +1 -4
  89. package/src/vite/utils/shared-utils.ts +7 -0
package/src/router.ts CHANGED
@@ -5,10 +5,14 @@ import { isCachedFunction } from "./cache/taint.js";
5
5
  import { assertClientComponent } from "./component-utils.js";
6
6
  import { DefaultDocument } from "./components/DefaultDocument.js";
7
7
  import type { SerializedManifest } from "./debug.js";
8
+ import {
9
+ DEV_DISCOVERY_EPOCH_HEADER,
10
+ DEV_DISCOVERY_PROBE_HEADER,
11
+ isValidDevDiscoveryEpoch,
12
+ } from "./dev-discovery-protocol.js";
8
13
  import { createReverse, type ReverseFunction } from "./reverse.js";
9
14
  import {
10
15
  registerRouteMap,
11
- getPrecomputedEntries,
12
16
  getRouterManifest,
13
17
  getRouterPrecomputedEntries,
14
18
  ensureRouterManifest,
@@ -229,6 +233,14 @@ export function createRouter<TEnv = any>(
229
233
  // order (unlike the counter which depends on import order).
230
234
  const routerId =
231
235
  userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
236
+ const rawDevDiscoveryEpoch = (
237
+ globalThis as typeof globalThis & {
238
+ __RANGO_DEV_DISCOVERY_EPOCH?: unknown;
239
+ }
240
+ ).__RANGO_DEV_DISCOVERY_EPOCH;
241
+ const devDiscoveryEpoch = isValidDevDiscoveryEpoch(rawDevDiscoveryEpoch)
242
+ ? rawDevDiscoveryEpoch
243
+ : undefined;
232
244
 
233
245
  // Resolve the rango state cookie name once, here, so the two cookie writers
234
246
  // (the client document.cookie writer and the server Set-Cookie writer)
@@ -405,8 +417,7 @@ export function createRouter<TEnv = any>(
405
417
  string,
406
418
  Record<string, string>
407
419
  > | null {
408
- const current =
409
- getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
420
+ const current = getRouterPrecomputedEntries(routerId);
410
421
  if (current !== precomputedSource) {
411
422
  precomputedSource = current;
412
423
  // buildPrecomputedByPrefix drops any staticPrefix owned by more than one
@@ -669,6 +680,7 @@ export function createRouter<TEnv = any>(
669
680
 
670
681
  // Prerender/static match deps (bind closure state for extracted functions)
671
682
  const prerenderDeps = {
683
+ routerId,
672
684
  findMatch,
673
685
  buildRouterContext,
674
686
  mergedRouteMap,
@@ -700,6 +712,7 @@ export function createRouter<TEnv = any>(
700
712
  routeName?: string,
701
713
  buildEnv?: TEnv,
702
714
  devMode?: boolean,
715
+ rootScoped?: boolean,
703
716
  ) {
704
717
  return _renderStaticSegment<TEnv>(
705
718
  handler,
@@ -708,6 +721,8 @@ export function createRouter<TEnv = any>(
708
721
  routeName,
709
722
  buildEnv,
710
723
  devMode,
724
+ routerId,
725
+ rootScoped,
711
726
  );
712
727
  }
713
728
 
@@ -788,6 +803,7 @@ export function createRouter<TEnv = any>(
788
803
  parent: syntheticMapRoot,
789
804
  counters: {},
790
805
  mountIndex: currentMountIndex,
806
+ routerId,
791
807
  cacheProfiles: resolvedCacheProfiles,
792
808
  // basename sets the initial URL prefix so all path() patterns
793
809
  // are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
@@ -1078,6 +1094,9 @@ export function createRouter<TEnv = any>(
1078
1094
  // Expose basename for runtime manifest generation
1079
1095
  __basename: basename,
1080
1096
 
1097
+ // Pin payload metadata to the worker generation that created this router.
1098
+ __devDiscoveryEpoch: devDiscoveryEpoch,
1099
+
1081
1100
  // Expose router-level boundary defaults for build-time clientChunks
1082
1101
  // discovery (so a "use client" default boundary lands in app-fallback).
1083
1102
  // These are createRouter options, never pushed onto EntryData.
@@ -1096,6 +1115,18 @@ export function createRouter<TEnv = any>(
1096
1115
  | null = null;
1097
1116
 
1098
1117
  return async (request: Request, input: RouterRequestInput<TEnv> = {}) => {
1118
+ if (
1119
+ devDiscoveryEpoch !== undefined &&
1120
+ request.headers.get(DEV_DISCOVERY_PROBE_HEADER) ===
1121
+ String(devDiscoveryEpoch)
1122
+ ) {
1123
+ return new Response(null, {
1124
+ headers: {
1125
+ [DEV_DISCOVERY_EPOCH_HEADER]: String(devDiscoveryEpoch),
1126
+ },
1127
+ });
1128
+ }
1129
+
1099
1130
  // Trigger lazy import of per-router manifest data before route matching.
1100
1131
  // No-op if data is already loaded or no loader is registered.
1101
1132
  await ensureRouterManifest(routerId);
@@ -15,6 +15,7 @@ import type { SSRStreamMode } from "../router/router-options.js";
15
15
  export interface HandlerContext<TEnv = unknown> {
16
16
  router: RangoInternal<TEnv, any>;
17
17
  version: string;
18
+ devDiscoveryEpoch?: number;
18
19
  renderToReadableStream: RSCDependencies["renderToReadableStream"];
19
20
  decodeReply: RSCDependencies["decodeReply"];
20
21
  createTemporaryReferenceSet: RSCDependencies["createTemporaryReferenceSet"];
@@ -389,6 +389,7 @@ export function createRSCHandler<
389
389
  const handlerCtx: HandlerContext<TEnv> = {
390
390
  router,
391
391
  version,
392
+ devDiscoveryEpoch: router.__devDiscoveryEpoch,
392
393
  renderToReadableStream,
393
394
  decodeReply,
394
395
  createTemporaryReferenceSet,
@@ -583,6 +584,7 @@ export function createRSCHandler<
583
584
  // - Streaming
584
585
  // Store basename on request context (scoped per-request via existing ALS)
585
586
  requestContext._basename = router.basename;
587
+ requestContext._routerId = router.id;
586
588
 
587
589
  // Resolved span tracing for this request (read at each traced phase).
588
590
  requestContext._tracing = router.tracing;
@@ -1236,7 +1238,7 @@ export function createRSCHandler<
1236
1238
  };
1237
1239
  return renderRscResponse(
1238
1240
  {
1239
- ctx: { renderToReadableStream, callOnError },
1241
+ ctx: handlerCtx,
1240
1242
  request,
1241
1243
  url,
1242
1244
  env,
@@ -209,7 +209,7 @@ export async function handleLoaderFetch<TEnv>(
209
209
  const cleanUrl = stripInternalParams(url);
210
210
  const cleanSearchParams = cleanUrl.searchParams;
211
211
  const searchSchema = reqCtx._routeName
212
- ? getSearchSchema(reqCtx._routeName)
212
+ ? getSearchSchema(reqCtx._routeName, reqCtx._routerId)
213
213
  : undefined;
214
214
  const loaderCtx: any = {
215
215
  ...reqCtx,
@@ -228,7 +228,7 @@ export async function handleLoaderFetch<TEnv>(
228
228
  reqCtx._routeName,
229
229
  mergedParams,
230
230
  reqCtx._routeName
231
- ? isRouteRootScoped(reqCtx._routeName)
231
+ ? isRouteRootScoped(reqCtx._routeName, reqCtx._routerId)
232
232
  : undefined,
233
233
  ),
234
234
  ...(loaderFormData ? { formData: loaderFormData } : {}),
@@ -9,8 +9,6 @@ import {
9
9
  getGlobalRouteMap,
10
10
  hasCachedManifest,
11
11
  setCachedManifest,
12
- getRouteTrie,
13
- setRouteTrie,
14
12
  setRouterManifest,
15
13
  setRouterTrie,
16
14
  setRouterPrecomputedEntries,
@@ -32,11 +30,10 @@ export async function buildRouterTrieFromUrlpatterns(
32
30
  ): Promise<void> {
33
31
  const { generateManifestFull } =
34
32
  await import("../build/generate-manifest.js");
35
- const generated = await generateManifestFull(
36
- router.urlpatterns,
37
- undefined,
38
- router.basename ? { urlPrefix: router.basename } : undefined,
39
- );
33
+ const generated = await generateManifestFull(router.urlpatterns, undefined, {
34
+ routerId: router.id,
35
+ ...(router.basename ? { urlPrefix: router.basename } : {}),
36
+ });
40
37
  // Build the trie through the SAME shared helper the production discovery uses
41
38
  // (discover-routers.ts), so the dev runtime-rebuilt trie and the prod
42
39
  // serialized trie cannot drift. buildPerRouterTrie returns null when there
@@ -45,10 +42,6 @@ export async function buildRouterTrieFromUrlpatterns(
45
42
  const trie = buildPerRouterTrie(generated);
46
43
  if (trie) {
47
44
  setRouterTrie(router.id, trie);
48
- // Set global trie only if not already set by another router
49
- if (!getRouteTrie()) {
50
- setRouteTrie(trie);
51
- }
52
45
  }
53
46
  setRouterManifest(router.id, generated.routeManifest);
54
47
 
@@ -53,8 +53,13 @@ export interface RscRenderStageTracking {
53
53
  span?: TraceSpan;
54
54
  }
55
55
 
56
+ type RscRenderContext<TEnv> = Pick<
57
+ HandlerContext<TEnv>,
58
+ "renderToReadableStream" | "callOnError" | "devDiscoveryEpoch"
59
+ >;
60
+
56
61
  export interface RscRenderInput<TEnv> {
57
- ctx: Pick<HandlerContext<TEnv>, "renderToReadableStream" | "callOnError">;
62
+ ctx: RscRenderContext<TEnv>;
58
63
  request: Request;
59
64
  url: URL;
60
65
  env: TEnv;
@@ -66,7 +71,7 @@ export interface RscRenderInput<TEnv> {
66
71
  }
67
72
 
68
73
  export interface RscFlightStageInput<TEnv> {
69
- ctx: Pick<HandlerContext<TEnv>, "renderToReadableStream" | "callOnError">;
74
+ ctx: RscRenderContext<TEnv>;
70
75
  request: Request;
71
76
  url: URL;
72
77
  env: TEnv;
@@ -146,6 +151,9 @@ function createFlightStage<TEnv>(
146
151
  input: RscFlightStageInput<TEnv>,
147
152
  init: ResponseInit,
148
153
  ): RscFlightStage {
154
+ if (input.ctx.devDiscoveryEpoch !== undefined && input.payload.metadata) {
155
+ input.payload.metadata.devDiscoveryEpoch = input.ctx.devDiscoveryEpoch;
156
+ }
149
157
  const stream = input.ctx.renderToReadableStream<RscPayload>(input.payload, {
150
158
  temporaryReferences: input.temporaryReferences,
151
159
  onError: (error: unknown) => {