@rangojs/router 0.0.0-experimental.d20dd405 → 0.0.0-experimental.dacec167

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 (212) hide show
  1. package/README.md +8 -8
  2. package/dist/bin/rango.js +147 -57
  3. package/dist/testing/vitest.js +82 -0
  4. package/dist/vite/index.js +914 -485
  5. package/package.json +55 -11
  6. package/skills/bundle-analysis/SKILL.md +159 -0
  7. package/skills/cache-guide/SKILL.md +220 -30
  8. package/skills/caching/SKILL.md +116 -8
  9. package/skills/composability/SKILL.md +27 -2
  10. package/skills/document-cache/SKILL.md +78 -55
  11. package/skills/handler-use/SKILL.md +1 -1
  12. package/skills/hooks/SKILL.md +196 -21
  13. package/skills/host-router/SKILL.md +45 -20
  14. package/skills/intercept/SKILL.md +1 -4
  15. package/skills/layout/SKILL.md +4 -7
  16. package/skills/links/SKILL.md +22 -10
  17. package/skills/loader/SKILL.md +149 -6
  18. package/skills/middleware/SKILL.md +13 -9
  19. package/skills/migrate-nextjs/SKILL.md +1 -1
  20. package/skills/mime-routes/SKILL.md +27 -0
  21. package/skills/observability/SKILL.md +137 -0
  22. package/skills/parallel/SKILL.md +3 -6
  23. package/skills/prerender/SKILL.md +14 -33
  24. package/skills/rango/SKILL.md +242 -26
  25. package/skills/react-compiler/SKILL.md +168 -0
  26. package/skills/response-routes/SKILL.md +58 -9
  27. package/skills/route/SKILL.md +9 -4
  28. package/skills/router-setup/SKILL.md +3 -3
  29. package/skills/server-actions/SKILL.md +53 -41
  30. package/skills/testing/SKILL.md +778 -0
  31. package/skills/typesafety/SKILL.md +310 -26
  32. package/skills/use-cache/SKILL.md +34 -5
  33. package/skills/view-transitions/SKILL.md +85 -3
  34. package/src/__augment-tests__/augment.ts +81 -0
  35. package/src/__augment-tests__/augmented.check.ts +117 -0
  36. package/src/browser/action-coordinator.ts +53 -36
  37. package/src/browser/event-controller.ts +42 -66
  38. package/src/browser/history-state.ts +21 -0
  39. package/src/browser/index.ts +3 -3
  40. package/src/browser/navigation-bridge.ts +9 -67
  41. package/src/browser/navigation-client.ts +12 -15
  42. package/src/browser/navigation-store.ts +7 -8
  43. package/src/browser/navigation-transaction.ts +10 -28
  44. package/src/browser/partial-update.ts +8 -16
  45. package/src/browser/react/NavigationProvider.tsx +55 -65
  46. package/src/browser/react/location-state-shared.ts +175 -4
  47. package/src/browser/react/location-state.ts +39 -13
  48. package/src/browser/react/use-handle.ts +17 -9
  49. package/src/browser/react/use-params.ts +3 -4
  50. package/src/browser/react/use-reverse.ts +19 -12
  51. package/src/browser/react/use-router.ts +14 -1
  52. package/src/browser/response-adapter.ts +25 -0
  53. package/src/browser/rsc-router.tsx +30 -16
  54. package/src/browser/scroll-restoration.ts +30 -25
  55. package/src/browser/segment-structure-assert.ts +2 -2
  56. package/src/browser/server-action-bridge.ts +23 -30
  57. package/src/browser/types.ts +2 -0
  58. package/src/build/collect-fallback-refs.ts +107 -0
  59. package/src/build/generate-manifest.ts +60 -35
  60. package/src/build/generate-route-types.ts +2 -0
  61. package/src/build/index.ts +2 -0
  62. package/src/build/route-types/codegen.ts +4 -4
  63. package/src/build/route-types/include-resolution.ts +1 -1
  64. package/src/build/route-types/per-module-writer.ts +7 -4
  65. package/src/build/route-types/router-processing.ts +55 -14
  66. package/src/build/route-types/scan-filter.ts +1 -1
  67. package/src/build/route-types/source-scan.ts +118 -0
  68. package/src/build/runtime-discovery.ts +9 -20
  69. package/src/cache/cache-scope.ts +28 -42
  70. package/src/cache/cf/cf-cache-store.ts +49 -6
  71. package/src/client.tsx +5 -7
  72. package/src/context-var.ts +5 -5
  73. package/src/decode-loader-results.ts +36 -0
  74. package/src/errors.ts +30 -1
  75. package/src/handle.ts +26 -13
  76. package/src/host/index.ts +2 -2
  77. package/src/host/router.ts +129 -57
  78. package/src/host/types.ts +31 -2
  79. package/src/host/utils.ts +1 -1
  80. package/src/href-client.ts +136 -19
  81. package/src/index.rsc.ts +6 -4
  82. package/src/index.ts +13 -6
  83. package/src/loader-store.ts +500 -0
  84. package/src/loader.rsc.ts +21 -6
  85. package/src/loader.ts +3 -10
  86. package/src/missing-id-error.ts +68 -0
  87. package/src/prerender.ts +4 -4
  88. package/src/response-utils.ts +9 -0
  89. package/src/reverse.ts +16 -13
  90. package/src/route-content-wrapper.tsx +6 -28
  91. package/src/route-definition/dsl-helpers.ts +238 -263
  92. package/src/route-definition/helper-factories.ts +29 -139
  93. package/src/route-definition/helpers-types.ts +37 -14
  94. package/src/route-definition/use-item-types.ts +32 -0
  95. package/src/route-types.ts +19 -41
  96. package/src/router/basename.ts +14 -0
  97. package/src/router/content-negotiation.ts +15 -2
  98. package/src/router/error-handling.ts +1 -1
  99. package/src/router/intercept-resolution.ts +4 -18
  100. package/src/router/lazy-includes.ts +2 -2
  101. package/src/router/loader-resolution.ts +16 -2
  102. package/src/router/match-handlers.ts +62 -20
  103. package/src/router/match-middleware/cache-lookup.ts +44 -91
  104. package/src/router/match-middleware/cache-store.ts +3 -2
  105. package/src/router/match-result.ts +32 -30
  106. package/src/router/metrics.ts +1 -1
  107. package/src/router/middleware-types.ts +1 -1
  108. package/src/router/middleware.ts +46 -78
  109. package/src/router/prerender-match.ts +1 -1
  110. package/src/router/preview-match.ts +3 -1
  111. package/src/router/request-classification.ts +4 -28
  112. package/src/router/revalidation.ts +43 -1
  113. package/src/router/router-interfaces.ts +45 -28
  114. package/src/router/router-options.ts +40 -1
  115. package/src/router/router-registry.ts +2 -5
  116. package/src/router/segment-resolution/fresh.ts +19 -6
  117. package/src/router/segment-resolution/revalidation.ts +19 -6
  118. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  119. package/src/router/telemetry.ts +99 -0
  120. package/src/router/types.ts +8 -0
  121. package/src/router.ts +37 -21
  122. package/src/rsc/handler-context.ts +2 -2
  123. package/src/rsc/handler.ts +20 -65
  124. package/src/rsc/helpers.ts +22 -2
  125. package/src/rsc/index.ts +1 -1
  126. package/src/rsc/origin-guard.ts +28 -10
  127. package/src/rsc/response-route-handler.ts +32 -52
  128. package/src/rsc/rsc-rendering.ts +27 -53
  129. package/src/rsc/runtime-warnings.ts +9 -10
  130. package/src/rsc/server-action.ts +13 -37
  131. package/src/rsc/ssr-setup.ts +16 -0
  132. package/src/rsc/types.ts +2 -2
  133. package/src/search-params.ts +4 -4
  134. package/src/segment-system.tsx +64 -49
  135. package/src/serialize.ts +243 -0
  136. package/src/server/context.ts +118 -51
  137. package/src/server/cookie-store.ts +28 -4
  138. package/src/server/request-context.ts +10 -0
  139. package/src/static-handler.ts +1 -1
  140. package/src/testing/cache-status.ts +166 -0
  141. package/src/testing/collect-handle.ts +63 -0
  142. package/src/testing/dispatch.ts +440 -0
  143. package/src/testing/dom.entry.ts +22 -0
  144. package/src/testing/e2e/fixture.ts +154 -0
  145. package/src/testing/e2e/index.ts +149 -0
  146. package/src/testing/e2e/matchers.ts +51 -0
  147. package/src/testing/e2e/page-helpers.ts +272 -0
  148. package/src/testing/e2e/parity.ts +306 -0
  149. package/src/testing/e2e/server.ts +183 -0
  150. package/src/testing/flight-matchers.ts +104 -0
  151. package/src/testing/flight-runtime.d.ts +57 -0
  152. package/src/testing/flight-tree.ts +320 -0
  153. package/src/testing/flight.entry.ts +39 -0
  154. package/src/testing/flight.ts +197 -0
  155. package/src/testing/generated-routes.ts +223 -0
  156. package/src/testing/index.ts +106 -0
  157. package/src/testing/internal/context.ts +331 -0
  158. package/src/testing/internal/flight-client-globals.ts +30 -0
  159. package/src/testing/render-route.tsx +565 -0
  160. package/src/testing/run-loader.ts +341 -0
  161. package/src/testing/run-middleware.ts +188 -0
  162. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  163. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  164. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  165. package/src/testing/vitest-stubs/version.ts +5 -0
  166. package/src/testing/vitest.ts +270 -0
  167. package/src/types/global-namespace.ts +39 -26
  168. package/src/types/handler-context.ts +56 -11
  169. package/src/types/index.ts +1 -0
  170. package/src/types/segments.ts +18 -1
  171. package/src/urls/include-helper.ts +10 -53
  172. package/src/urls/index.ts +0 -3
  173. package/src/urls/path-helper-types.ts +11 -3
  174. package/src/urls/path-helper.ts +17 -52
  175. package/src/urls/pattern-types.ts +36 -19
  176. package/src/urls/response-types.ts +20 -19
  177. package/src/urls/type-extraction.ts +26 -116
  178. package/src/urls/urls-function.ts +1 -5
  179. package/src/use-loader.tsx +413 -42
  180. package/src/vite/debug.ts +1 -0
  181. package/src/vite/discovery/bundle-postprocess.ts +6 -6
  182. package/src/vite/discovery/discover-routers.ts +70 -48
  183. package/src/vite/discovery/discovery-errors.ts +194 -0
  184. package/src/vite/discovery/prerender-collection.ts +19 -25
  185. package/src/vite/discovery/route-types-writer.ts +40 -84
  186. package/src/vite/discovery/state.ts +33 -0
  187. package/src/vite/discovery/virtual-module-codegen.ts +13 -23
  188. package/src/vite/index.ts +2 -0
  189. package/src/vite/plugin-types.ts +67 -0
  190. package/src/vite/plugins/cjs-to-esm.ts +3 -7
  191. package/src/vite/plugins/client-ref-hashing.ts +12 -1
  192. package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -1
  193. package/src/vite/plugins/expose-action-id.ts +2 -2
  194. package/src/vite/plugins/expose-id-utils.ts +12 -8
  195. package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
  196. package/src/vite/plugins/expose-ids/handler-transform.ts +8 -61
  197. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  198. package/src/vite/plugins/expose-internal-ids.ts +47 -67
  199. package/src/vite/plugins/performance-tracks.ts +12 -16
  200. package/src/vite/plugins/use-cache-transform.ts +13 -11
  201. package/src/vite/plugins/version-injector.ts +2 -12
  202. package/src/vite/plugins/version-plugin.ts +59 -2
  203. package/src/vite/plugins/virtual-entries.ts +2 -2
  204. package/src/vite/rango.ts +67 -15
  205. package/src/vite/router-discovery.ts +208 -63
  206. package/src/vite/utils/ast-handler-extract.ts +15 -15
  207. package/src/vite/utils/bundle-analysis.ts +4 -2
  208. package/src/vite/utils/client-chunks.ts +190 -0
  209. package/src/vite/utils/forward-user-plugins.ts +193 -0
  210. package/src/vite/utils/manifest-utils.ts +21 -5
  211. package/src/vite/utils/shared-utils.ts +107 -26
  212. package/src/browser/action-response-classifier.ts +0 -99
