@rangojs/router 0.0.0-experimental.2

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 (155) hide show
  1. package/CLAUDE.md +7 -0
  2. package/README.md +19 -0
  3. package/dist/vite/index.js +1298 -0
  4. package/package.json +140 -0
  5. package/skills/caching/SKILL.md +319 -0
  6. package/skills/document-cache/SKILL.md +152 -0
  7. package/skills/hooks/SKILL.md +359 -0
  8. package/skills/intercept/SKILL.md +292 -0
  9. package/skills/layout/SKILL.md +216 -0
  10. package/skills/loader/SKILL.md +365 -0
  11. package/skills/middleware/SKILL.md +442 -0
  12. package/skills/parallel/SKILL.md +255 -0
  13. package/skills/route/SKILL.md +141 -0
  14. package/skills/router-setup/SKILL.md +403 -0
  15. package/skills/theme/SKILL.md +54 -0
  16. package/skills/typesafety/SKILL.md +352 -0
  17. package/src/__mocks__/version.ts +6 -0
  18. package/src/__tests__/component-utils.test.ts +76 -0
  19. package/src/__tests__/route-definition.test.ts +63 -0
  20. package/src/__tests__/urls.test.tsx +436 -0
  21. package/src/browser/event-controller.ts +876 -0
  22. package/src/browser/index.ts +18 -0
  23. package/src/browser/link-interceptor.ts +121 -0
  24. package/src/browser/lru-cache.ts +69 -0
  25. package/src/browser/merge-segment-loaders.ts +126 -0
  26. package/src/browser/navigation-bridge.ts +893 -0
  27. package/src/browser/navigation-client.ts +162 -0
  28. package/src/browser/navigation-store.ts +823 -0
  29. package/src/browser/partial-update.ts +559 -0
  30. package/src/browser/react/Link.tsx +248 -0
  31. package/src/browser/react/NavigationProvider.tsx +275 -0
  32. package/src/browser/react/ScrollRestoration.tsx +94 -0
  33. package/src/browser/react/context.ts +53 -0
  34. package/src/browser/react/index.ts +52 -0
  35. package/src/browser/react/location-state-shared.ts +120 -0
  36. package/src/browser/react/location-state.ts +62 -0
  37. package/src/browser/react/use-action.ts +240 -0
  38. package/src/browser/react/use-client-cache.ts +56 -0
  39. package/src/browser/react/use-handle.ts +178 -0
  40. package/src/browser/react/use-href.tsx +208 -0
  41. package/src/browser/react/use-link-status.ts +134 -0
  42. package/src/browser/react/use-navigation.ts +150 -0
  43. package/src/browser/react/use-segments.ts +188 -0
  44. package/src/browser/request-controller.ts +164 -0
  45. package/src/browser/rsc-router.tsx +353 -0
  46. package/src/browser/scroll-restoration.ts +324 -0
  47. package/src/browser/server-action-bridge.ts +747 -0
  48. package/src/browser/shallow.ts +35 -0
  49. package/src/browser/types.ts +464 -0
  50. package/src/cache/__tests__/document-cache.test.ts +522 -0
  51. package/src/cache/__tests__/memory-segment-store.test.ts +487 -0
  52. package/src/cache/__tests__/memory-store.test.ts +484 -0
  53. package/src/cache/cache-scope.ts +565 -0
  54. package/src/cache/cf/__tests__/cf-cache-store.test.ts +428 -0
  55. package/src/cache/cf/cf-cache-store.ts +428 -0
  56. package/src/cache/cf/index.ts +19 -0
  57. package/src/cache/document-cache.ts +340 -0
  58. package/src/cache/index.ts +58 -0
  59. package/src/cache/memory-segment-store.ts +150 -0
  60. package/src/cache/memory-store.ts +253 -0
  61. package/src/cache/types.ts +387 -0
  62. package/src/client.rsc.tsx +88 -0
  63. package/src/client.tsx +621 -0
  64. package/src/component-utils.ts +76 -0
  65. package/src/components/DefaultDocument.tsx +23 -0
  66. package/src/default-error-boundary.tsx +88 -0
  67. package/src/deps/browser.ts +8 -0
  68. package/src/deps/html-stream-client.ts +2 -0
  69. package/src/deps/html-stream-server.ts +2 -0
  70. package/src/deps/rsc.ts +10 -0
  71. package/src/deps/ssr.ts +2 -0
  72. package/src/errors.ts +259 -0
  73. package/src/handle.ts +120 -0
  74. package/src/handles/MetaTags.tsx +193 -0
  75. package/src/handles/index.ts +6 -0
  76. package/src/handles/meta.ts +247 -0
  77. package/src/href-client.ts +128 -0
  78. package/src/href-context.ts +33 -0
  79. package/src/href.ts +177 -0
  80. package/src/index.rsc.ts +79 -0
  81. package/src/index.ts +87 -0
  82. package/src/loader.rsc.ts +204 -0
  83. package/src/loader.ts +47 -0
  84. package/src/network-error-thrower.tsx +21 -0
  85. package/src/outlet-context.ts +15 -0
  86. package/src/root-error-boundary.tsx +277 -0
  87. package/src/route-content-wrapper.tsx +198 -0
  88. package/src/route-definition.ts +1371 -0
  89. package/src/route-map-builder.ts +146 -0
  90. package/src/route-types.ts +198 -0
  91. package/src/route-utils.ts +89 -0
  92. package/src/router/__tests__/match-context.test.ts +104 -0
  93. package/src/router/__tests__/match-pipelines.test.ts +537 -0
  94. package/src/router/__tests__/match-result.test.ts +566 -0
  95. package/src/router/__tests__/on-error.test.ts +935 -0
  96. package/src/router/__tests__/pattern-matching.test.ts +577 -0
  97. package/src/router/error-handling.ts +287 -0
  98. package/src/router/handler-context.ts +158 -0
  99. package/src/router/loader-resolution.ts +326 -0
  100. package/src/router/manifest.ts +138 -0
  101. package/src/router/match-context.ts +264 -0
  102. package/src/router/match-middleware/background-revalidation.ts +236 -0
  103. package/src/router/match-middleware/cache-lookup.ts +261 -0
  104. package/src/router/match-middleware/cache-store.ts +266 -0
  105. package/src/router/match-middleware/index.ts +81 -0
  106. package/src/router/match-middleware/intercept-resolution.ts +268 -0
  107. package/src/router/match-middleware/segment-resolution.ts +174 -0
  108. package/src/router/match-pipelines.ts +214 -0
  109. package/src/router/match-result.ts +214 -0
  110. package/src/router/metrics.ts +62 -0
  111. package/src/router/middleware.test.ts +1355 -0
  112. package/src/router/middleware.ts +748 -0
  113. package/src/router/pattern-matching.ts +272 -0
  114. package/src/router/revalidation.ts +190 -0
  115. package/src/router/router-context.ts +299 -0
  116. package/src/router/types.ts +96 -0
  117. package/src/router.ts +3876 -0
  118. package/src/rsc/__tests__/helpers.test.ts +175 -0
  119. package/src/rsc/handler.ts +1060 -0
  120. package/src/rsc/helpers.ts +64 -0
  121. package/src/rsc/index.ts +56 -0
  122. package/src/rsc/nonce.ts +18 -0
  123. package/src/rsc/types.ts +237 -0
  124. package/src/segment-system.tsx +456 -0
  125. package/src/server/__tests__/request-context.test.ts +171 -0
  126. package/src/server/context.ts +417 -0
  127. package/src/server/handle-store.ts +230 -0
  128. package/src/server/loader-registry.ts +174 -0
  129. package/src/server/request-context.ts +554 -0
  130. package/src/server/root-layout.tsx +10 -0
  131. package/src/server/tsconfig.json +14 -0
  132. package/src/server.ts +146 -0
  133. package/src/ssr/__tests__/ssr-handler.test.tsx +188 -0
  134. package/src/ssr/index.tsx +234 -0
  135. package/src/theme/ThemeProvider.tsx +291 -0
  136. package/src/theme/ThemeScript.tsx +61 -0
  137. package/src/theme/__tests__/theme.test.ts +120 -0
  138. package/src/theme/constants.ts +55 -0
  139. package/src/theme/index.ts +58 -0
  140. package/src/theme/theme-context.ts +70 -0
  141. package/src/theme/theme-script.ts +152 -0
  142. package/src/theme/types.ts +182 -0
  143. package/src/theme/use-theme.ts +44 -0
  144. package/src/types.ts +1561 -0
  145. package/src/urls.ts +726 -0
  146. package/src/use-loader.tsx +346 -0
  147. package/src/vite/__tests__/expose-loader-id.test.ts +117 -0
  148. package/src/vite/expose-action-id.ts +344 -0
  149. package/src/vite/expose-handle-id.ts +209 -0
  150. package/src/vite/expose-loader-id.ts +357 -0
  151. package/src/vite/expose-location-state-id.ts +177 -0
  152. package/src/vite/index.ts +787 -0
  153. package/src/vite/package-resolution.ts +125 -0
  154. package/src/vite/version.d.ts +12 -0
  155. package/src/vite/virtual-entries.ts +109 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Server-side loader registry for GET-based fetching
