@rangojs/router 0.0.0-experimental.7 → 0.0.0-experimental.71
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/AGENTS.md +9 -0
- package/README.md +942 -4
- package/dist/bin/rango.js +1689 -0
- package/dist/vite/index.js +4951 -930
- package/package.json +70 -60
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +334 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +92 -31
- package/skills/loader/SKILL.md +404 -44
- package/skills/middleware/SKILL.md +173 -34
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +204 -1
- package/skills/prerender/SKILL.md +685 -0
- package/skills/rango/SKILL.md +85 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +257 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +328 -89
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +296 -558
- package/src/browser/navigation-client.ts +179 -69
- package/src/browser/navigation-store.ts +73 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +328 -313
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +150 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +160 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +230 -74
- package/src/browser/react/NavigationProvider.tsx +87 -11
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- 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 +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +30 -126
- package/src/browser/react/use-href.tsx +2 -2
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +76 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +214 -58
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +221 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +141 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +39 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +418 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +618 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/runtime-discovery.ts +231 -0
- 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 +342 -0
- package/src/cache/cache-scope.ts +167 -309
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +105 -179
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +108 -2
- package/src/handle.ts +55 -29
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +155 -19
- package/src/index.ts +223 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -157
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +186 -0
- package/src/prerender.ts +524 -0
- package/src/reverse.ts +351 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +982 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +434 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-definition.ts +1 -1428
- package/src/route-map-builder.ts +217 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +70 -8
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +435 -86
- package/src/router/intercept-resolution.ts +402 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +356 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +154 -35
- package/src/router/match-api.ts +555 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +459 -10
- package/src/router/match-middleware/cache-store.ts +98 -26
- package/src/router/match-middleware/intercept-resolution.ts +57 -17
- package/src/router/match-middleware/segment-resolution.ts +80 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +135 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +220 -0
- package/src/router/middleware.ts +324 -369
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +748 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1379 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +291 -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 +239 -0
- package/src/router/types.ts +78 -3
- package/src/router.ts +740 -4252
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +907 -797
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +391 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +246 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +356 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +46 -11
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +165 -17
- package/src/server/context.ts +315 -58
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +607 -81
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +103 -30
- package/src/static-handler.ts +126 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +791 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +210 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +109 -0
- package/src/types/segments.ts +151 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +346 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +116 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -802
- package/src/use-loader.tsx +161 -81
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +348 -0
- package/src/vite/discovery/prerender-collection.ts +439 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -1129
- package/src/vite/plugin-types.ts +103 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -53
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +786 -0
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +462 -0
- package/src/vite/router-discovery.ts +918 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +207 -0
- package/src/vite/utils/shared-utils.ts +170 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- 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/href.ts +0 -255
- package/src/server/route-manifest-cache.ts +0 -173
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- /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
|
-
}
|