@@ -32,35 +32,37 @@ Actions mutate state; route handlers and loaders read the latest state. After
32
32
  an action finishes, Rango performs a server-side revalidation render for the
33
33
  matched route so the UI receives fresh segment output and loader data.
34
34
 
35
- The main control point is `revalidate(({ actionId }) => ...)` on the segment
36
- that owns the data. This applies to `path()` handlers, `layout()` handlers,
37
- `parallel()` slots, `intercept()` routes, and loader registrations:
35
+ The main control point is `revalidate((ctx) => ...)` on the segment that owns
36
+ the data. Match specific actions by imported reference with `ctx.isAction()`;
37
+ use raw `actionId` only when you intentionally need path or directory matching.
38
+ This applies to `path()` handlers, `layout()` handlers, `parallel()` slots,
39
+ `intercept()` routes, and loader registrations:
38
40
 
39
41
  ```typescript
40
42
  // urls.tsx — path/layout/parallel/intercept/loader/revalidate are passed in by urls()
41
43
  import { urls } from "@rangojs/router";
44
+ import * as CartActions from "./actions/cart";
42
45
 
43
46
  export const urlpatterns = urls(({ path, loader, revalidate }) => [
44
47
  // The loader belongs to the route that consumes its data — nest it inside
45
48
  // the owning path() so the segment owns its data dependency.
46
49
  path("/cart", CartPage, { name: "cart" }, () => [
47
- revalidate(
48
- ({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
49
- ),
50
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
50
51
  loader(CartLoader, () => [
51
- revalidate(
52
- ({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
53
- ),
52
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
54
53
  ]),
55
54
  ]),
56
55
  ]);
57
56
  ```