3
+ *
4
+ * Loaders are loaded lazily via dynamic imports when first requested.
5
+ * The RSC handler looks up loaders by $$id to execute them.
6
+ */
7
+
8
+ import type { LoaderFn } from "../types.js";
9
+ import type { MiddlewareFn } from "../router/middleware.js";
10
+ import { getFetchableLoader } from "../loader.rsc.js";
11
+
12
+ interface RegisteredLoader {
13
+ fn: LoaderFn<any, any, any>;
14
+ middleware: MiddlewareFn[];
15
+ }
16
+
17
+ // Server-side cache - maps loader $$id to function and middleware
18
+ // This is a CACHE populated by getLoaderLazy() when loaders are first accessed.
19
+ // The source of truth is fetchableLoaderRegistry in loader.ts, which is populated
20
+ // when createLoader() runs. This cache exists to:
21
+ // 1. Avoid repeated lookups/imports for the same loader
22
+ // 2. Support lazy loading in production (loaders imported on-demand)
23
+ // 3. Provide a stable reference for the RSC handler
24
+ const loaderRegistry = new Map<string, RegisteredLoader>();
25
+
26
+ // Lazy import map - set by the loader manifest
27
+ // Maps loader $$id to a function that imports the loader module
28
+ type LazyLoaderImport = () => Promise<{ $$id: string }>;
29
+ let lazyLoaderImports: Map<string, LazyLoaderImport> | null = null;
30
+
31
+ /**
32
+ * Set the lazy loader imports map (called by the loader manifest)
33
+ */
34
+ export function setLoaderImports(
35
+ imports: Record<string, LazyLoaderImport>
36
+ ): void {
37
+ lazyLoaderImports = new Map(Object.entries(imports));
38
+ }
39
+
40
+ /**
41
+ * Register a fetchable loader by $$id
42
+ * Called by createLoader when fetchable option is provided
43
+ */
44
+ export function registerLoader(
45
+ id: string,
46
+ fn: LoaderFn<any, any, any>,
47
+ middleware: MiddlewareFn[] = []
48
+ ): void {
49
+ if (loaderRegistry.has(id)) {
50
+ // Already registered (can happen during HMR)
51
+ return;
52
+ }
53
+ loaderRegistry.set(id, { fn, middleware });
54
+ }
55
+
56
+ /**
57
+ * Get a registered loader by $$id (synchronous)
58
+ * Returns undefined if loader is not registered
59
+ */
60
+ export function getLoader(id: string): RegisteredLoader | undefined {
61
+ return loaderRegistry.get(id);
62
+ }
63
+
64
+ /**
65
+ * Get a loader by $$id, loading it lazily if needed
66
+ * This is the primary method for the RSC handler to get loaders
67
+ *
68
+ * In production: IDs are hashed, looked up via the lazy import map
69
+ * In dev: IDs are "filePath#exportName", resolved via dynamic import
70
+ */
71
+ export async function getLoaderLazy(
72
+ id: string
73
+ ): Promise<RegisteredLoader | undefined> {
74
+ // Check if already cached in main registry
75
+ const existing = loaderRegistry.get(id);
76
+ if (existing) {
77
+ return existing;
78
+ }
79
+
80
+ // Check the fetchable loader registry (populated by createLoader)
81
+ const fetchable = getFetchableLoader(id);
82
+ if (fetchable) {
83
+ // Cache in main registry for future requests
84
+ loaderRegistry.set(id, fetchable);
85
+ return fetchable;
86
+ }
87
+
88
+ // Try to lazy load from the import map (production mode)
89
+ if (lazyLoaderImports && lazyLoaderImports.size > 0) {
90
+ const lazyImport = lazyLoaderImports.get(id);
91
+ if (lazyImport) {
92
+ try {
93
+ // Import the loader module - this triggers createLoader which registers fn
94
+ await lazyImport();
95
+
96
+ // Now try to get from fetchable registry (createLoader registered it)
97
+ const registered = getFetchableLoader(id);
98
+ if (registered) {
99
+ loaderRegistry.set(id, registered);
100
+ return registered;
101
+ }
102
+ } catch (error) {
103
+ console.error(`[LoaderRegistry] Failed to load loader "${id}":`, error);
104
+ }
105
+ }
106
+ }
107
+
108
+ // Dev mode fallback: parse the ID and use Vite's dynamic import
109
+ // ID format in dev: "src/path/to/file.ts#ExportName"
110
+ const hashIndex = id.indexOf("#");
111
+ if (hashIndex !== -1) {
112
+ const filePath = id.slice(0, hashIndex);
113
+
114
+ try {
115
+ // In dev mode, Vite handles dynamic imports
116
+ // Just importing the module triggers createLoader which registers the fn
117
+ await import(/* @vite-ignore */ `/${filePath}`);
118
+
119
+ // Now try to get from fetchable registry
120
+ const registered = getFetchableLoader(id);
121
+ if (registered) {
122
+ loaderRegistry.set(id, registered);
123
+ return registered;
124
+ }
125
+ } catch (error) {
126
+ console.error(`[LoaderRegistry] Failed to load loader "${id}":`, error);
127
+ }
128
+ }
129
+
130
+ return undefined;
131
+ }
132
+
133
+ /**
134
+ * Check if a loader is registered by $$id
135
+ */
136
+ export function hasLoader(id: string): boolean {
137
+ return loaderRegistry.has(id) || getFetchableLoader(id) !== undefined;
138
+ }
139
+
140
+ /**
141
+ * Get all registered loader IDs (for debugging)
142
+ */
143
+ export function getRegisteredLoaderIds(): string[] {
144
+ return Array.from(loaderRegistry.keys());
145
+ }
146
+
147
+ /**
148
+ * Register a loader by its $$id (injected by Vite plugin)
149
+ * This is called during module loading to cache loaders
150
+ */
151
+ export function registerLoaderById(loader: {
152
+ $$id: string;
153
+ fn?: LoaderFn<any, any, any>;
154
+ }): void {
155
+ if (!loader.$$id) {
156
+ return;
157
+ }
158
+ if (loaderRegistry.has(loader.$$id)) {
159
+ // Already registered (can happen during HMR)
160
+ return;
161
+ }
162
+
163
+ // For fetchable loaders, fn is stored in the fetchable registry by $$id
164
+ const fetchable = getFetchableLoader(loader.$$id);
165
+ if (fetchable) {
166
+ loaderRegistry.set(loader.$$id, fetchable);
167
+ return;
168
+ }
169
+
170
+ // Fall back to using fn from the loader object (non-fetchable loaders)
171
+ if (loader.fn) {
172
+ loaderRegistry.set(loader.$$id, { fn: loader.fn, middleware: [] });
173
+ }
174
+ }