@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.80

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 (312) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +942 -4
  3. package/dist/bin/rango.js +1689 -0
  4. package/dist/vite/index.js +4960 -935
  5. package/package.json +70 -60
  6. package/skills/breadcrumbs/SKILL.md +250 -0
  7. package/skills/cache-guide/SKILL.md +294 -0
  8. package/skills/caching/SKILL.md +93 -23
  9. package/skills/composability/SKILL.md +172 -0
  10. package/skills/debug-manifest/SKILL.md +12 -8
  11. package/skills/document-cache/SKILL.md +18 -16
  12. package/skills/fonts/SKILL.md +167 -0
  13. package/skills/handler-use/SKILL.md +362 -0
  14. package/skills/hooks/SKILL.md +334 -72
  15. package/skills/host-router/SKILL.md +218 -0
  16. package/skills/intercept/SKILL.md +151 -8
  17. package/skills/layout/SKILL.md +122 -3
  18. package/skills/links/SKILL.md +92 -31
  19. package/skills/loader/SKILL.md +404 -44
  20. package/skills/middleware/SKILL.md +205 -37
  21. package/skills/migrate-nextjs/SKILL.md +560 -0
  22. package/skills/migrate-react-router/SKILL.md +764 -0
  23. package/skills/mime-routes/SKILL.md +128 -0
  24. package/skills/parallel/SKILL.md +263 -1
  25. package/skills/prerender/SKILL.md +685 -0
  26. package/skills/rango/SKILL.md +87 -16
  27. package/skills/response-routes/SKILL.md +411 -0
  28. package/skills/route/SKILL.md +281 -14
  29. package/skills/router-setup/SKILL.md +210 -32
  30. package/skills/tailwind/SKILL.md +129 -0
  31. package/skills/theme/SKILL.md +9 -8
  32. package/skills/typesafety/SKILL.md +328 -89
  33. package/skills/use-cache/SKILL.md +324 -0
  34. package/src/__internal.ts +102 -4
  35. package/src/bin/rango.ts +321 -0
  36. package/src/browser/action-coordinator.ts +97 -0
  37. package/src/browser/action-response-classifier.ts +99 -0
  38. package/src/browser/app-version.ts +14 -0
  39. package/src/browser/event-controller.ts +92 -64
  40. package/src/browser/history-state.ts +80 -0
  41. package/src/browser/intercept-utils.ts +52 -0
  42. package/src/browser/link-interceptor.ts +24 -4
  43. package/src/browser/logging.ts +55 -0
  44. package/src/browser/merge-segment-loaders.ts +20 -12
  45. package/src/browser/navigation-bridge.ts +317 -560
  46. package/src/browser/navigation-client.ts +206 -68
  47. package/src/browser/navigation-store.ts +73 -55
  48. package/src/browser/navigation-transaction.ts +297 -0
  49. package/src/browser/network-error-handler.ts +61 -0
  50. package/src/browser/partial-update.ts +343 -316
  51. package/src/browser/prefetch/cache.ts +216 -0
  52. package/src/browser/prefetch/fetch.ts +206 -0
  53. package/src/browser/prefetch/observer.ts +65 -0
  54. package/src/browser/prefetch/policy.ts +48 -0
  55. package/src/browser/prefetch/queue.ts +160 -0
  56. package/src/browser/prefetch/resource-ready.ts +77 -0
  57. package/src/browser/rango-state.ts +112 -0
  58. package/src/browser/react/Link.tsx +253 -74
  59. package/src/browser/react/NavigationProvider.tsx +87 -11
  60. package/src/browser/react/context.ts +11 -0
  61. package/src/browser/react/filter-segment-order.ts +11 -0
  62. package/src/browser/react/index.ts +12 -12
  63. package/src/browser/react/location-state-shared.ts +95 -53
  64. package/src/browser/react/location-state.ts +60 -15
  65. package/src/browser/react/mount-context.ts +6 -1
  66. package/src/browser/react/nonce-context.ts +23 -0
  67. package/src/browser/react/shallow-equal.ts +27 -0
  68. package/src/browser/react/use-action.ts +29 -51
  69. package/src/browser/react/use-client-cache.ts +5 -3
  70. package/src/browser/react/use-handle.ts +30 -126
  71. package/src/browser/react/use-href.tsx +2 -2
  72. package/src/browser/react/use-link-status.ts +6 -5
  73. package/src/browser/react/use-navigation.ts +44 -65
  74. package/src/browser/react/use-params.ts +65 -0
  75. package/src/browser/react/use-pathname.ts +47 -0
  76. package/src/browser/react/use-router.ts +76 -0
  77. package/src/browser/react/use-search-params.ts +56 -0
  78. package/src/browser/react/use-segments.ts +80 -97
  79. package/src/browser/response-adapter.ts +73 -0
  80. package/src/browser/rsc-router.tsx +214 -58
  81. package/src/browser/scroll-restoration.ts +127 -52
  82. package/src/browser/segment-reconciler.ts +243 -0
  83. package/src/browser/segment-structure-assert.ts +16 -0
  84. package/src/browser/server-action-bridge.ts +510 -603
  85. package/src/browser/shallow.ts +6 -1
  86. package/src/browser/types.ts +141 -48
  87. package/src/browser/validate-redirect-origin.ts +29 -0
  88. package/src/build/generate-manifest.ts +235 -24
  89. package/src/build/generate-route-types.ts +39 -0
  90. package/src/build/index.ts +13 -0
  91. package/src/build/route-trie.ts +291 -0
  92. package/src/build/route-types/ast-helpers.ts +25 -0
  93. package/src/build/route-types/ast-route-extraction.ts +98 -0
  94. package/src/build/route-types/codegen.ts +102 -0
  95. package/src/build/route-types/include-resolution.ts +418 -0
  96. package/src/build/route-types/param-extraction.ts +48 -0
  97. package/src/build/route-types/per-module-writer.ts +128 -0
  98. package/src/build/route-types/router-processing.ts +618 -0
  99. package/src/build/route-types/scan-filter.ts +85 -0
  100. package/src/build/runtime-discovery.ts +231 -0
  101. package/src/cache/background-task.ts +34 -0
  102. package/src/cache/cache-key-utils.ts +44 -0
  103. package/src/cache/cache-policy.ts +125 -0
  104. package/src/cache/cache-runtime.ts +342 -0
  105. package/src/cache/cache-scope.ts +167 -309
  106. package/src/cache/cf/cf-cache-store.ts +571 -17
  107. package/src/cache/cf/index.ts +13 -3
  108. package/src/cache/document-cache.ts +116 -77
  109. package/src/cache/handle-capture.ts +81 -0
  110. package/src/cache/handle-snapshot.ts +41 -0
  111. package/src/cache/index.ts +1 -15
  112. package/src/cache/memory-segment-store.ts +191 -13
  113. package/src/cache/profile-registry.ts +73 -0
  114. package/src/cache/read-through-swr.ts +134 -0
  115. package/src/cache/segment-codec.ts +256 -0
  116. package/src/cache/taint.ts +153 -0
  117. package/src/cache/types.ts +72 -122
  118. package/src/client.rsc.tsx +3 -1
  119. package/src/client.tsx +135 -301
  120. package/src/component-utils.ts +4 -4
  121. package/src/components/DefaultDocument.tsx +5 -1
  122. package/src/context-var.ts +156 -0
  123. package/src/debug.ts +19 -9
  124. package/src/errors.ts +108 -2
  125. package/src/handle.ts +55 -29
  126. package/src/handles/MetaTags.tsx +73 -20
  127. package/src/handles/breadcrumbs.ts +66 -0
  128. package/src/handles/index.ts +1 -0
  129. package/src/handles/meta.ts +30 -13
  130. package/src/host/cookie-handler.ts +21 -15
  131. package/src/host/errors.ts +8 -8
  132. package/src/host/index.ts +4 -7
  133. package/src/host/pattern-matcher.ts +27 -27
  134. package/src/host/router.ts +61 -39
  135. package/src/host/testing.ts +8 -8
  136. package/src/host/types.ts +15 -7
  137. package/src/host/utils.ts +1 -1
  138. package/src/href-client.ts +119 -29
  139. package/src/index.rsc.ts +155 -19
  140. package/src/index.ts +251 -30
  141. package/src/internal-debug.ts +11 -0
  142. package/src/loader.rsc.ts +26 -157
  143. package/src/loader.ts +27 -10
  144. package/src/network-error-thrower.tsx +3 -1
  145. package/src/outlet-provider.tsx +45 -0
  146. package/src/prerender/param-hash.ts +37 -0
  147. package/src/prerender/store.ts +186 -0
  148. package/src/prerender.ts +524 -0
  149. package/src/reverse.ts +354 -0
  150. package/src/root-error-boundary.tsx +41 -29
  151. package/src/route-content-wrapper.tsx +7 -4
  152. package/src/route-definition/dsl-helpers.ts +1121 -0
  153. package/src/route-definition/helper-factories.ts +200 -0
  154. package/src/route-definition/helpers-types.ts +478 -0
  155. package/src/route-definition/index.ts +55 -0
  156. package/src/route-definition/redirect.ts +101 -0
  157. package/src/route-definition/resolve-handler-use.ts +149 -0
  158. package/src/route-definition.ts +1 -1428
  159. package/src/route-map-builder.ts +217 -123
  160. package/src/route-name.ts +53 -0
  161. package/src/route-types.ts +77 -8
  162. package/src/router/content-negotiation.ts +215 -0
  163. package/src/router/debug-manifest.ts +72 -0
  164. package/src/router/error-handling.ts +9 -9
  165. package/src/router/find-match.ts +160 -0
  166. package/src/router/handler-context.ts +438 -86
  167. package/src/router/intercept-resolution.ts +402 -0
  168. package/src/router/lazy-includes.ts +237 -0
  169. package/src/router/loader-resolution.ts +356 -128
  170. package/src/router/logging.ts +251 -0
  171. package/src/router/manifest.ts +163 -35
  172. package/src/router/match-api.ts +555 -0
  173. package/src/router/match-context.ts +5 -3
  174. package/src/router/match-handlers.ts +440 -0
  175. package/src/router/match-middleware/background-revalidation.ts +108 -93
  176. package/src/router/match-middleware/cache-lookup.ts +460 -10
  177. package/src/router/match-middleware/cache-store.ts +98 -26
  178. package/src/router/match-middleware/intercept-resolution.ts +57 -17
  179. package/src/router/match-middleware/segment-resolution.ts +80 -6
  180. package/src/router/match-pipelines.ts +10 -45
  181. package/src/router/match-result.ts +135 -35
  182. package/src/router/metrics.ts +240 -15
  183. package/src/router/middleware-cookies.ts +55 -0
  184. package/src/router/middleware-types.ts +220 -0
  185. package/src/router/middleware.ts +324 -369
  186. package/src/router/navigation-snapshot.ts +182 -0
  187. package/src/router/pattern-matching.ts +211 -43
  188. package/src/router/prerender-match.ts +502 -0
  189. package/src/router/preview-match.ts +98 -0
  190. package/src/router/request-classification.ts +310 -0
  191. package/src/router/revalidation.ts +137 -38
  192. package/src/router/route-snapshot.ts +245 -0
  193. package/src/router/router-context.ts +41 -21
  194. package/src/router/router-interfaces.ts +484 -0
  195. package/src/router/router-options.ts +618 -0
  196. package/src/router/router-registry.ts +24 -0
  197. package/src/router/segment-resolution/fresh.ts +748 -0
  198. package/src/router/segment-resolution/helpers.ts +268 -0
  199. package/src/router/segment-resolution/loader-cache.ts +199 -0
  200. package/src/router/segment-resolution/revalidation.ts +1379 -0
  201. package/src/router/segment-resolution/static-store.ts +67 -0
  202. package/src/router/segment-resolution.ts +21 -0
  203. package/src/router/segment-wrappers.ts +291 -0
  204. package/src/router/telemetry-otel.ts +299 -0
  205. package/src/router/telemetry.ts +300 -0
  206. package/src/router/timeout.ts +148 -0
  207. package/src/router/trie-matching.ts +239 -0
  208. package/src/router/types.ts +78 -3
  209. package/src/router.ts +740 -4252
  210. package/src/rsc/handler-context.ts +45 -0
  211. package/src/rsc/handler.ts +907 -797
  212. package/src/rsc/helpers.ts +140 -6
  213. package/src/rsc/index.ts +0 -20
  214. package/src/rsc/loader-fetch.ts +229 -0
  215. package/src/rsc/manifest-init.ts +90 -0
  216. package/src/rsc/nonce.ts +14 -0
  217. package/src/rsc/origin-guard.ts +141 -0
  218. package/src/rsc/progressive-enhancement.ts +391 -0
  219. package/src/rsc/response-error.ts +37 -0
  220. package/src/rsc/response-route-handler.ts +347 -0
  221. package/src/rsc/rsc-rendering.ts +246 -0
  222. package/src/rsc/runtime-warnings.ts +42 -0
  223. package/src/rsc/server-action.ts +356 -0
  224. package/src/rsc/ssr-setup.ts +128 -0
  225. package/src/rsc/types.ts +46 -11
  226. package/src/search-params.ts +230 -0
  227. package/src/segment-content-promise.ts +67 -0
  228. package/src/segment-loader-promise.ts +122 -0
  229. package/src/segment-system.tsx +134 -36
  230. package/src/server/context.ts +341 -61
  231. package/src/server/cookie-store.ts +190 -0
  232. package/src/server/fetchable-loader-store.ts +37 -0
  233. package/src/server/handle-store.ts +113 -15
  234. package/src/server/loader-registry.ts +24 -64
  235. package/src/server/request-context.ts +607 -81
  236. package/src/server.ts +35 -130
  237. package/src/ssr/index.tsx +103 -30
  238. package/src/static-handler.ts +126 -0
  239. package/src/theme/ThemeProvider.tsx +21 -15
  240. package/src/theme/ThemeScript.tsx +5 -5
  241. package/src/theme/constants.ts +5 -2
  242. package/src/theme/index.ts +4 -14
  243. package/src/theme/theme-context.ts +4 -30
  244. package/src/theme/theme-script.ts +21 -18
  245. package/src/types/boundaries.ts +158 -0
  246. package/src/types/cache-types.ts +198 -0
  247. package/src/types/error-types.ts +192 -0
  248. package/src/types/global-namespace.ts +100 -0
  249. package/src/types/handler-context.ts +791 -0
  250. package/src/types/index.ts +88 -0
  251. package/src/types/loader-types.ts +210 -0
  252. package/src/types/route-config.ts +170 -0
  253. package/src/types/route-entry.ts +120 -0
  254. package/src/types/segments.ts +150 -0
  255. package/src/types.ts +1 -1623
  256. package/src/urls/include-helper.ts +207 -0
  257. package/src/urls/index.ts +53 -0
  258. package/src/urls/path-helper-types.ts +372 -0
  259. package/src/urls/path-helper.ts +364 -0
  260. package/src/urls/pattern-types.ts +107 -0
  261. package/src/urls/response-types.ts +116 -0
  262. package/src/urls/type-extraction.ts +372 -0
  263. package/src/urls/urls-function.ts +98 -0
  264. package/src/urls.ts +1 -802
  265. package/src/use-loader.tsx +161 -81
  266. package/src/vite/discovery/bundle-postprocess.ts +181 -0
  267. package/src/vite/discovery/discover-routers.ts +348 -0
  268. package/src/vite/discovery/prerender-collection.ts +439 -0
  269. package/src/vite/discovery/route-types-writer.ts +258 -0
  270. package/src/vite/discovery/self-gen-tracking.ts +47 -0
  271. package/src/vite/discovery/state.ts +117 -0
  272. package/src/vite/discovery/virtual-module-codegen.ts +203 -0
  273. package/src/vite/index.ts +15 -1133
  274. package/src/vite/plugin-types.ts +103 -0
  275. package/src/vite/plugins/cjs-to-esm.ts +93 -0
  276. package/src/vite/plugins/client-ref-dedup.ts +115 -0
  277. package/src/vite/plugins/client-ref-hashing.ts +105 -0
  278. package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
  279. package/src/vite/plugins/expose-id-utils.ts +299 -0
  280. package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
  281. package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
  282. package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
  283. package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
  284. package/src/vite/plugins/expose-ids/types.ts +45 -0
  285. package/src/vite/plugins/expose-internal-ids.ts +786 -0
  286. package/src/vite/plugins/performance-tracks.ts +88 -0
  287. package/src/vite/plugins/refresh-cmd.ts +127 -0
  288. package/src/vite/plugins/use-cache-transform.ts +323 -0
  289. package/src/vite/plugins/version-injector.ts +83 -0
  290. package/src/vite/plugins/version-plugin.ts +266 -0
  291. package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
  292. package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
  293. package/src/vite/rango.ts +462 -0
  294. package/src/vite/router-discovery.ts +918 -0
  295. package/src/vite/utils/ast-handler-extract.ts +517 -0
  296. package/src/vite/utils/banner.ts +36 -0
  297. package/src/vite/utils/bundle-analysis.ts +137 -0
  298. package/src/vite/utils/manifest-utils.ts +70 -0
  299. package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
  300. package/src/vite/utils/prerender-utils.ts +221 -0
  301. package/src/vite/utils/shared-utils.ts +170 -0
  302. package/CLAUDE.md +0 -43
  303. package/src/browser/lru-cache.ts +0 -69
  304. package/src/browser/request-controller.ts +0 -164
  305. package/src/cache/memory-store.ts +0 -253
  306. package/src/href-context.ts +0 -33
  307. package/src/href.ts +0 -255
  308. package/src/server/route-manifest-cache.ts +0 -173
  309. package/src/vite/expose-handle-id.ts +0 -209
  310. package/src/vite/expose-loader-id.ts +0 -426
  311. package/src/vite/expose-location-state-id.ts +0 -177
  312. /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