58
57
 
59
- For module-level `"use server"` files, the `actionId` passed to every
58
+ `ctx.isAction()` resolves the imported action reference the same way the router
59
+ derives `actionId`, so it matches in both dev and production and survives action
60
+ renames/moves as type errors instead of silent substring drift.
61
+
62
+ For module-level `"use server"` files, the raw `actionId` passed to every
60
63
  server-side `revalidate()` predicate is path-bearing in the server/RSC
61
- environment in both dev and production: `src/actions/cart.ts#addToCart`. This
62
- is intentional so path, layout, parallel, intercept, and loader revalidation
63
- predicates can filter by action file, directory, or export name.
64
+ environment in both dev and production: `src/actions/cart.ts#addToCart`. This is
65
+ the escape hatch for broad filters by action file, directory, or export name.
64
66
 
65
67
  Actions and the follow-up revalidation render share one request context.
66
68
  Values written in the action with `ctx.set(MyVar, value)` or `ctx.set("key",
@@ -91,15 +93,18 @@ export async function switchTenant(tenantId: string) {
91
93
  ```typescript
92
94
  // urls.tsx
93
95
  import { urls } from "@rangojs/router";
96
+ import * as TenantActions from "./actions/tenant";
94
97
  import { ChangedTenant } from "./context";
