@rangojs/router 0.0.0-experimental.10

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 (172) hide show
  1. package/CLAUDE.md +43 -0
  2. package/README.md +19 -0
  3. package/dist/bin/rango.js +227 -0
  4. package/dist/vite/index.js +3039 -0
  5. package/package.json +171 -0
  6. package/skills/caching/SKILL.md +191 -0
  7. package/skills/debug-manifest/SKILL.md +108 -0
  8. package/skills/document-cache/SKILL.md +180 -0
  9. package/skills/fonts/SKILL.md +165 -0
  10. package/skills/hooks/SKILL.md +442 -0
  11. package/skills/intercept/SKILL.md +190 -0
  12. package/skills/layout/SKILL.md +213 -0
  13. package/skills/links/SKILL.md +180 -0
  14. package/skills/loader/SKILL.md +246 -0
  15. package/skills/middleware/SKILL.md +202 -0
  16. package/skills/mime-routes/SKILL.md +124 -0
  17. package/skills/parallel/SKILL.md +228 -0
  18. package/skills/prerender/SKILL.md +283 -0
  19. package/skills/rango/SKILL.md +54 -0
  20. package/skills/response-routes/SKILL.md +358 -0
  21. package/skills/route/SKILL.md +173 -0
  22. package/skills/router-setup/SKILL.md +346 -0
  23. package/skills/tailwind/SKILL.md +129 -0
  24. package/skills/theme/SKILL.md +78 -0
  25. package/skills/typesafety/SKILL.md +394 -0
  26. package/src/__internal.ts +175 -0
  27. package/src/bin/rango.ts +24 -0
  28. package/src/browser/event-controller.ts +876 -0
  29. package/src/browser/index.ts +18 -0
  30. package/src/browser/link-interceptor.ts +121 -0
  31. package/src/browser/lru-cache.ts +69 -0
  32. package/src/browser/merge-segment-loaders.ts +126 -0
  33. package/src/browser/navigation-bridge.ts +913 -0
  34. package/src/browser/navigation-client.ts +165 -0
  35. package/src/browser/navigation-store.ts +823 -0
  36. package/src/browser/partial-update.ts +600 -0
  37. package/src/browser/react/Link.tsx +248 -0
  38. package/src/browser/react/NavigationProvider.tsx +346 -0
  39. package/src/browser/react/ScrollRestoration.tsx +94 -0
  40. package/src/browser/react/context.ts +53 -0
  41. package/src/browser/react/index.ts +52 -0
  42. package/src/browser/react/location-state-shared.ts +120 -0
  43. package/src/browser/react/location-state.ts +62 -0
  44. package/src/browser/react/mount-context.ts +32 -0
  45. package/src/browser/react/use-action.ts +240 -0
  46. package/src/browser/react/use-client-cache.ts +56 -0
  47. package/src/browser/react/use-handle.ts +203 -0
  48. package/src/browser/react/use-href.tsx +40 -0
  49. package/src/browser/react/use-link-status.ts +134 -0
  50. package/src/browser/react/use-mount.ts +31 -0
  51. package/src/browser/react/use-navigation.ts +140 -0
  52. package/src/browser/react/use-segments.ts +188 -0
  53. package/src/browser/request-controller.ts +164 -0
  54. package/src/browser/rsc-router.tsx +352 -0
  55. package/src/browser/scroll-restoration.ts +324 -0
  56. package/src/browser/segment-structure-assert.ts +67 -0
  57. package/src/browser/server-action-bridge.ts +762 -0
  58. package/src/browser/shallow.ts +35 -0
  59. package/src/browser/types.ts +478 -0
  60. package/src/build/generate-manifest.ts +377 -0
  61. package/src/build/generate-route-types.ts +828 -0
  62. package/src/build/index.ts +36 -0
  63. package/src/build/route-trie.ts +239 -0
  64. package/src/cache/cache-scope.ts +563 -0
  65. package/src/cache/cf/cf-cache-store.ts +428 -0
  66. package/src/cache/cf/index.ts +19 -0
  67. package/src/cache/document-cache.ts +340 -0
  68. package/src/cache/index.ts +58 -0
  69. package/src/cache/memory-segment-store.ts +150 -0
  70. package/src/cache/memory-store.ts +253 -0
  71. package/src/cache/types.ts +392 -0
  72. package/src/client.rsc.tsx +83 -0
  73. package/src/client.tsx +643 -0
  74. package/src/component-utils.ts +76 -0
  75. package/src/components/DefaultDocument.tsx +23 -0
  76. package/src/debug.ts +233 -0
  77. package/src/default-error-boundary.tsx +88 -0
  78. package/src/deps/browser.ts +8 -0
  79. package/src/deps/html-stream-client.ts +2 -0
  80. package/src/deps/html-stream-server.ts +2 -0
  81. package/src/deps/rsc.ts +10 -0
  82. package/src/deps/ssr.ts +2 -0
  83. package/src/errors.ts +295 -0
  84. package/src/handle.ts +130 -0
  85. package/src/handles/MetaTags.tsx +193 -0
  86. package/src/handles/index.ts +6 -0
  87. package/src/handles/meta.ts +247 -0
  88. package/src/host/cookie-handler.ts +159 -0
  89. package/src/host/errors.ts +97 -0
  90. package/src/host/index.ts +56 -0
  91. package/src/host/pattern-matcher.ts +214 -0
  92. package/src/host/router.ts +330 -0
  93. package/src/host/testing.ts +79 -0
  94. package/src/host/types.ts +138 -0
  95. package/src/host/utils.ts +25 -0
  96. package/src/href-client.ts +202 -0
  97. package/src/href-context.ts +33 -0
  98. package/src/index.rsc.ts +121 -0
  99. package/src/index.ts +165 -0
  100. package/src/loader.rsc.ts +207 -0
  101. package/src/loader.ts +47 -0
  102. package/src/network-error-thrower.tsx +21 -0
  103. package/src/outlet-context.ts +15 -0
  104. package/src/prerender/param-hash.ts +35 -0
  105. package/src/prerender/store.ts +40 -0
  106. package/src/prerender.ts +156 -0
  107. package/src/reverse.ts +267 -0
  108. package/src/root-error-boundary.tsx +277 -0
  109. package/src/route-content-wrapper.tsx +193 -0
  110. package/src/route-definition.ts +1431 -0
  111. package/src/route-map-builder.ts +242 -0
  112. package/src/route-types.ts +220 -0
  113. package/src/router/error-handling.ts +287 -0
  114. package/src/router/handler-context.ts +158 -0
  115. package/src/router/intercept-resolution.ts +387 -0
  116. package/src/router/loader-resolution.ts +327 -0
  117. package/src/router/manifest.ts +216 -0
  118. package/src/router/match-api.ts +621 -0
  119. package/src/router/match-context.ts +264 -0
  120. package/src/router/match-middleware/background-revalidation.ts +236 -0
  121. package/src/router/match-middleware/cache-lookup.ts +382 -0
  122. package/src/router/match-middleware/cache-store.ts +276 -0
  123. package/src/router/match-middleware/index.ts +81 -0
  124. package/src/router/match-middleware/intercept-resolution.ts +281 -0
  125. package/src/router/match-middleware/segment-resolution.ts +184 -0
  126. package/src/router/match-pipelines.ts +214 -0
  127. package/src/router/match-result.ts +213 -0
  128. package/src/router/metrics.ts +62 -0
  129. package/src/router/middleware.ts +791 -0
  130. package/src/router/pattern-matching.ts +407 -0
  131. package/src/router/revalidation.ts +190 -0
  132. package/src/router/router-context.ts +301 -0
  133. package/src/router/segment-resolution.ts +1315 -0
  134. package/src/router/trie-matching.ts +172 -0
  135. package/src/router/types.ts +163 -0
  136. package/src/router.gen.ts +6 -0
  137. package/src/router.ts +2423 -0
  138. package/src/rsc/handler.ts +1443 -0
  139. package/src/rsc/helpers.ts +64 -0
  140. package/src/rsc/index.ts +56 -0
  141. package/src/rsc/nonce.ts +18 -0
  142. package/src/rsc/types.ts +236 -0
  143. package/src/segment-system.tsx +442 -0
  144. package/src/server/context.ts +466 -0
  145. package/src/server/handle-store.ts +229 -0
  146. package/src/server/loader-registry.ts +174 -0
  147. package/src/server/request-context.ts +554 -0
  148. package/src/server/root-layout.tsx +10 -0
  149. package/src/server/tsconfig.json +14 -0
  150. package/src/server.ts +171 -0
  151. package/src/ssr/index.tsx +296 -0
  152. package/src/theme/ThemeProvider.tsx +291 -0
  153. package/src/theme/ThemeScript.tsx +61 -0
  154. package/src/theme/constants.ts +59 -0
  155. package/src/theme/index.ts +58 -0
  156. package/src/theme/theme-context.ts +70 -0
  157. package/src/theme/theme-script.ts +152 -0
  158. package/src/theme/types.ts +182 -0
  159. package/src/theme/use-theme.ts +44 -0
  160. package/src/types.ts +1757 -0
  161. package/src/urls.gen.ts +8 -0
  162. package/src/urls.ts +1282 -0
  163. package/src/use-loader.tsx +346 -0
  164. package/src/vite/expose-action-id.ts +344 -0
  165. package/src/vite/expose-handle-id.ts +209 -0
  166. package/src/vite/expose-loader-id.ts +426 -0
  167. package/src/vite/expose-location-state-id.ts +177 -0
  168. package/src/vite/expose-prerender-handler-id.ts +429 -0
  169. package/src/vite/index.ts +2068 -0
  170. package/src/vite/package-resolution.ts +125 -0
  171. package/src/vite/version.d.ts +12 -0
  172. package/src/vite/virtual-entries.ts +114 -0
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Router Context using AsyncLocalStorage
3
+ *
4
+ * Provides clean dependency injection for router middleware without parameter drilling.
5
+ * All closure functions from createRouter() are made available via getRouterContext().
6
+ */
7
+ import { AsyncLocalStorage } from "async_hooks";
8
+ import type { CacheScope } from "../cache/cache-scope.js";
9
+ import type {
10
+ EntryData,
11
+ InterceptEntry,
12
+ InterceptSelectorContext,
13
+ MetricsStore,
14
+ } from "../server/context.js";
15
+ import type {
16
+ HandlerContext,
17
+ ResolvedSegment,
18
+ ShouldRevalidateFn,
19
+ } from "../types.js";
20
+ import type { RouteMatchResult } from "./pattern-matching.js";
21
+
22
+ /**
23
+ * Revalidation context passed to segment resolution
24
+ */
25
+ export interface RevalidationContext {
26
+ clientSegmentIds: Set<string>;
27
+ prevParams: Record<string, string>;
28
+ request: Request;
29
+ prevUrl: URL;
30
+ nextUrl: URL;
31
+ routeKey: string;
32
+ actionContext?: {
33
+ actionId?: string;
34
+ actionUrl?: URL;
35
+ actionResult?: any;
36
+ formData?: FormData;
37
+ };
38
+ stale: boolean;
39
+ }
40
+
41
+ /**
42
+ * Result from intercept lookup
43
+ */
44
+ export interface InterceptResult {
45
+ intercept: InterceptEntry;
46
+ entry: EntryData;
47
+ }
48
+
49
+ /**
50
+ * Router context available via AsyncLocalStorage
51
+ *
52
+ * Contains closure functions from createRouter() that middleware needs access to.
53
+ * Instead of passing 20+ parameters, middleware calls getRouterContext() to access them.
54
+ */
55
+ export interface RouterContext<TEnv = any> {
56
+ // Route matching
57
+ findMatch: (pathname: string) => RouteMatchResult | null;
58
+
59
+ // Manifest loading
60
+ loadManifest: (
61
+ entry: any,
62
+ routeKey: string,
63
+ pathname: string,
64
+ metricsStore?: MetricsStore,
65
+ isSSR?: boolean
66
+ ) => Promise<EntryData>;
67
+
68
+ // Entry traversal
69
+ traverseBack: (entry: EntryData) => Generator<EntryData>;
70
+
71
+ // Handler context creation
72
+ createHandlerContext: (
73
+ params: Record<string, string>,
74
+ request: Request,
75
+ searchParams: URLSearchParams,
76
+ pathname: string,
77
+ url: URL,
78
+ bindings?: any,
79
+ routeMap?: Record<string, string>,
80
+ routeName?: string
81
+ ) => HandlerContext<any, TEnv>;
82
+
83
+ // Loader setup
84
+ setupLoaderAccess: (
85
+ ctx: HandlerContext<any, TEnv>,
86
+ loaderPromises: Map<string, Promise<any>>
87
+ ) => void;
88
+
89
+ setupLoaderAccessSilent: (
90
+ ctx: HandlerContext<any, TEnv>,
91
+ loaderPromises: Map<string, Promise<any>>
92
+ ) => void;
93
+
94
+ // Context access
95
+ getContext: () => {
96
+ getOrCreateStore: (key: string) => any;
97
+ runWithStore: <T>(
98
+ store: any,
99
+ namespace: string,
100
+ parent: any,
101
+ fn: () => T
102
+ ) => T;
103
+ };
104
+
105
+ // Metrics
106
+ getMetricsStore: () => MetricsStore | undefined;
107
+
108
+ // Cache
109
+ createCacheScope: (
110
+ cacheConfig: any,
111
+ parent: CacheScope | null
112
+ ) => CacheScope | null;
113
+
114
+ // Intercept detection
115
+ findInterceptForRoute: (
116
+ routeKey: string,
117
+ parentEntry: EntryData | null,
118
+ selectorContext: InterceptSelectorContext,
119
+ isAction: boolean
120
+ ) => InterceptResult | null;
121
+
122
+ // Segment resolution (with revalidation)
123
+ resolveAllSegmentsWithRevalidation: (
124
+ entries: EntryData[],
125
+ routeKey: string,
126
+ params: Record<string, string>,
127
+ handlerContext: HandlerContext<any, TEnv>,
128
+ clientSegmentSet: Set<string>,
129
+ prevParams: Record<string, string>,
130
+ request: Request,
131
+ prevUrl: URL,
132
+ nextUrl: URL,
133
+ loaderPromises: Map<string, Promise<any>>,
134
+ actionContext: any | undefined,
135
+ interceptResult: InterceptResult | null,
136
+ localRouteName: string,
137
+ pathname: string
138
+ ) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
139
+
140
+ // Generator-based segment resolution (for pipeline)
141
+ resolveAllSegmentsWithRevalidationGenerator?: (
142
+ entries: EntryData[],
143
+ routeKey: string,
144
+ params: Record<string, string>,
145
+ handlerContext: HandlerContext<any, TEnv>,
146
+ clientSegmentSet: Set<string>,
147
+ prevParams: Record<string, string>,
148
+ request: Request,
149
+ prevUrl: URL,
150
+ nextUrl: URL,
151
+ loaderPromises: Map<string, Promise<any>>,
152
+ actionContext?: any
153
+ ) => AsyncGenerator<ResolvedSegment | { __type: "id"; id: string }>;
154
+
155
+ // Intercept resolution
156
+ resolveInterceptEntry: (
157
+ intercept: InterceptEntry,
158
+ entry: EntryData,
159
+ params: Record<string, string>,
160
+ handlerContext: HandlerContext<any, TEnv>,
161
+ belongsToRoute: boolean,
162
+ revalidationContext?: RevalidationContext
163
+ ) => Promise<ResolvedSegment[]>;
164
+
165
+ // Collect with markers
166
+ collectWithMarkers?: <T>(
167
+ gen: AsyncGenerator<T | { __type: "id"; id: string }>
168
+ ) => Promise<{ items: T[]; matchedIds: string[] }>;
169
+
170
+ // Revalidation evaluation
171
+ evaluateRevalidation: (params: {
172
+ segment: ResolvedSegment;
173
+ prevParams: Record<string, string>;
174
+ getPrevSegment: (() => Promise<ResolvedSegment | undefined>) | null;
175
+ request: Request;
176
+ prevUrl: URL;
177
+ nextUrl: URL;
178
+ revalidations: Array<{ name: string; fn: any }>;
179
+ routeKey: string;
180
+ context: HandlerContext<any, TEnv>;
181
+ actionContext?: any;
182
+ stale?: boolean;
183
+ }) => Promise<boolean>;
184
+
185
+ // Request context
186
+ getRequestContext: () =>
187
+ | {
188
+ waitUntil: (fn: () => Promise<void>) => void;
189
+ _handleStore?: any;
190
+ }
191
+ | undefined;
192
+
193
+ // Simple segment resolution (without revalidation - for full match)
194
+ resolveAllSegments: (
195
+ entries: EntryData[],
196
+ routeKey: string,
197
+ params: Record<string, string>,
198
+ handlerContext: HandlerContext<any, TEnv>,
199
+ loaderPromises: Map<string, Promise<any>>
200
+ ) => Promise<ResolvedSegment[]>;
201
+
202
+ // Generator-based simple resolution
203
+ resolveAllSegmentsGenerator?: (
204
+ entries: EntryData[],
205
+ routeKey: string,
206
+ params: Record<string, string>,
207
+ handlerContext: HandlerContext<any, TEnv>,
208
+ loaderPromises: Map<string, Promise<any>>
209
+ ) => AsyncGenerator<ResolvedSegment | { __type: "id"; id: string }>;
210
+
211
+ // Collect segments from generator
212
+ collectSegmentsFromGenerator?: <T>(
213
+ gen: AsyncGenerator<T | { __type: "id"; id: string }>
214
+ ) => Promise<T[]>;
215
+
216
+ // Handle store
217
+ createHandleStore: () => any;
218
+
219
+ // Loaders-only resolution (for full match cache hit - no revalidation)
220
+ resolveLoadersOnly?: (
221
+ entries: EntryData[],
222
+ handlerContext: HandlerContext<any, TEnv>
223
+ ) => Promise<ResolvedSegment[]>;
224
+
225
+ // Loaders-only resolution (for cache hit scenarios)
226
+ resolveLoadersOnlyWithRevalidation?: (
227
+ entries: EntryData[],
228
+ handlerContext: HandlerContext<any, TEnv>,
229
+ clientSegmentSet: Set<string>,
230
+ prevParams: Record<string, string>,
231
+ request: Request,
232
+ prevUrl: URL,
233
+ nextUrl: URL,
234
+ routeKey: string,
235
+ actionContext?: any
236
+ ) => Promise<{ segments: ResolvedSegment[]; matchedIds: string[] }>;
237
+
238
+ // Entry revalidation map
239
+ buildEntryRevalidateMap?: (
240
+ entries: EntryData[]
241
+ ) => Map<string, { revalidate: ShouldRevalidateFn[] }>;
242
+
243
+ // Intercept loaders only (for cache hit + intercept scenarios)
244
+ resolveInterceptLoadersOnly?: (
245
+ intercept: InterceptEntry,
246
+ entry: EntryData,
247
+ params: Record<string, string>,
248
+ handlerContext: HandlerContext<any, TEnv>,
249
+ belongsToRoute: boolean,
250
+ revalidationContext: {
251
+ clientSegmentIds: Set<string>;
252
+ prevParams: Record<string, string>;
253
+ request: Request;
254
+ prevUrl: URL;
255
+ nextUrl: URL;
256
+ routeKey: string;
257
+ actionContext?: any;
258
+ stale?: boolean;
259
+ }
260
+ ) => Promise<{
261
+ loaderDataPromise: Promise<any[]> | any[];
262
+ loaderIds: string[];
263
+ } | null>;
264
+ }
265
+
266
+ // AsyncLocalStorage instance for router context
267
+ const routerContext = new AsyncLocalStorage<RouterContext<any>>();
268
+
269
+ /**
270
+ * Get router dependencies from AsyncLocalStorage context
271
+ *
272
+ * @throws Error if called outside of router context (runWithRouterContext)
273
+ */
274
+ export function getRouterContext<TEnv = any>(): RouterContext<TEnv> {
275
+ const deps = routerContext.getStore();
276
+ if (!deps) {
277
+ throw new Error(
278
+ "getRouterContext() called outside of router context. " +
279
+ "Ensure code is running inside runWithRouterContext()."
280
+ );
281
+ }
282
+ return deps as RouterContext<TEnv>;
283
+ }
284
+
285
+ /**
286
+ * Run a function with router dependencies available via getRouterContext()
287
+ *
288
+ * All async code within fn() can call getRouterContext() to access router closures.
289
+ * This works across async boundaries thanks to AsyncLocalStorage.
290
+ *
291
+ * @param deps Router dependencies to make available
292
+ * @param fn Function to run with dependencies available
293
+ * @returns Result of fn()
294
+ */
295
+ export function runWithRouterContext<T, TEnv = any>(
296
+ deps: RouterContext<TEnv>,
297
+ fn: () => T
298
+ ): T {
299
+ return routerContext.run(deps, fn);
300
+ }
301
+