@rangojs/router 0.0.0-experimental.259 → 0.0.0-experimental.26
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.
- package/README.md +294 -28
- package/dist/bin/rango.js +355 -47
- package/dist/vite/index.js +1658 -1239
- package/package.json +3 -3
- package/skills/cache-guide/SKILL.md +9 -5
- package/skills/caching/SKILL.md +4 -4
- package/skills/document-cache/SKILL.md +2 -2
- package/skills/hooks/SKILL.md +40 -29
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +79 -0
- package/skills/layout/SKILL.md +62 -2
- package/skills/loader/SKILL.md +229 -15
- package/skills/middleware/SKILL.md +109 -30
- package/skills/parallel/SKILL.md +57 -2
- package/skills/prerender/SKILL.md +189 -19
- package/skills/rango/SKILL.md +1 -2
- package/skills/response-routes/SKILL.md +3 -3
- package/skills/route/SKILL.md +44 -3
- package/skills/router-setup/SKILL.md +80 -3
- package/skills/theme/SKILL.md +5 -4
- package/skills/typesafety/SKILL.md +59 -16
- package/skills/use-cache/SKILL.md +16 -2
- package/src/__internal.ts +1 -1
- package/src/bin/rango.ts +56 -19
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/event-controller.ts +29 -48
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +1 -1
- package/src/browser/link-interceptor.ts +19 -3
- package/src/browser/merge-segment-loaders.ts +9 -2
- package/src/browser/navigation-bridge.ts +66 -443
- package/src/browser/navigation-client.ts +34 -62
- package/src/browser/navigation-store.ts +4 -33
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/partial-update.ts +103 -151
- package/src/browser/prefetch/cache.ts +67 -0
- package/src/browser/prefetch/fetch.ts +137 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +154 -44
- package/src/browser/react/NavigationProvider.tsx +32 -0
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +2 -6
- package/src/browser/react/location-state-shared.ts +29 -11
- package/src/browser/react/location-state.ts +6 -4
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +23 -45
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +21 -64
- package/src/browser/react/use-navigation.ts +7 -32
- package/src/browser/react/use-params.ts +5 -34
- package/src/browser/react/use-pathname.ts +2 -3
- package/src/browser/react/use-router.ts +3 -6
- package/src/browser/react/use-search-params.ts +2 -1
- package/src/browser/react/use-segments.ts +75 -114
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +46 -22
- package/src/browser/scroll-restoration.ts +10 -7
- package/src/browser/server-action-bridge.ts +458 -405
- package/src/browser/types.ts +21 -35
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +38 -13
- package/src/build/generate-route-types.ts +4 -0
- package/src/build/index.ts +1 -0
- package/src/build/route-trie.ts +19 -3
- package/src/build/route-types/codegen.ts +13 -4
- package/src/build/route-types/include-resolution.ts +13 -0
- package/src/build/route-types/per-module-writer.ts +15 -3
- package/src/build/route-types/router-processing.ts +170 -18
- package/src/build/runtime-discovery.ts +13 -1
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +136 -123
- package/src/cache/cache-scope.ts +76 -83
- package/src/cache/cf/cf-cache-store.ts +12 -7
- package/src/cache/document-cache.ts +93 -69
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/index.ts +0 -15
- package/src/cache/memory-segment-store.ts +43 -69
- package/src/cache/profile-registry.ts +43 -8
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +140 -117
- package/src/cache/taint.ts +30 -3
- package/src/cache/types.ts +1 -115
- package/src/client.rsc.tsx +0 -1
- package/src/client.tsx +53 -76
- package/src/errors.ts +6 -1
- package/src/handle.ts +1 -1
- package/src/handles/MetaTags.tsx +5 -2
- package/src/host/cookie-handler.ts +8 -3
- package/src/host/index.ts +0 -3
- package/src/host/router.ts +14 -1
- package/src/href-client.ts +3 -1
- package/src/index.rsc.ts +53 -10
- package/src/index.ts +73 -43
- package/src/loader.rsc.ts +12 -4
- package/src/loader.ts +8 -0
- package/src/prerender/store.ts +60 -18
- package/src/prerender.ts +76 -18
- package/src/reverse.ts +11 -7
- package/src/root-error-boundary.tsx +30 -26
- package/src/route-definition/dsl-helpers.ts +9 -6
- package/src/route-definition/index.ts +0 -3
- package/src/route-definition/redirect.ts +15 -3
- package/src/route-map-builder.ts +38 -2
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +7 -0
- package/src/router/content-negotiation.ts +1 -1
- package/src/router/debug-manifest.ts +16 -3
- package/src/router/handler-context.ts +96 -17
- package/src/router/intercept-resolution.ts +6 -4
- package/src/router/lazy-includes.ts +4 -0
- package/src/router/loader-resolution.ts +6 -11
- package/src/router/logging.ts +100 -3
- package/src/router/manifest.ts +32 -3
- package/src/router/match-api.ts +62 -54
- package/src/router/match-context.ts +3 -0
- package/src/router/match-handlers.ts +185 -11
- package/src/router/match-middleware/background-revalidation.ts +65 -85
- package/src/router/match-middleware/cache-lookup.ts +78 -10
- package/src/router/match-middleware/cache-store.ts +2 -0
- package/src/router/match-pipelines.ts +8 -43
- package/src/router/match-result.ts +0 -9
- package/src/router/metrics.ts +233 -13
- package/src/router/middleware-types.ts +34 -39
- package/src/router/middleware.ts +290 -130
- package/src/router/pattern-matching.ts +61 -10
- package/src/router/prerender-match.ts +36 -6
- package/src/router/preview-match.ts +7 -1
- package/src/router/revalidation.ts +61 -2
- package/src/router/router-context.ts +15 -0
- package/src/router/router-interfaces.ts +158 -40
- package/src/router/router-options.ts +223 -1
- package/src/router/router-registry.ts +5 -2
- package/src/router/segment-resolution/fresh.ts +165 -242
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +102 -98
- package/src/router/segment-resolution/revalidation.ts +394 -272
- package/src/router/segment-resolution/static-store.ts +2 -2
- package/src/router/segment-resolution.ts +1 -3
- package/src/router/segment-wrappers.ts +3 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +20 -2
- package/src/router/types.ts +7 -1
- package/src/router.ts +203 -18
- package/src/rsc/handler-context.ts +13 -2
- package/src/rsc/handler.ts +489 -438
- package/src/rsc/helpers.ts +125 -5
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +84 -42
- package/src/rsc/manifest-init.ts +3 -2
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +245 -19
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +47 -43
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +166 -66
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +20 -2
- package/src/search-params.ts +38 -23
- package/src/server/context.ts +61 -7
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +84 -12
- package/src/server/loader-registry.ts +11 -46
- package/src/server/request-context.ts +275 -49
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +67 -28
- package/src/static-handler.ts +7 -0
- package/src/theme/ThemeProvider.tsx +6 -1
- package/src/theme/index.ts +4 -18
- package/src/theme/theme-context.ts +1 -28
- package/src/theme/theme-script.ts +2 -1
- package/src/types/cache-types.ts +6 -1
- package/src/types/error-types.ts +3 -0
- package/src/types/global-namespace.ts +22 -0
- package/src/types/handler-context.ts +103 -16
- package/src/types/index.ts +1 -1
- package/src/types/loader-types.ts +9 -6
- package/src/types/route-config.ts +17 -26
- package/src/types/route-entry.ts +28 -0
- package/src/types/segments.ts +0 -5
- package/src/urls/include-helper.ts +49 -8
- package/src/urls/index.ts +1 -0
- package/src/urls/path-helper-types.ts +30 -12
- package/src/urls/path-helper.ts +17 -2
- package/src/urls/pattern-types.ts +21 -1
- package/src/urls/response-types.ts +29 -7
- package/src/urls/type-extraction.ts +23 -15
- package/src/use-loader.tsx +27 -9
- package/src/vite/discovery/bundle-postprocess.ts +32 -52
- package/src/vite/discovery/discover-routers.ts +52 -26
- package/src/vite/discovery/prerender-collection.ts +58 -41
- package/src/vite/discovery/route-types-writer.ts +7 -7
- package/src/vite/discovery/state.ts +7 -7
- package/src/vite/discovery/virtual-module-codegen.ts +5 -2
- package/src/vite/index.ts +10 -51
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +3 -3
- package/src/vite/plugins/expose-internal-ids.ts +4 -3
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +91 -3
- package/src/vite/plugins/version-plugin.ts +188 -18
- package/src/vite/rango.ts +61 -36
- package/src/vite/router-discovery.ts +173 -100
- package/src/vite/utils/prerender-utils.ts +81 -0
- package/src/vite/utils/shared-utils.ts +19 -9
- package/skills/testing/SKILL.md +0 -226
- package/src/browser/lru-cache.ts +0 -61
- package/src/browser/react/prefetch.ts +0 -27
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/route-definition/route-function.ts +0 -119
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- /package/{CLAUDE.md → AGENTS.md} +0 -0
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-Memory Cache Store
|
|
3
|
-
*
|
|
4
|
-
* Simple implementation for development and testing.
|
|
5
|
-
* Not suitable for production (no persistence, single-instance only).
|
|
6
|
-
*
|
|
7
|
-
* @internal This is reserved for future extensibility.
|
|
8
|
-
* For segment caching, use MemorySegmentCacheStore instead.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type {
|
|
12
|
-
CacheStore,
|
|
13
|
-
CacheEntry,
|
|
14
|
-
CacheValue,
|
|
15
|
-
CachePutOptions,
|
|
16
|
-
CacheMetadata,
|
|
17
|
-
CacheValueType,
|
|
18
|
-
} from "./types.js";
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Constants
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
/** Default TTL when no explicit value is provided */
|
|
25
|
-
const DEFAULT_TTL_SECONDS = 60;
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// Types
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
interface StoredEntry {
|
|
32
|
-
/** Stored value (streams/responses converted to ArrayBuffer) */
|
|
33
|
-
value: ArrayBuffer | string | object;
|
|
34
|
-
metadata: CacheMetadata;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* In-memory cache store implementation
|
|
39
|
-
*/
|
|
40
|
-
export class MemoryCacheStore implements CacheStore {
|
|
41
|
-
private cache = new Map<string, StoredEntry>();
|
|
42
|
-
|
|
43
|
-
async match<T = CacheValue>(key: string): Promise<CacheEntry<T> | undefined> {
|
|
44
|
-
const entry = this.cache.get(key);
|
|
45
|
-
|
|
46
|
-
if (!entry) {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Check expiration
|
|
51
|
-
if (entry.metadata.expiresAt && Date.now() > entry.metadata.expiresAt) {
|
|
52
|
-
this.cache.delete(key);
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Reconstruct value based on original type
|
|
57
|
-
const value = this.reconstructValue(entry);
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
value: value as T,
|
|
61
|
-
metadata: entry.metadata,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async put<T extends CacheValue>(
|
|
66
|
-
key: string,
|
|
67
|
-
value: T,
|
|
68
|
-
options?: CachePutOptions,
|
|
69
|
-
): Promise<void> {
|
|
70
|
-
const ttl = options?.ttl ?? DEFAULT_TTL_SECONDS;
|
|
71
|
-
const expiresAt = Date.now() + ttl * 1000;
|
|
72
|
-
|
|
73
|
-
// Detect value type and convert for storage
|
|
74
|
-
const { storedValue, valueType, responseHeaders, responseStatus } =
|
|
75
|
-
await this.prepareForStorage(value);
|
|
76
|
-
|
|
77
|
-
const metadata: CacheMetadata = {
|
|
78
|
-
...options?.metadata,
|
|
79
|
-
expiresAt,
|
|
80
|
-
valueType,
|
|
81
|
-
responseHeaders,
|
|
82
|
-
responseStatus,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
this.cache.set(key, {
|
|
86
|
-
value: storedValue,
|
|
87
|
-
metadata,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async delete(key: string): Promise<boolean> {
|
|
92
|
-
return this.cache.delete(key);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Clear all entries (useful for testing)
|
|
97
|
-
*/
|
|
98
|
-
clear(): void {
|
|
99
|
-
this.cache.clear();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get current cache size (useful for testing/debugging)
|
|
104
|
-
*/
|
|
105
|
-
get size(): number {
|
|
106
|
-
return this.cache.size;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Manually purge expired entries
|
|
111
|
-
*/
|
|
112
|
-
purgeExpired(): number {
|
|
113
|
-
const now = Date.now();
|
|
114
|
-
let purged = 0;
|
|
115
|
-
|
|
116
|
-
for (const [key, entry] of this.cache) {
|
|
117
|
-
if (entry.metadata.expiresAt && now > entry.metadata.expiresAt) {
|
|
118
|
-
this.cache.delete(key);
|
|
119
|
-
purged++;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return purged;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Prepare a value for storage
|
|
128
|
-
* Converts streams and responses to ArrayBuffer, detects type
|
|
129
|
-
*/
|
|
130
|
-
private async prepareForStorage(value: CacheValue): Promise<{
|
|
131
|
-
storedValue: ArrayBuffer | string | object;
|
|
132
|
-
valueType: CacheValueType;
|
|
133
|
-
responseHeaders?: Record<string, string>;
|
|
134
|
-
responseStatus?: number;
|
|
135
|
-
}> {
|
|
136
|
-
// ReadableStream -> ArrayBuffer
|
|
137
|
-
if (value instanceof ReadableStream) {
|
|
138
|
-
return {
|
|
139
|
-
storedValue: await streamToArrayBuffer(value),
|
|
140
|
-
valueType: "stream",
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Response -> ArrayBuffer + headers/status
|
|
145
|
-
if (value instanceof Response) {
|
|
146
|
-
const headers: Record<string, string> = {};
|
|
147
|
-
value.headers.forEach((v, k) => {
|
|
148
|
-
headers[k] = v;
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
storedValue: await value.clone().arrayBuffer(),
|
|
153
|
-
valueType: "response",
|
|
154
|
-
responseHeaders: headers,
|
|
155
|
-
responseStatus: value.status,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// ArrayBuffer -> store as-is
|
|
160
|
-
if (value instanceof ArrayBuffer) {
|
|
161
|
-
return {
|
|
162
|
-
storedValue: value,
|
|
163
|
-
valueType: "arraybuffer",
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// String -> store as-is
|
|
168
|
-
if (typeof value === "string") {
|
|
169
|
-
return {
|
|
170
|
-
storedValue: value,
|
|
171
|
-
valueType: "string",
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Object -> store as-is (JSON-serializable)
|
|
176
|
-
return {
|
|
177
|
-
storedValue: value,
|
|
178
|
-
valueType: "object",
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Reconstruct original value type from stored entry
|
|
184
|
-
*/
|
|
185
|
-
private reconstructValue(entry: StoredEntry): CacheValue {
|
|
186
|
-
const { value, metadata } = entry;
|
|
187
|
-
|
|
188
|
-
switch (metadata.valueType) {
|
|
189
|
-
case "stream":
|
|
190
|
-
return arrayBufferToStream(value as ArrayBuffer);
|
|
191
|
-
|
|
192
|
-
case "response": {
|
|
193
|
-
const status = metadata.responseStatus ?? 200;
|
|
194
|
-
// Status codes 204 (No Content) and 304 (Not Modified) cannot have a body
|
|
195
|
-
const isNullBodyStatus = status === 204 || status === 304;
|
|
196
|
-
return new Response(isNullBodyStatus ? null : (value as ArrayBuffer), {
|
|
197
|
-
status,
|
|
198
|
-
headers: metadata.responseHeaders,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
case "arraybuffer":
|
|
203
|
-
case "string":
|
|
204
|
-
case "object":
|
|
205
|
-
default:
|
|
206
|
-
return value as CacheValue;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Convert a ReadableStream to ArrayBuffer.
|
|
213
|
-
* @internal
|
|
214
|
-
*/
|
|
215
|
-
async function streamToArrayBuffer(
|
|
216
|
-
stream: ReadableStream<Uint8Array>,
|
|
217
|
-
): Promise<ArrayBuffer> {
|
|
218
|
-
const chunks: Uint8Array[] = [];
|
|
219
|
-
const reader = stream.getReader();
|
|
220
|
-
|
|
221
|
-
while (true) {
|
|
222
|
-
const { done, value } = await reader.read();
|
|
223
|
-
if (done) break;
|
|
224
|
-
chunks.push(value);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Concatenate chunks
|
|
228
|
-
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
229
|
-
const result = new Uint8Array(totalLength);
|
|
230
|
-
let offset = 0;
|
|
231
|
-
|
|
232
|
-
for (const chunk of chunks) {
|
|
233
|
-
result.set(chunk, offset);
|
|
234
|
-
offset += chunk.length;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return result.buffer;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Convert an ArrayBuffer to a ReadableStream.
|
|
242
|
-
* @internal
|
|
243
|
-
*/
|
|
244
|
-
function arrayBufferToStream(buffer: ArrayBuffer): ReadableStream<Uint8Array> {
|
|
245
|
-
const uint8 = new Uint8Array(buffer);
|
|
246
|
-
|
|
247
|
-
return new ReadableStream({
|
|
248
|
-
start(controller) {
|
|
249
|
-
controller.enqueue(uint8);
|
|
250
|
-
controller.close();
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
}
|
package/src/href-context.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Href Context for route name resolution
|
|
5
|
-
*
|
|
6
|
-
* This module is marked "use client" so it can be imported by both:
|
|
7
|
-
* - Server (segment-system): Gets a client reference for createElement
|
|
8
|
-
* - Client (useHref): Uses the actual context for useContext
|
|
9
|
-
*
|
|
10
|
-
* The context stores:
|
|
11
|
-
* - routeMap: Map of route names to URL patterns
|
|
12
|
-
* - routeName: Current matched route name (for local name resolution)
|
|
13
|
-
*/
|
|
14
|
-
import { createContext, type Context } from "react";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Context value for href resolution
|
|
18
|
-
*/
|
|
19
|
-
export interface HrefContextValue {
|
|
20
|
-
/** Route map: route name -> URL pattern */
|
|
21
|
-
routeMap: Record<string, string>;
|
|
22
|
-
/** Current matched route name (includes name prefix from include()) */
|
|
23
|
-
routeName?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Context for href resolution (route map and current route name)
|
|
28
|
-
*
|
|
29
|
-
* On the server: Populated by renderSegments() via HrefContext.Provider
|
|
30
|
-
* On the client: Populated by NavigationProvider from RSC metadata
|
|
31
|
-
*/
|
|
32
|
-
export const HrefContext: Context<HrefContextValue | null> =
|
|
33
|
-
createContext<HrefContextValue | null>(null);
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ResolvedRouteMap,
|
|
3
|
-
RouteConfig,
|
|
4
|
-
RouteDefinition,
|
|
5
|
-
RouteDefinitionOptions,
|
|
6
|
-
TrailingSlashMode,
|
|
7
|
-
} from "../types.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Result of route() function with paths and trailing slash config
|
|
11
|
-
*/
|
|
12
|
-
export interface RouteDefinitionResult<T extends RouteDefinition> {
|
|
13
|
-
routes: ResolvedRouteMap<T>;
|
|
14
|
-
trailingSlash: Record<string, TrailingSlashMode>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Check if a value is a RouteConfig object
|
|
19
|
-
*/
|
|
20
|
-
function isRouteConfig(value: unknown): value is RouteConfig {
|
|
21
|
-
return (
|
|
22
|
-
typeof value === "object" &&
|
|
23
|
-
value !== null &&
|
|
24
|
-
"path" in value &&
|
|
25
|
-
typeof (value as RouteConfig).path === "string"
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Define routes with optional trailing slash configuration
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```typescript
|
|
34
|
-
* // Simple string paths
|
|
35
|
-
* const routes = route({
|
|
36
|
-
* blog: "/blog",
|
|
37
|
-
* post: "/blog/:id",
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* // With trailing slash config
|
|
41
|
-
* const routes = route({
|
|
42
|
-
* blog: "/blog",
|
|
43
|
-
* api: { path: "/api", trailingSlash: "ignore" },
|
|
44
|
-
* }, { trailingSlash: "never" }); // global default
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
export function route<const T extends RouteDefinition>(
|
|
48
|
-
input: T,
|
|
49
|
-
options?: RouteDefinitionOptions,
|
|
50
|
-
): ResolvedRouteMap<T> & {
|
|
51
|
-
__trailingSlash?: Record<string, TrailingSlashMode>;
|
|
52
|
-
} {
|
|
53
|
-
const trailingSlash: Record<string, TrailingSlashMode> = {};
|
|
54
|
-
const routes = flattenRoutes(
|
|
55
|
-
input as RouteDefinition,
|
|
56
|
-
"",
|
|
57
|
-
trailingSlash,
|
|
58
|
-
options?.trailingSlash,
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// Attach trailing slash config as a non-enumerable property
|
|
62
|
-
// This keeps backwards compatibility while passing the config through
|
|
63
|
-
const result = routes as ResolvedRouteMap<T> & {
|
|
64
|
-
__trailingSlash?: Record<string, TrailingSlashMode>;
|
|
65
|
-
};
|
|
66
|
-
if (Object.keys(trailingSlash).length > 0) {
|
|
67
|
-
Object.defineProperty(result, "__trailingSlash", {
|
|
68
|
-
value: trailingSlash,
|
|
69
|
-
enumerable: false,
|
|
70
|
-
writable: false,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Flatten nested route definitions
|
|
79
|
-
*/
|
|
80
|
-
function flattenRoutes(
|
|
81
|
-
routes: RouteDefinition,
|
|
82
|
-
prefix: string,
|
|
83
|
-
trailingSlashConfig: Record<string, TrailingSlashMode>,
|
|
84
|
-
defaultTrailingSlash?: TrailingSlashMode,
|
|
85
|
-
): Record<string, string> {
|
|
86
|
-
const flattened: Record<string, string> = {};
|
|
87
|
-
|
|
88
|
-
for (const [key, value] of Object.entries(routes)) {
|
|
89
|
-
const fullKey = prefix + key;
|
|
90
|
-
|
|
91
|
-
if (typeof value === "string") {
|
|
92
|
-
// Direct route pattern - include prefix
|
|
93
|
-
flattened[fullKey] = value;
|
|
94
|
-
// Apply default trailing slash if set
|
|
95
|
-
if (defaultTrailingSlash) {
|
|
96
|
-
trailingSlashConfig[fullKey] = defaultTrailingSlash;
|
|
97
|
-
}
|
|
98
|
-
} else if (isRouteConfig(value)) {
|
|
99
|
-
// Route config object with path and optional trailingSlash
|
|
100
|
-
flattened[fullKey] = value.path;
|
|
101
|
-
// Use route-specific config or fall back to default
|
|
102
|
-
const mode = value.trailingSlash ?? defaultTrailingSlash;
|
|
103
|
-
if (mode) {
|
|
104
|
-
trailingSlashConfig[fullKey] = mode;
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
// Nested routes - flatten recursively
|
|
108
|
-
const nested = flattenRoutes(
|
|
109
|
-
value,
|
|
110
|
-
`${fullKey}.`,
|
|
111
|
-
trailingSlashConfig,
|
|
112
|
-
defaultTrailingSlash,
|
|
113
|
-
);
|
|
114
|
-
Object.assign(flattened, nested);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return flattened;
|
|
119
|
-
}
|
package/src/router.gen.ts
DELETED
package/src/urls.gen.ts
DELETED
/package/{CLAUDE.md → AGENTS.md}
RENAMED
|
File without changes
|