95
98
 
96
99
  export const urlpatterns = urls(({ path, revalidate }) => [
97
100
  path("/dashboard/:tenantId", DashboardPage, { name: "dashboard" }, () => [
98
- revalidate(
99
- ({ actionId, context }) =>
100
- actionId?.startsWith("src/actions/tenant.ts#") &&
101
- context.get(ChangedTenant) === context.params.tenantId,
102
- ),
101
+ revalidate((ctx) => {
102
+ if (!ctx.isAction(TenantActions)) return undefined;
103
+ return (
104
+ ctx.context.get(ChangedTenant) === ctx.context.params.tenantId ||
105
+ undefined
106
+ );
107
+ }),
103
108
  ]),
104
109
  ]);
105
110
  ```
@@ -380,13 +385,18 @@ re-render so the UI updates. Rango runs the action, then evaluates
380
385
  `revalidate()` on matched segments and loaders. Each path, layout, parallel,
381
386
  intercept, or loader rule decides whether that piece re-renders/re-resolves.
382
387
 
383
- The `actionId` arrives as part of the revalidation context match it to
384
- scope re-runs to specific actions.
388
+ Use `ctx.isAction()` for specific actions or modules. It accepts one action,
389
+ several actions, or a namespace import (`import * as CartActions`). Pair it with
390
+ `|| undefined` for "revalidate on match, otherwise defer to defaults/downstream
391
+ rules."
385
392
 
386
393
  ```typescript