@@ -1,173 +0,0 @@
1
- /**
2
- * Route Manifest Cache
3
- *
4
- * Three-tier caching strategy for route manifest data:
5
- * 1. In-memory (same isolate) - instant
6
- * 2. SegmentCacheStore (caches.default on Cloudflare) - ~1-2ms
7
- * 3. Generate on-demand (cache miss) - ~98ms
8
- *
9
- * Benefits:
10
- * - Removes 725KB bundled manifest from worker code
11
- * - Typical cold start: 0-2ms (cache hit)
12
- * - Worst case: ~98ms (first request per colo)
13
- */
14
-
15
- import type { SegmentCacheStore, CachedEntryData } from "../cache/types.js";
16
- import type { GeneratedManifest } from "../build/generate-manifest.js";
17
- import { setCachedManifest, hasCachedManifest } from "../route-map-builder.js";
18
-
19
- /**
20
- * Cached route data structure
21
- */
22
- interface CachedRouteData {
23
- /** Route name → pattern mapping for href() */
24
- routeManifest: Record<string, string>;
25
- /** Version string for cache invalidation */
26
- version: string;
27
- }
28
-
29
- // ============================================================================
30
- // Tier 1: In-memory singleton (same isolate - instant)
31
- // ============================================================================
32
-
33
- let memoryManifest: CachedRouteData | null = null;
34
-
35
- /**
36
- * Options for getRouteManifestData
37
- */
38
- export interface GetRouteManifestOptions {
39
- /** Cache store implementation (e.g., CFCacheStore). If omitted, memory-only caching is used. */
40
- store?: SegmentCacheStore;
41
- /** Optional function to schedule non-blocking cache write (e.g., ctx.waitUntil) */
42
- waitUntil?: (promise: Promise<void>) => void;
43
- }
44
-
45
- /**
46
- * Get route manifest data with caching:
47
- * 1. In-memory (same isolate) - instant
48
- * 2. SegmentCacheStore (if provided, e.g., CFCacheStore on Cloudflare) - ~1-2ms
49
- * 3. Generate on-demand (cache miss) - ~98ms
50
- *
51
- * When no store is provided, only in-memory caching is used (memory-only mode).
52
- * This is suitable for development or when external cache is not available.
53
- *
54
- * @param generateFn - Function to generate manifest on cache miss
55
- * @param version - Version string for cache invalidation
56
- * @param options - Optional cache store and waitUntil function
57
- * @returns Cached or freshly generated route data
58
- */
59
- export async function getRouteManifestData(
60
- generateFn: () => GeneratedManifest,
61
- version: string,
62
- options?: GetRouteManifestOptions
63
- ): Promise<CachedRouteData> {
64
- const { store, waitUntil } = options ?? {};
65
- const cacheKey = `route-manifest:${version}`;
66
-
67
- const startTime = performance.now();
68
-
69
- // 1. In-memory check (same isolate) - instant
70
- if (memoryManifest?.version === version) {
71
- console.log("[route-manifest] HIT memory cache (same isolate)");
72
- return memoryManifest;
73
- }
74
-
75
- // 2. Cache store check (if store provided) - ~1-2ms
76
- if (store) {
77
- try {
78
- const cached = await store.get(cacheKey);
79
- if (cached?.data) {
80
- // Extract manifest from the CachedEntryData wrapper
81
- const manifest = (cached.data as unknown as { manifest: CachedRouteData }).manifest;
82
- if (manifest?.version === version) {
83
- memoryManifest = manifest;
84
- setCachedManifest(memoryManifest.routeManifest);
85
- const duration = (performance.now() - startTime).toFixed(2);
86
- console.log(`[route-manifest] HIT edge cache (${duration}ms, ${Object.keys(manifest.routeManifest).length} routes)`);
87
- return memoryManifest;
88
- }
89
- }
90
- } catch (error) {
91
- // Cache miss or error - fall through to generation
92
- console.warn("[route-manifest] Edge cache read failed:", error);
93
- }
94
- }
95
-
96
- // 3. Generate on cache miss - ~98ms
97
- const generated = generateFn();
98
- memoryManifest = {
99
- routeManifest: generated.routeManifest,
100
- version,
101
- };
102
- // Make available to getGlobalRouteMap() for href()
103
- setCachedManifest(memoryManifest.routeManifest);
104
- const duration = (performance.now() - startTime).toFixed(2);
105
- console.log(`[route-manifest] MISS - generated fresh (${duration}ms, ${Object.keys(generated.routeManifest).length} routes)`);
106
-
107
- // Store in cache for other isolates (only if store provided)
108
- // OFF RENDERING PATH via waitUntil
109
- if (store) {
110
- console.log("[route-manifest] Writing to edge cache (via waitUntil)...");
111
- const cachePromise = (async () => {
112
- try {
113
- // Wrap in CachedEntryData format expected by SegmentCacheStore
114
- const data: CachedEntryData = {
115
- segments: [],
116
- handles: {},
117
- expiresAt: Date.now() + 31536000 * 1000, // 1 year
118
- };
119
- // Store manifest in a custom field
120
- (data as unknown as { manifest: CachedRouteData }).manifest = memoryManifest!;
121
- await store.set(cacheKey, data, 31536000); // 1 year TTL
122
- console.log("[route-manifest] Edge cache write complete");
123
- } catch (error) {
124
- console.warn("[route-manifest] Edge cache write failed:", error);
125
- }
126
- })();
127
-
128
- if (waitUntil) {
129
- // Non-blocking: cache write happens after response is sent
130
- waitUntil(cachePromise);
131
- } else {
132
- // Fallback: blocking write (dev mode or no waitUntil available)
133
- await cachePromise;
134
- }
135
- }
136
-
137
- return memoryManifest;
138
- }
139
-
140
- /**
141
- * Sync access to in-memory manifest (for href())
142
- * Returns null if not yet loaded
143
- *
144
- * @returns The route manifest or null if not loaded
145
- */
146
- export function getRouteManifestSync(): Record<string, string> | null {
147
- return memoryManifest?.routeManifest ?? null;
148
- }
149
-
150
- /**
151
- * Clear in-memory cache (for testing)
152
- */
153
- export function clearRouteManifestCache(): void {
154
- memoryManifest = null;
155
- }
156
-
157
- /**
158
- * Check if manifest is loaded in memory
159
- *
160
- * @returns true if manifest is available synchronously
161
- */
162
- export function isManifestLoaded(): boolean {
163
- return memoryManifest !== null;
164
- }
165
-
166
- /**
167
- * Get the current cached version (for debugging)
168
- *
169
- * @returns The version string or null if not loaded
170
- */
171
- export function getManifestVersion(): string | null {
172
- return memoryManifest?.version ?? null;
173
- }
@@ -1,209 +0,0 @@
1
- import type { Plugin, ResolvedConfig } from "vite";
2
- import MagicString from "magic-string";
3
- import path from "node:path";
4
- import crypto from "node:crypto";
5
-
6
- /**
7
- * Normalize path to forward slashes
8
- */
9
- function normalizePath(p: string): string {
10
- return p.split(path.sep).join("/");
11
- }
12
-
13
- /**
14
- * Generate a short hash for a handle ID
15
- * Uses first 8 chars of SHA-256 hash for uniqueness while keeping IDs short
16
- * Appends export name for easier debugging: "abc123#Breadcrumbs"
17
- */
18
- function hashHandleId(filePath: string, exportName: string): string {
19
- const input = `${filePath}#${exportName}`;
20
- const hash = crypto.createHash("sha256").update(input).digest("hex");
21
- return `${hash.slice(0, 8)}#${exportName}`;
22
- }
23
-
24
- /**
25
- * Check if file imports createHandle from rsc-router
26
- */
27
- function hasCreateHandleImport(code: string): boolean {
28
- // Match: import { createHandle } from "@rangojs/router" or "@rangojs/router/..."
29
- const pattern =
30
- /import\s*\{[^}]*\bcreateHandle\b[^}]*\}\s*from\s*["']@rangojs\/router(?:\/[^"']+)?["']/;
31
- return pattern.test(code);
32
- }
33
-
34
- /**
35
- * Analyze createHandle arguments to determine injection strategy
36
- * Returns: { hasArgs: boolean, firstArgIsString: boolean, firstArgIsFunction: boolean }
37
- */
38
- function analyzeCreateHandleArgs(
39
- code: string,
40
- startPos: number,
41
- endPos: number
42
- ): { hasArgs: boolean; firstArgIsString: boolean; firstArgIsFunction: boolean } {
43
- // Extract the content between parentheses
44
- const content = code.slice(startPos, endPos).trim();
45
-
46
- if (!content) {
47
- return { hasArgs: false, firstArgIsString: false, firstArgIsFunction: false };
48
- }
49
-
50
- // Check if first arg starts with a quote (string literal)
51
- const firstArgIsString = /^["']/.test(content);
52
-
53
- // Check if first arg starts with ( for arrow function or function keyword
54
- const firstArgIsFunction =
55
- content.startsWith("(") ||
56
- content.startsWith("function") ||
57
- // Check for identifier that could be a collect function reference
58
- /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*(?:,|$)/.test(content);
59
-
60
- return { hasArgs: true, firstArgIsString, firstArgIsFunction };
61
- }
62
-
63
- /**
64
- * Transform export const X = createHandle(...) patterns to inject $$id
65
- *
66
- * Handles these cases:
67
- * 1. createHandle() - no args -> inject (undefined, "id")
68
- * 2. createHandle("name") - string name -> inject (, "id") after existing arg
69
- * 3. createHandle(collectFn) - collect function -> inject (collectFn, "id")
70
- * 4. createHandle("name", collectFn) - both -> inject (, "id") after existing args
71
- */
72
- function transformHandleExports(
73
- code: string,
74
- filePath: string,
75
- sourceId?: string,
76
- isBuild: boolean = false
77
- ): { code: string; map: ReturnType<MagicString["generateMap"]> } | null {
78
- // Quick bail-out
79
- if (!code.includes("createHandle")) {
80
- return null;
81
- }
82
-
83
- // Must have direct import from rsc-router
84
- if (!hasCreateHandleImport(code)) {
85
- return null;
86
- }
87
-
88
- // Match: export const X = createHandle<...>(
89
- // Captures the export name (X)
90
- const pattern = /export\s+const\s+(\w+)\s*=\s*createHandle\s*(?:<[^>]*>)?\s*\(/g;
91
-
92
- const s = new MagicString(code);
93
- let hasChanges = false;
94
- let match: RegExpExecArray | null;
95
-
96
- while ((match = pattern.exec(code)) !== null) {
97
- const exportName = match[1];
98
- const matchEnd = match.index + match[0].length;
99
-
100
- // Find the end of the createHandle(...) call
101
- let parenDepth = 1;
102
- let i = matchEnd;
103
- while (i < code.length && parenDepth > 0) {
104
- if (code[i] === "(") parenDepth++;
105
- if (code[i] === ")") parenDepth--;
106
- i++;
107
- }
108
-
109
- // i now points just after the closing )
110
- const closeParenPos = i - 1;
111
-
112
- // Analyze what arguments exist
113
- const args = analyzeCreateHandleArgs(code, matchEnd, closeParenPos);
114
-
115
- // Find the semicolon or end of statement
116
- let statementEnd = i;
117
- while (statementEnd < code.length && /\s/.test(code[statementEnd])) {
118
- statementEnd++;
119
- }
120
- if (code[statementEnd] === ";") {
121
- statementEnd++;
122
- }
123
-
124
- // Generate ID: hashed in production, readable in dev
125
- const handleId = isBuild
126
- ? hashHandleId(filePath, exportName)
127
- : `${filePath}#${exportName}`;
128
-
129
- // Inject $$id as the last parameter
130
- let paramInjection: string;
131
- if (!args.hasArgs) {
132
- // No args: createHandle() -> createHandle(undefined, "id")
133
- paramInjection = `undefined, "${handleId}"`;
134
- } else {
135
- // Has args: createHandle(x) -> createHandle(x, "id")
136
- paramInjection = `, "${handleId}"`;
137
- }
138
- s.appendLeft(closeParenPos, paramInjection);
139
-
140
- // Also set $$id property for external access
141
- const propInjection = `\n${exportName}.$$id = "${handleId}";`;
142
- s.appendRight(statementEnd, propInjection);
143
- hasChanges = true;
144
- }
145
-
146
- if (!hasChanges) {
147
- return null;
148
- }
149
-
150
- return {
151
- code: s.toString(),
152
- map: s.generateMap({ source: sourceId, includeContent: true }),
153
- };
154
- }
155
-
156
- /**
157
- * Vite plugin that exposes $$id on createHandle calls.
158
- *
159
- * When users create handles with createHandle(), this plugin:
160
- * 1. Injects a $$id as the last parameter (used as the handle name)
161
- * 2. Sets $$id property on the exported constant for external access
162
- *
163
- * This allows handles to be created without explicit names:
164
- * - Before: export const Breadcrumbs = createHandle<Item>("breadcrumbs")
165
- * - After: export const Breadcrumbs = createHandle<Item>()
166
- *
167
- * The name is auto-generated from file path + export name.
168
- *
169
- * Requirements:
170
- * - Must use direct import: import { createHandle } from "@rangojs/router"
171
- * - Must use named export: export const MyHandle = createHandle(...)
172
- */
173
- export function exposeHandleId(): Plugin {
174
- let config: ResolvedConfig;
175
- let isBuild = false;
176
-
177
- return {
178
- name: "@rangojs/router:expose-handle-id",
179
- enforce: "post",
180
-
181
- configResolved(resolvedConfig) {
182
- config = resolvedConfig;
183
- isBuild = config.command === "build";
184
- },
185
-
186
- transform(code, id) {
187
- // Skip node_modules
188
- if (id.includes("/node_modules/")) {
189
- return;
190
- }
191
-
192
- // Quick bail-out
193
- if (!code.includes("createHandle")) {
194
- return;
195
- }
196
-
197
- // Must have direct import from rsc-router
198
- if (!hasCreateHandleImport(code)) {
199
- return;
200
- }
201
-
202
- // Get relative path for the ID
203
- const relativePath = normalizePath(path.relative(config.root, id));
204
-
205
- // Transform: inject $$id
206
- return transformHandleExports(code, relativePath, id, isBuild);
207
- },
208
- };
209
- }