@rangojs/router 0.0.0-experimental.d7eeaa75 → 0.0.0-experimental.dc2bd2b4

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 (253) hide show
  1. package/README.md +120 -25
  2. package/dist/bin/rango.js +147 -57
  3. package/dist/testing/vitest.js +48 -0
  4. package/dist/vite/index.js +2151 -846
  5. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  6. package/package.json +57 -11
  7. package/skills/breadcrumbs/SKILL.md +3 -1
  8. package/skills/bundle-analysis/SKILL.md +159 -0
  9. package/skills/cache-guide/SKILL.md +220 -30
  10. package/skills/caching/SKILL.md +116 -8
  11. package/skills/composability/SKILL.md +27 -2
  12. package/skills/document-cache/SKILL.md +78 -55
  13. package/skills/handler-use/SKILL.md +364 -0
  14. package/skills/hooks/SKILL.md +229 -20
  15. package/skills/host-router/SKILL.md +45 -20
  16. package/skills/i18n/SKILL.md +276 -0
  17. package/skills/intercept/SKILL.md +46 -4
  18. package/skills/layout/SKILL.md +28 -7
  19. package/skills/links/SKILL.md +247 -17
  20. package/skills/loader/SKILL.md +219 -9
  21. package/skills/middleware/SKILL.md +47 -12
  22. package/skills/migrate-nextjs/SKILL.md +562 -0
  23. package/skills/migrate-react-router/SKILL.md +769 -0
  24. package/skills/mime-routes/SKILL.md +27 -0
  25. package/skills/observability/SKILL.md +137 -0
  26. package/skills/parallel/SKILL.md +71 -6
  27. package/skills/prerender/SKILL.md +14 -33
  28. package/skills/rango/SKILL.md +242 -22
  29. package/skills/react-compiler/SKILL.md +168 -0
  30. package/skills/response-routes/SKILL.md +66 -9
  31. package/skills/route/SKILL.md +57 -4
  32. package/skills/router-setup/SKILL.md +3 -3
  33. package/skills/server-actions/SKILL.md +751 -0
  34. package/skills/streams-and-websockets/SKILL.md +283 -0
  35. package/skills/testing/SKILL.md +647 -0
  36. package/skills/typesafety/SKILL.md +319 -27
  37. package/skills/use-cache/SKILL.md +34 -5
  38. package/skills/view-transitions/SKILL.md +294 -0
  39. package/src/__augment-tests__/augment.ts +81 -0
  40. package/src/__augment-tests__/augmented.check.ts +117 -0
  41. package/src/browser/action-coordinator.ts +53 -36
  42. package/src/browser/app-shell.ts +52 -0
  43. package/src/browser/event-controller.ts +86 -70
  44. package/src/browser/history-state.ts +21 -0
  45. package/src/browser/index.ts +3 -3
  46. package/src/browser/navigation-bridge.ts +84 -11
  47. package/src/browser/navigation-client.ts +76 -28
  48. package/src/browser/navigation-store.ts +32 -9
  49. package/src/browser/navigation-transaction.ts +10 -28
  50. package/src/browser/partial-update.ts +64 -26
  51. package/src/browser/prefetch/cache.ts +129 -21
  52. package/src/browser/prefetch/fetch.ts +148 -16
  53. package/src/browser/prefetch/queue.ts +36 -5
  54. package/src/browser/rango-state.ts +53 -13
  55. package/src/browser/react/Link.tsx +30 -2
  56. package/src/browser/react/NavigationProvider.tsx +72 -31
  57. package/src/browser/react/filter-segment-order.ts +51 -7
  58. package/src/browser/react/index.ts +3 -0
  59. package/src/browser/react/location-state-shared.ts +175 -4
  60. package/src/browser/react/location-state.ts +39 -13
  61. package/src/browser/react/use-handle.ts +17 -9
  62. package/src/browser/react/use-navigation.ts +22 -2
  63. package/src/browser/react/use-params.ts +20 -8
  64. package/src/browser/react/use-reverse.ts +106 -0
  65. package/src/browser/react/use-router.ts +22 -2
  66. package/src/browser/react/use-segments.ts +11 -8
  67. package/src/browser/response-adapter.ts +25 -0
  68. package/src/browser/rsc-router.tsx +64 -22
  69. package/src/browser/scroll-restoration.ts +22 -14
  70. package/src/browser/segment-reconciler.ts +36 -14
  71. package/src/browser/segment-structure-assert.ts +2 -2
  72. package/src/browser/server-action-bridge.ts +23 -30
  73. package/src/browser/types.ts +21 -0
  74. package/src/build/collect-fallback-refs.ts +107 -0
  75. package/src/build/generate-manifest.ts +60 -35
  76. package/src/build/generate-route-types.ts +2 -0
  77. package/src/build/index.ts +2 -0
  78. package/src/build/route-trie.ts +52 -25
  79. package/src/build/route-types/codegen.ts +4 -4
  80. package/src/build/route-types/include-resolution.ts +1 -1
  81. package/src/build/route-types/per-module-writer.ts +7 -4
  82. package/src/build/route-types/router-processing.ts +55 -14
  83. package/src/build/route-types/scan-filter.ts +1 -1
  84. package/src/build/route-types/source-scan.ts +118 -0
  85. package/src/build/runtime-discovery.ts +9 -20
  86. package/src/cache/cache-scope.ts +28 -42
  87. package/src/cache/cf/cf-cache-store.ts +54 -13
  88. package/src/client.rsc.tsx +3 -0
  89. package/src/client.tsx +92 -182
  90. package/src/context-var.ts +5 -5
  91. package/src/decode-loader-results.ts +36 -0
  92. package/src/errors.ts +30 -1
  93. package/src/handle.ts +26 -13
  94. package/src/host/index.ts +2 -2
  95. package/src/host/router.ts +129 -57
  96. package/src/host/types.ts +31 -2
  97. package/src/host/utils.ts +1 -1
  98. package/src/href-client.ts +140 -20
  99. package/src/index.rsc.ts +9 -4
  100. package/src/index.ts +53 -15
  101. package/src/loader-store.ts +500 -0
  102. package/src/loader.rsc.ts +2 -5
  103. package/src/loader.ts +3 -10
  104. package/src/missing-id-error.ts +68 -0
  105. package/src/outlet-context.ts +1 -1
  106. package/src/prerender.ts +4 -4
  107. package/src/response-utils.ts +37 -0
  108. package/src/reverse.ts +65 -36
  109. package/src/route-content-wrapper.tsx +6 -28
  110. package/src/route-definition/dsl-helpers.ts +384 -257
  111. package/src/route-definition/helper-factories.ts +29 -139
  112. package/src/route-definition/helpers-types.ts +100 -28
  113. package/src/route-definition/resolve-handler-use.ts +6 -0
  114. package/src/route-definition/use-item-types.ts +32 -0
  115. package/src/route-types.ts +26 -41
  116. package/src/router/basename.ts +14 -0
  117. package/src/router/content-negotiation.ts +15 -2
  118. package/src/router/error-handling.ts +1 -1
  119. package/src/router/handler-context.ts +21 -38
  120. package/src/router/intercept-resolution.ts +4 -18
  121. package/src/router/lazy-includes.ts +8 -8
  122. package/src/router/loader-resolution.ts +19 -2
  123. package/src/router/manifest.ts +22 -13
  124. package/src/router/match-api.ts +4 -3
  125. package/src/router/match-handlers.ts +63 -20
  126. package/src/router/match-middleware/cache-lookup.ts +44 -91
  127. package/src/router/match-middleware/cache-store.ts +3 -2
  128. package/src/router/match-result.ts +53 -32
  129. package/src/router/metrics.ts +1 -1
  130. package/src/router/middleware-types.ts +15 -26
  131. package/src/router/middleware.ts +99 -84
  132. package/src/router/pattern-matching.ts +101 -17
  133. package/src/router/prerender-match.ts +1 -1
  134. package/src/router/preview-match.ts +3 -1
  135. package/src/router/request-classification.ts +4 -28
  136. package/src/router/revalidation.ts +58 -2
  137. package/src/router/router-interfaces.ts +45 -28
  138. package/src/router/router-options.ts +40 -1
  139. package/src/router/router-registry.ts +2 -5
  140. package/src/router/segment-resolution/fresh.ts +27 -6
  141. package/src/router/segment-resolution/revalidation.ts +147 -106
  142. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  143. package/src/router/substitute-pattern-params.ts +56 -0
  144. package/src/router/telemetry.ts +99 -0
  145. package/src/router/trie-matching.ts +18 -13
  146. package/src/router/types.ts +8 -0
  147. package/src/router/url-params.ts +49 -0
  148. package/src/router.ts +38 -23
  149. package/src/rsc/handler-context.ts +2 -2
  150. package/src/rsc/handler.ts +28 -69
  151. package/src/rsc/helpers.ts +91 -43
  152. package/src/rsc/index.ts +1 -1
  153. package/src/rsc/origin-guard.ts +28 -10
  154. package/src/rsc/progressive-enhancement.ts +4 -0
  155. package/src/rsc/response-route-handler.ts +46 -53
  156. package/src/rsc/rsc-rendering.ts +35 -51
  157. package/src/rsc/runtime-warnings.ts +9 -10
  158. package/src/rsc/server-action.ts +17 -37
  159. package/src/rsc/ssr-setup.ts +16 -0
  160. package/src/rsc/types.ts +8 -2
  161. package/src/search-params.ts +4 -4
  162. package/src/segment-content-promise.ts +67 -0
  163. package/src/segment-loader-promise.ts +122 -0
  164. package/src/segment-system.tsx +132 -116
  165. package/src/serialize.ts +243 -0
  166. package/src/server/context.ts +143 -53
  167. package/src/server/cookie-store.ts +28 -4
  168. package/src/server/request-context.ts +20 -42
  169. package/src/ssr/index.tsx +5 -1
  170. package/src/static-handler.ts +1 -1
  171. package/src/testing/cache-status.ts +166 -0
  172. package/src/testing/collect-handle.ts +63 -0
  173. package/src/testing/dispatch.ts +440 -0
  174. package/src/testing/dom.entry.ts +22 -0
  175. package/src/testing/e2e/fixture.ts +154 -0
  176. package/src/testing/e2e/index.ts +149 -0
  177. package/src/testing/e2e/matchers.ts +51 -0
  178. package/src/testing/e2e/page-helpers.ts +272 -0
  179. package/src/testing/e2e/parity.ts +306 -0
  180. package/src/testing/e2e/server.ts +183 -0
  181. package/src/testing/flight-matchers.ts +104 -0
  182. package/src/testing/flight-runtime.d.ts +21 -0
  183. package/src/testing/flight.entry.ts +22 -0
  184. package/src/testing/flight.ts +182 -0
  185. package/src/testing/generated-routes.ts +223 -0
  186. package/src/testing/index.ts +105 -0
  187. package/src/testing/internal/context.ts +193 -0
  188. package/src/testing/render-route.tsx +536 -0
  189. package/src/testing/run-loader.ts +296 -0
  190. package/src/testing/run-middleware.ts +170 -0
  191. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  192. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  193. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  194. package/src/testing/vitest-stubs/version.ts +5 -0
  195. package/src/testing/vitest.ts +183 -0
  196. package/src/types/global-namespace.ts +39 -26
  197. package/src/types/handler-context.ts +68 -50
  198. package/src/types/index.ts +1 -0
  199. package/src/types/loader-types.ts +5 -6
  200. package/src/types/request-scope.ts +126 -0
  201. package/src/types/route-entry.ts +11 -0
  202. package/src/types/segments.ts +35 -2
  203. package/src/urls/include-helper.ts +34 -67
  204. package/src/urls/index.ts +0 -3
  205. package/src/urls/path-helper-types.ts +41 -7
  206. package/src/urls/path-helper.ts +17 -52
  207. package/src/urls/pattern-types.ts +36 -19
  208. package/src/urls/response-types.ts +22 -29
  209. package/src/urls/type-extraction.ts +26 -116
  210. package/src/urls/urls-function.ts +1 -5
  211. package/src/use-loader.tsx +413 -42
  212. package/src/vite/debug.ts +185 -0
  213. package/src/vite/discovery/bundle-postprocess.ts +6 -6
  214. package/src/vite/discovery/discover-routers.ts +101 -51
  215. package/src/vite/discovery/discovery-errors.ts +194 -0
  216. package/src/vite/discovery/gate-state.ts +171 -0
  217. package/src/vite/discovery/prerender-collection.ts +67 -26
  218. package/src/vite/discovery/route-types-writer.ts +40 -84
  219. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  220. package/src/vite/discovery/state.ts +33 -0
  221. package/src/vite/discovery/virtual-module-codegen.ts +13 -23
  222. package/src/vite/index.ts +2 -0
  223. package/src/vite/plugin-types.ts +67 -0
  224. package/src/vite/plugins/cjs-to-esm.ts +8 -7
  225. package/src/vite/plugins/client-ref-dedup.ts +16 -0
  226. package/src/vite/plugins/client-ref-hashing.ts +28 -5
  227. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  228. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  229. package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
  230. package/src/vite/plugins/expose-action-id.ts +54 -30
  231. package/src/vite/plugins/expose-id-utils.ts +12 -8
  232. package/src/vite/plugins/expose-ids/export-analysis.ts +100 -20
  233. package/src/vite/plugins/expose-ids/handler-transform.ts +8 -61
  234. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -5
  235. package/src/vite/plugins/expose-ids/router-transform.ts +20 -3
  236. package/src/vite/plugins/expose-internal-ids.ts +496 -486
  237. package/src/vite/plugins/performance-tracks.ts +29 -25
  238. package/src/vite/plugins/use-cache-transform.ts +65 -50
  239. package/src/vite/plugins/version-injector.ts +39 -23
  240. package/src/vite/plugins/version-plugin.ts +59 -2
  241. package/src/vite/plugins/virtual-entries.ts +2 -2
  242. package/src/vite/rango.ts +116 -29
  243. package/src/vite/router-discovery.ts +750 -100
  244. package/src/vite/utils/ast-handler-extract.ts +15 -15
  245. package/src/vite/utils/banner.ts +1 -1
  246. package/src/vite/utils/bundle-analysis.ts +4 -2
  247. package/src/vite/utils/client-chunks.ts +190 -0
  248. package/src/vite/utils/forward-user-plugins.ts +193 -0
  249. package/src/vite/utils/manifest-utils.ts +21 -5
  250. package/src/vite/utils/package-resolution.ts +41 -1
  251. package/src/vite/utils/prerender-utils.ts +21 -6
  252. package/src/vite/utils/shared-utils.ts +107 -26
  253. package/src/browser/action-response-classifier.ts +0 -99
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Shared internals for the consumer testing primitives.
3
+ *
4
+ * Builds a real RequestContext via the same createRequestContext the RSC
5
+ * handler uses, with test-friendly defaults, so loaders and middleware run
6
+ * with production-fidelity context (cookies, headers, get/set, use, reverse)
7
+ * instead of a hand-rolled mock.
8
+ */
9
+
10
+ import {
11
+ createRequestContext,
12
+ runWithRequestContext,
13
+ type RequestContext,
14
+ } from "../../server/request-context.js";
15
+ import { createReverseFunction } from "../../router/handler-context.js";
16
+ import { normalizeBasename } from "../../router/basename.js";
17
+ import { contextSet, type ContextVar } from "../../context-var.js";
18
+ import type { ThemeConfig } from "../../theme/types.js";
19
+ import { resolveThemeConfig } from "../../theme/constants.js";
20
+ import type { SegmentCacheStore } from "../../cache/types.js";
21
+ import type { CacheProfile } from "../../cache/profile-registry.js";
22
+
23
+ const DEFAULT_ORIGIN = "http://localhost/";
24
+
25
+ /**
26
+ * Initializer for seeded context variables (as a prior middleware would have
27
+ * set). Either a plain object keyed by var name (the common, best-inferring
28
+ * form: `{ user: u }`) or a list of `[key, value]` tuples where the key may be a
29
+ * `createVar()` handle or a string (`[[userVar, u], ["flag", true]]`).
30
+ */
31
+ export type VarsInit =
32
+ | Record<string, unknown>
33
+ | ReadonlyArray<readonly [ContextVar<unknown> | string, unknown]>;
34
+
35
+ /** Normalize a Request | string | undefined into a concrete Request. */
36
+ export function toRequest(
37
+ request: Request | string | undefined,
38
+ init?: RequestInit,
39
+ ): Request {
40
+ if (request instanceof Request) return request;
41
+ if (typeof request === "string") {
42
+ return new Request(new URL(request, DEFAULT_ORIGIN), init);
43
+ }
44
+ return new Request(DEFAULT_ORIGIN, init);
45
+ }
46
+
47
+ /**
48
+ * Preload variables as if set by upstream middleware. Accepts entries keyed by
49
+ * either a ContextVar (from createVar) or a string, matching ctx.set().
50
+ */
51
+ export function seedVariables(
52
+ variables: Record<string, unknown>,
53
+ vars?: VarsInit,
54
+ ): Record<string, unknown> {
55
+ if (!vars) return variables;
56
+ // Array/iterable form -> use the tuples as-is; plain object -> its entries.
57
+ const entries: Iterable<readonly [ContextVar<unknown> | string, unknown]> =
58
+ Symbol.iterator in (vars as object)
59
+ ? (vars as ReadonlyArray<
60
+ readonly [ContextVar<unknown> | string, unknown]
61
+ >)
62
+ : Object.entries(vars as Record<string, unknown>);
63
+ for (const [key, value] of entries) {
64
+ contextSet(variables, key as ContextVar<unknown>, value);
65
+ }
66
+ return variables;
67
+ }
68
+
69
+ export interface CreateTestContextOptions<TEnv> {
70
+ env?: TEnv;
71
+ request?: Request | string;
72
+ requestInit?: RequestInit;
73
+ /** Backing store for ctx.get()/ctx.set(); pre-seeded from `vars`. */
74
+ variables?: Record<string, unknown>;
75
+ /** Variables a prior middleware would have set (object or [key, value] list). */
76
+ vars?: VarsInit;
77
+ /** Route name -> pattern map enabling ctx.reverse() without global state. */
78
+ routeMap?: Record<string, string>;
79
+ routeName?: string;
80
+ params?: Record<string, string>;
81
+ /**
82
+ * Router basename for this request (what the RSC handler stores on the
83
+ * context). Drives redirect() prefixing. Normalized exactly like
84
+ * createRouter({ basename }) (leading slash forced, trailing stripped, bare
85
+ * "/" -> undefined) so passing the same value your router takes yields the
86
+ * same redirect Location. Defaults to undefined (no basename).
87
+ */
88
+ basename?: string;
89
+ /**
90
+ * Cache store backing `use cache` functions invoked during the test, the
91
+ * same shape `createRouter({ cache })` resolves. Without it,
92
+ * registerCachedFunction bypasses (it checks for a store FIRST), so a cached
93
+ * function runs uncached and its taint/profile guards never fire. Wire one
94
+ * (e.g. `new MemorySegmentCacheStore()`) to exercise real cache behavior.
95
+ */
96
+ cacheStore?: SegmentCacheStore;
97
+ /**
98
+ * Cache profiles in the `createRouter({ cacheProfiles })` shape. Required for
99
+ * a `use cache: "profileName"` function to resolve its profile (an unknown
100
+ * profile throws), once a `cacheStore` is wired.
101
+ */
102
+ cacheProfiles?: Record<string, CacheProfile>;
103
+ /**
104
+ * Theme config in the same shape `createRouter({ theme })` takes (resolved
105
+ * internally). Without it `ctx.theme`/`ctx.setTheme` are inert (undefined),
106
+ * mirroring an app with no theme configured. Pass one (e.g. `true`, or
107
+ * `{ themes: [...] }`) to exercise a handler that reads them.
108
+ */
109
+ theme?: ThemeConfig | true;
110
+ }
111
+
112
+ export interface TestRequestContext<TEnv> {
113
+ ctx: RequestContext<TEnv>;
114
+ request: Request;
115
+ url: URL;
116
+ variables: Record<string, unknown>;
117
+ }
118
+
119
+ /**
120
+ * Create a real RequestContext for unit-testing loaders/middleware.
121
+ *
122
+ * The returned `ctx` must be ENTERED before use — wrap your call in
123
+ * `runWithRequestContext(ctx, fn)` (re-exported from `@rangojs/router/testing`)
124
+ * so that cookie/header mutations and `getRequestContext()` resolve. For the
125
+ * common case prefer {@link runInRequestContext}, which builds AND enters the
126
+ * context in a single call.
127
+ */
128
+ export function createTestRequestContext<TEnv>(
129
+ opts: CreateTestContextOptions<TEnv> = {},
130
+ ): TestRequestContext<TEnv> {
131
+ const request = toRequest(opts.request, opts.requestInit);
132
+ const url = new URL(request.url);
133
+ const variables = seedVariables(opts.variables ?? {}, opts.vars);
134
+ const ctx = createRequestContext<TEnv>({
135
+ env: (opts.env ?? {}) as TEnv,
136
+ request,
137
+ url,
138
+ variables,
139
+ themeConfig:
140
+ opts.theme === undefined ? undefined : resolveThemeConfig(opts.theme),
141
+ cacheStore: opts.cacheStore,
142
+ cacheProfiles: opts.cacheProfiles,
143
+ });
144
+ if (opts.basename !== undefined)
145
+ ctx._basename = normalizeBasename(opts.basename);
146
+ if (opts.params) ctx.params = opts.params;
147
+ if (opts.routeMap) {
148
+ ctx._routeName = opts.routeName;
149
+ ctx.reverse = createReverseFunction(
150
+ opts.routeMap,
151
+ opts.routeName,
152
+ opts.params ?? {},
153
+ ) as RequestContext<TEnv>["reverse"];
154
+ }
155
+ return { ctx, request, url, variables };
156
+ }
157
+
158
+ /**
159
+ * Build a seeded RequestContext (via {@link createTestRequestContext}) and run
160
+ * `fn` inside it, so code under test that calls `getRequestContext()`,
161
+ * `cookies()`, or reads/mutates request headers resolves exactly as in
162
+ * production.
163
+ *
164
+ * This is the entry point for the advanced cases the unit wrappers
165
+ * (`runLoader` / `runMiddleware`) do not model — most notably a server ACTION
166
+ * that authenticates off the request cookie: an action has no loader context, so
167
+ * `runLoader` is the wrong shape, yet it still needs a real request context to
168
+ * read the cookie and resolve `getRequestContext()`.
169
+ *
170
+ * `fn` receives the same `RequestContext` `createTestRequestContext` returns; its
171
+ * return value is passed straight through — a returned promise keeps the context
172
+ * active across awaits because it runs inside AsyncLocalStorage.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const session = await runInRequestContext(
177
+ * () => authorizeTenantAction(input),
178
+ * {
179
+ * env,
180
+ * request: new Request("https://app.test/", {
181
+ * headers: { Cookie: "sid=abc" },
182
+ * }),
183
+ * },
184
+ * );
185
+ * ```
186
+ */
187
+ export function runInRequestContext<T, TEnv = unknown>(
188
+ fn: (ctx: RequestContext<TEnv>) => T,
189
+ opts: CreateTestContextOptions<TEnv> = {},
190
+ ): T {
191
+ const { ctx } = createTestRequestContext<TEnv>(opts);
192
+ return runWithRequestContext(ctx, () => fn(ctx));
193
+ }