387
394
  // urls.tsx — inside the urls() callback. Nest each loader inside the path(),
388
395
  // layout(), or parallel() that owns its data so the route tree mirrors the
389
396
  // data dependencies.
397
+ import * as AccountActions from "./actions/account";
398
+ import * as CartActions from "./actions/cart";
399
+
390
400
  urls(({ path, loader, revalidate }) => [
391
401
  path("/", HomePage, { name: "home" }, () => [
392
402
  // Loader data re-runs by default after any action. Opt out with revalidate(() => false).
@@ -395,36 +405,37 @@ urls(({ path, loader, revalidate }) => [
395
405
 
396
406
  // Re-render the cart page handler AND re-resolve its loader after cart actions
397
407
  path("/cart", CartPage, { name: "cart" }, () => [
398
- revalidate(
399
- ({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
400
- ),
408
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
401
409
  loader(CartLoader, () => [
402
- revalidate(
403
- ({ actionId }) => actionId?.startsWith("src/actions/cart.ts#") ?? false,
404
- ),
410
+ revalidate((ctx) => ctx.isAction(CartActions) || undefined),
405
411
  ]),
406
412
  ]),
407
413
 
408
- // Re-run after any action under src/actions/account/
414
+ // Re-run after any action exported by the account actions module
409
415
  path("/account", AccountPage, { name: "account" }, () => [
410
416
  loader(AccountLoader, () => [
411
- revalidate(
412
- ({ actionId }) => actionId?.startsWith("src/actions/account/") ?? false,
413
- ),
417
+ revalidate((ctx) => ctx.isAction(AccountActions) || undefined),
414
418
  ]),
415
419
  ]),
416
420
  ]);
417
421
  ```
418
422
 
419
- `actionId` is stable per action. For actions exported from a module-level
420
- `"use server"` file, the ID is prefixed with the source file path
421
- (`src/actions/cart.ts#addToCart`), so substring matching by file path is the
422
- recommended scope. **Inline `"use server"` actions** (declared inside an RSC
423
- component) intentionally keep their hashed IDs — file paths are withheld
424
- from the client for security. If you need file-path-based revalidation
425
- predicates, define the action in a module-level `"use server"` file rather
426
- than inline. See `/loader` for the full revalidation contract (deferred
427
- returns, soft suggestions).
423
+ The raw `actionId` string stays available for broad path filters:
424
+
425
+ ```typescript
426
+ // Match any action under src/actions/account/, including modules not imported here.
427
+ revalidate(
428
+ ({ actionId }) => actionId?.startsWith("src/actions/account/") || undefined,
429
+ );
430
+ ```
431
+
432
+ For actions exported from a module-level `"use server"` file, the ID is prefixed
433
+ with the source file path (`src/actions/cart.ts#addToCart`). **Inline `"use
434
+ server"` actions** (declared inside an RSC component) intentionally keep their
435
+ hashed IDs — file paths are withheld from the client for security. If you need
436
+ file-path-based revalidation predicates, define the action in a module-level
437
+ `"use server"` file rather than inline. See `/loader` for the full revalidation
438
+ contract (deferred returns, soft suggestions).
428
439
 
429
440
  ### Cross-segment dependencies
430
441
 
@@ -434,8 +445,9 @@ stale context. Share the same `revalidate` predicate on both producer and
434
445
  consumer:
435
446
 
436
447
  ```typescript
437
- const revalidateCart = ({ actionId }) =>
438
- actionId?.startsWith("src/actions/cart.ts#") ?? false;
448
+ import * as CartActions from "./actions/cart";
449
+
450
+ const revalidateCart = (ctx) => ctx.isAction(CartActions) || undefined;
439
451
 
440
452
  urls(({ path, layout, loader, revalidate }) => [
441
453
  layout(CartLayout, () => [