@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,193 @@
1
+ "use client";
2
+ import type { ReactNode } from "react";
3
+ import { Suspense, use, useId } from "react";
4
+ import { invariant } from "./errors";
5
+ import { OutletProvider } from "./client.js";
6
+ import type { ResolvedSegment } from "./types.js";
7
+ import { isLoaderDataResult } from "./types.js";
8
+
9
+ /**
10
+ * Stable async wrapper component for route content
11
+ * Using a module-level component ensures React sees the same component reference
12
+ * across renders, preventing unnecessary remounts during actions.
13
+ *
14
+ * When content is a pending promise, React suspends and shows the nearest
15
+ * Suspense fallback. When content is already resolved, it renders immediately
16
+ * without suspension.
17
+ *
18
+ * @param segmentId - Stable ID from segment, used for consistent keys across renders
19
+ */
20
+ export function RouteContentWrapper({
21
+ content,
22
+ fallback,
23
+ segmentId,
24
+ }: {
25
+ content: Promise<ReactNode>;
26
+ fallback?: ReactNode;
27
+ segmentId?: string;
28
+ }): ReactNode {
29
+ if (!content) {
30
+ // Already resolved
31
+ return content as ReactNode;
32
+ }
33
+ return (
34
+ <Suspense fallback={fallback ?? null} key={segmentId ? "route-content-suspense-" + segmentId : undefined}>
35
+ <Suspender content={content} key={segmentId} />
36
+ </Suspense>
37
+ );
38
+ }
39
+
40
+ export function RouteContentWrapperCallback<T>({
41
+ resolve,
42
+ fallback,
43
+ children,
44
+ }: {
45
+ resolve: Promise<T> | T;
46
+ fallback?: ReactNode;
47
+ children: (data: T) => ReactNode;
48
+ }): ReactNode {
49
+ const id = useId();
50
+ invariant(children, "RouteContentWrapperCallback requires children");
51
+ invariant(
52
+ typeof children === "function",
53
+ "RouteContentWrapperCallback requires children to be a function"
54
+ );
55
+ invariant(
56
+ resolve !== undefined,
57
+ "RouteContentWrapperCallback requires resolve"
58
+ );
59
+ return (
60
+ <Suspense
61
+ fallback={fallback ?? null}
62
+ key={"route-content-suspense-callback-" + id}
63
+ >
64
+ <SuspenderCallback resolve={resolve} key={id}>
65
+ {children}
66
+ </SuspenderCallback>
67
+ </Suspense>
68
+ );
69
+ }
70
+
71
+ const Suspender = ({
72
+ content,
73
+ }: {
74
+ content: Promise<ReactNode> | ReactNode;
75
+ }): ReactNode => {
76
+ invariant(content instanceof Promise, "Suspender expects a Promise content");
77
+
78
+ return use(content);
79
+ };
80
+
81
+ const SuspenderCallback = <T,>({
82
+ resolve,
83
+ children,
84
+ }: {
85
+ resolve: Promise<T> | T;
86
+ children: (data: T) => ReactNode;
87
+ }): ReactNode => {
88
+ return resolve instanceof Promise
89
+ ? children(use(resolve))
90
+ : children(resolve);
91
+ };
92
+
93
+ /**
94
+ * LoaderBoundary - Client component that resolves loader promises and renders OutletProvider
95
+ *
96
+ * This component enables streaming with loaders by:
97
+ * 1. Receiving loader promises (serializable across RSC boundary)
98
+ * 2. Using React's use() to resolve them (triggers Suspense)
99
+ * 3. Rendering OutletProvider with resolved data
100
+ *
101
+ * The callback logic lives inside this client component, avoiding the
102
+ * "Functions are not valid as a child of Client Components" error.
103
+ */
104
+ export interface LoaderBoundaryProps {
105
+ loaderDataPromise: Promise<any[]> | any[];
106
+ loaderIds: string[];
107
+ fallback?: ReactNode;
108
+ outletKey: string;
109
+ outletContent: ReactNode;
110
+ segment: ResolvedSegment;
111
+ parallel?: ResolvedSegment[];
112
+ children: ReactNode;
113
+ }
114
+
115
+ export function LoaderBoundary({
116
+ loaderDataPromise,
117
+ loaderIds,
118
+ fallback,
119
+ outletKey,
120
+ outletContent,
121
+ segment,
122
+ parallel,
123
+ children,
124
+ }: LoaderBoundaryProps): ReactNode {
125
+ return (
126
+ <Suspense fallback={fallback ?? null} key={`loader-boundary-${outletKey}`}>
127
+ <LoaderResolver
128
+ loaderDataPromise={loaderDataPromise}
129
+ loaderIds={loaderIds}
130
+ outletKey={outletKey}
131
+ outletContent={outletContent}
132
+ segment={segment}
133
+ parallel={parallel}
134
+ >
135
+ {children}
136
+ </LoaderResolver>
137
+ </Suspense>
138
+ );
139
+ }
140
+
141
+ /**
142
+ * Internal component that resolves loader promises and renders OutletProvider
143
+ */
144
+ function LoaderResolver({
145
+ loaderDataPromise,
146
+ loaderIds,
147
+ outletKey,
148
+ outletContent,
149
+ segment,
150
+ parallel,
151
+ children,
152
+ }: Omit<LoaderBoundaryProps, "fallback">): ReactNode {
153
+ // Resolve loader promises using React's use()
154
+ const resolvedData =
155
+ loaderDataPromise instanceof Promise
156
+ ? use(loaderDataPromise)
157
+ : loaderDataPromise;
158
+
159
+ // Build loaderData record from resolved values
160
+ const loaderData: Record<string, any> = {};
161
+ let loaderErrorFallback: ReactNode = null;
162
+
163
+ loaderIds.forEach((id, i) => {
164
+ const result = resolvedData[i];
165
+
166
+ if (isLoaderDataResult(result)) {
167
+ if (result.ok) {
168
+ loaderData[id] = result.data;
169
+ } else {
170
+ if (result.fallback) {
171
+ loaderErrorFallback = result.fallback;
172
+ } else {
173
+ throw new Error(result.error.message);
174
+ }
175
+ }
176
+ } else {
177
+ // Legacy format - direct data
178
+ loaderData[id] = result;
179
+ }
180
+ });
181
+
182
+ return (
183
+ <OutletProvider
184
+ key={outletKey}
185
+ content={outletContent}
186
+ segment={segment}
187
+ parallel={parallel}
188
+ loaderData={Object.keys(loaderData).length > 0 ? loaderData : undefined}
189
+ >
190
+ {loaderErrorFallback ?? children}
191
+ </OutletProvider>
192
+ );
193
+ }