@rangojs/router 0.0.0-experimental.20 → 0.0.0-experimental.20dbba0c
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 +4 -0
- package/README.md +172 -50
- package/dist/bin/rango.js +138 -50
- package/dist/vite/index.js +1160 -508
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +17 -16
- package/skills/breadcrumbs/SKILL.md +252 -0
- package/skills/cache-guide/SKILL.md +32 -0
- package/skills/caching/SKILL.md +49 -8
- package/skills/document-cache/SKILL.md +2 -2
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +61 -51
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +20 -0
- package/skills/layout/SKILL.md +22 -0
- package/skills/links/SKILL.md +91 -17
- package/skills/loader/SKILL.md +107 -24
- package/skills/middleware/SKILL.md +34 -3
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +765 -0
- package/skills/parallel/SKILL.md +185 -0
- package/skills/prerender/SKILL.md +112 -70
- package/skills/rango/SKILL.md +24 -23
- package/skills/response-routes/SKILL.md +8 -0
- package/skills/route/SKILL.md +58 -4
- package/skills/router-setup/SKILL.md +95 -5
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/typesafety/SKILL.md +38 -24
- package/src/__internal.ts +92 -0
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +5 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +175 -17
- package/src/browser/navigation-client.ts +177 -44
- package/src/browser/navigation-store.ts +68 -9
- package/src/browser/navigation-transaction.ts +11 -9
- package/src/browser/partial-update.ts +113 -17
- package/src/browser/prefetch/cache.ts +275 -28
- package/src/browser/prefetch/fetch.ts +191 -46
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +123 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +53 -13
- package/src/browser/react/Link.tsx +98 -14
- package/src/browser/react/NavigationProvider.tsx +89 -14
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/use-handle.ts +9 -58
- package/src/browser/react/use-navigation.ts +22 -2
- package/src/browser/react/use-params.ts +11 -1
- package/src/browser/react/use-router.ts +29 -9
- package/src/browser/rsc-router.tsx +177 -66
- package/src/browser/scroll-restoration.ts +41 -42
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/server-action-bridge.ts +8 -6
- package/src/browser/types.ts +73 -5
- package/src/build/generate-manifest.ts +6 -6
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/route-trie.ts +67 -25
- package/src/build/route-types/include-resolution.ts +8 -1
- package/src/build/route-types/router-processing.ts +223 -74
- package/src/build/route-types/scan-filter.ts +8 -1
- package/src/cache/cache-runtime.ts +15 -11
- package/src/cache/cache-scope.ts +48 -7
- package/src/cache/cf/cf-cache-store.ts +455 -15
- package/src/cache/cf/index.ts +5 -1
- package/src/cache/document-cache.ts +17 -7
- package/src/cache/index.ts +1 -0
- package/src/cache/taint.ts +55 -0
- package/src/client.rsc.tsx +2 -1
- package/src/client.tsx +85 -276
- package/src/context-var.ts +72 -2
- package/src/debug.ts +2 -2
- package/src/handle.ts +40 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/host/index.ts +0 -3
- package/src/index.rsc.ts +9 -36
- package/src/index.ts +79 -70
- package/src/outlet-context.ts +1 -1
- package/src/prerender/store.ts +57 -15
- package/src/prerender.ts +138 -77
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +27 -2
- package/src/route-definition/dsl-helpers.ts +240 -40
- package/src/route-definition/helpers-types.ts +67 -19
- package/src/route-definition/index.ts +3 -3
- package/src/route-definition/redirect.ts +11 -3
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-map-builder.ts +7 -1
- package/src/route-types.ts +18 -0
- package/src/router/content-negotiation.ts +100 -1
- package/src/router/find-match.ts +4 -2
- package/src/router/handler-context.ts +129 -26
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +10 -7
- package/src/router/loader-resolution.ts +160 -22
- package/src/router/logging.ts +5 -2
- package/src/router/manifest.ts +31 -16
- package/src/router/match-api.ts +128 -193
- package/src/router/match-middleware/background-revalidation.ts +30 -2
- package/src/router/match-middleware/cache-lookup.ts +94 -17
- package/src/router/match-middleware/cache-store.ts +53 -10
- package/src/router/match-middleware/intercept-resolution.ts +9 -7
- package/src/router/match-middleware/segment-resolution.ts +61 -5
- package/src/router/match-result.ts +103 -18
- package/src/router/metrics.ts +238 -13
- package/src/router/middleware-types.ts +48 -27
- package/src/router/middleware.ts +201 -86
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +77 -11
- package/src/router/prerender-match.ts +114 -10
- package/src/router/preview-match.ts +30 -102
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +27 -7
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +6 -1
- package/src/router/router-interfaces.ts +50 -5
- package/src/router/router-options.ts +50 -19
- package/src/router/segment-resolution/fresh.ts +215 -19
- package/src/router/segment-resolution/helpers.ts +30 -25
- package/src/router/segment-resolution/loader-cache.ts +1 -0
- package/src/router/segment-resolution/revalidation.ts +454 -301
- package/src/router/segment-wrappers.ts +2 -0
- package/src/router/trie-matching.ts +30 -6
- package/src/router/types.ts +1 -0
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +89 -17
- package/src/rsc/handler.ts +563 -364
- package/src/rsc/helpers.ts +69 -41
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +5 -1
- package/src/rsc/progressive-enhancement.ts +37 -10
- package/src/rsc/response-route-handler.ts +14 -1
- package/src/rsc/rsc-rendering.ts +47 -44
- package/src/rsc/server-action.ts +24 -10
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +11 -1
- package/src/search-params.ts +16 -13
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +109 -23
- package/src/server/context.ts +174 -19
- package/src/server/handle-store.ts +19 -0
- package/src/server/loader-registry.ts +9 -8
- package/src/server/request-context.ts +218 -65
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +4 -0
- package/src/static-handler.ts +18 -6
- package/src/theme/index.ts +4 -13
- package/src/types/cache-types.ts +4 -4
- package/src/types/handler-context.ts +140 -72
- package/src/types/loader-types.ts +41 -15
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-config.ts +17 -8
- package/src/types/route-entry.ts +19 -1
- package/src/types/segments.ts +2 -5
- package/src/urls/include-helper.ts +24 -14
- package/src/urls/path-helper-types.ts +39 -6
- package/src/urls/path-helper.ts +48 -13
- package/src/urls/pattern-types.ts +12 -0
- package/src/urls/response-types.ts +18 -16
- package/src/use-loader.tsx +77 -5
- package/src/vite/discovery/bundle-postprocess.ts +61 -89
- package/src/vite/discovery/discover-routers.ts +7 -4
- package/src/vite/discovery/prerender-collection.ts +162 -88
- package/src/vite/discovery/state.ts +17 -13
- package/src/vite/index.ts +8 -3
- package/src/vite/plugin-types.ts +51 -79
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/plugins/expose-action-id.ts +1 -3
- package/src/vite/plugins/expose-id-utils.ts +12 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +30 -0
- package/src/vite/plugins/expose-internal-ids.ts +257 -40
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/version-plugin.ts +13 -1
- package/src/vite/rango.ts +190 -217
- package/src/vite/router-discovery.ts +241 -45
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/package-resolution.ts +34 -1
- package/src/vite/utils/prerender-utils.ts +97 -5
- package/src/vite/utils/shared-utils.ts +3 -2
- package/skills/testing/SKILL.md +0 -226
- package/src/route-definition/route-function.ts +0 -119
package/src/debug.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Debug utilities for manifest inspection and comparison
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type
|
|
5
|
+
import { getParallelSlotCount, type EntryData } from "./server/context";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Serialized entry for debug output
|
|
@@ -64,7 +64,7 @@ export function serializeManifest(
|
|
|
64
64
|
hasLoader: entry.loader?.length > 0,
|
|
65
65
|
hasMiddleware: entry.middleware?.length > 0,
|
|
66
66
|
hasErrorBoundary: entry.errorBoundary?.length > 0,
|
|
67
|
-
parallelCount: entry.parallel
|
|
67
|
+
parallelCount: getParallelSlotCount(entry.parallel),
|
|
68
68
|
interceptCount: entry.intercept?.length ?? 0,
|
|
69
69
|
};
|
|
70
70
|
|
package/src/handle.ts
CHANGED
|
@@ -133,3 +133,43 @@ export function isHandle(value: unknown): value is Handle<unknown, unknown> {
|
|
|
133
133
|
(value as { __brand: unknown }).__brand === "handle"
|
|
134
134
|
);
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Collect handle data from a HandleData map, applying the handle's collect
|
|
139
|
+
* function over segments in order. Shared between server-side rendered()
|
|
140
|
+
* reads and client-side useHandle().
|
|
141
|
+
*
|
|
142
|
+
* @param handle - The handle to collect data for
|
|
143
|
+
* @param data - Full handle data map (handleName -> segmentId -> entries[])
|
|
144
|
+
* @param segmentOrder - Segment IDs in parent -> child resolution order
|
|
145
|
+
*/
|
|
146
|
+
export function collectHandleData<TData, TAccumulated>(
|
|
147
|
+
handle: Handle<TData, TAccumulated>,
|
|
148
|
+
data: Record<string, Record<string, unknown[]>>,
|
|
149
|
+
segmentOrder: string[],
|
|
150
|
+
): TAccumulated {
|
|
151
|
+
const collectFn = getCollectFn(handle.$$id);
|
|
152
|
+
if (!collectFn && process.env.NODE_ENV !== "production") {
|
|
153
|
+
console.warn(
|
|
154
|
+
`[rsc-router] Handle "${handle.$$id}" has no registered collect function. ` +
|
|
155
|
+
`Falling back to flat array. Ensure the handle module is imported so ` +
|
|
156
|
+
`createHandle() runs and registers the collect function.`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
const collect = (collectFn ??
|
|
160
|
+
(defaultCollect as unknown as (segments: unknown[][]) => unknown)) as (
|
|
161
|
+
segments: TData[][],
|
|
162
|
+
) => TAccumulated;
|
|
163
|
+
|
|
164
|
+
const segmentData = data[handle.$$id];
|
|
165
|
+
if (!segmentData) return collect([]);
|
|
166
|
+
|
|
167
|
+
const segmentArrays: TData[][] = [];
|
|
168
|
+
for (const segmentId of segmentOrder) {
|
|
169
|
+
const entries = segmentData[segmentId];
|
|
170
|
+
if (entries && entries.length > 0) {
|
|
171
|
+
segmentArrays.push(entries as TData[]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return collect(segmentArrays);
|
|
175
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Breadcrumbs handle for accumulating breadcrumb items across route segments.
|
|
3
|
+
*
|
|
4
|
+
* Each layout/route pushes breadcrumb items via `ctx.use(Breadcrumbs)`.
|
|
5
|
+
* Items are collected in parent-to-child order with automatic deduplication
|
|
6
|
+
* by `href` (last item for each href wins).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // In route handler
|
|
11
|
+
* route("/blog/:slug", (ctx) => {
|
|
12
|
+
* const breadcrumb = ctx.use(Breadcrumbs);
|
|
13
|
+
* breadcrumb({ label: "Blog", href: "/blog" });
|
|
14
|
+
* breadcrumb({ label: post.title, href: `/blog/${ctx.params.slug}` });
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // In client component (consume with useHandle)
|
|
18
|
+
* const crumbs = useHandle(Breadcrumbs);
|
|
19
|
+
* crumbs.map((c) => <a href={c.href}>{c.label}</a>);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { ReactNode } from "react";
|
|
24
|
+
import { createHandle, type Handle } from "../handle.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A single breadcrumb item.
|
|
28
|
+
*
|
|
29
|
+
* @property label - Display text for the breadcrumb
|
|
30
|
+
* @property href - URL the breadcrumb links to
|
|
31
|
+
* @property content - Optional extra content (sync or async) rendered alongside the label
|
|
32
|
+
*/
|
|
33
|
+
export interface BreadcrumbItem {
|
|
34
|
+
label: string;
|
|
35
|
+
href: string;
|
|
36
|
+
content?: ReactNode | Promise<ReactNode>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Collect function for Breadcrumbs handle.
|
|
41
|
+
* Flattens segments in parent-to-child order with deduplication by href
|
|
42
|
+
* (last item for each href wins).
|
|
43
|
+
*/
|
|
44
|
+
function collectBreadcrumbs(segments: BreadcrumbItem[][]): BreadcrumbItem[] {
|
|
45
|
+
const all = segments.flat();
|
|
46
|
+
const seen = new Map<string, number>();
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < all.length; i++) {
|
|
49
|
+
seen.set(all[i].href, i);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Return items in order, keeping only the last occurrence per href
|
|
53
|
+
return all.filter((item, index) => seen.get(item.href) === index);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Built-in handle for accumulating breadcrumb navigation items.
|
|
58
|
+
*
|
|
59
|
+
* Use `ctx.use(Breadcrumbs)` in route handlers to push breadcrumb items.
|
|
60
|
+
* Use `useHandle(Breadcrumbs)` in client components to consume them.
|
|
61
|
+
*/
|
|
62
|
+
export const Breadcrumbs: Handle<BreadcrumbItem, BreadcrumbItem[]> =
|
|
63
|
+
createHandle<BreadcrumbItem, BreadcrumbItem[]>(
|
|
64
|
+
collectBreadcrumbs,
|
|
65
|
+
"__rsc_router_breadcrumbs__",
|
|
66
|
+
);
|
package/src/handles/index.ts
CHANGED
package/src/host/index.ts
CHANGED
|
@@ -25,9 +25,6 @@
|
|
|
25
25
|
// Core router
|
|
26
26
|
export { createHostRouter } from "./router.js";
|
|
27
27
|
|
|
28
|
-
// Host router registry for build-time discovery
|
|
29
|
-
export { HostRouterRegistry, type HostRouterRegistryEntry } from "./router.js";
|
|
30
|
-
|
|
31
28
|
// Utilities
|
|
32
29
|
export { defineHosts } from "./utils.js";
|
|
33
30
|
|
package/src/index.rsc.ts
CHANGED
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
// Re-export all universal exports from index.ts
|
|
13
13
|
export {
|
|
14
|
-
// Universal rendering utilities
|
|
15
|
-
renderSegments,
|
|
16
14
|
// Error classes
|
|
17
15
|
RouteNotFoundError,
|
|
18
16
|
DataNotFoundError,
|
|
@@ -21,9 +19,6 @@ export {
|
|
|
21
19
|
HandlerError,
|
|
22
20
|
BuildError,
|
|
23
21
|
InvalidHandlerError,
|
|
24
|
-
NetworkError,
|
|
25
|
-
isNetworkError,
|
|
26
|
-
sanitizeError,
|
|
27
22
|
RouterError,
|
|
28
23
|
Skip,
|
|
29
24
|
isSkip,
|
|
@@ -40,7 +35,6 @@ export type {
|
|
|
40
35
|
TrailingSlashMode,
|
|
41
36
|
// Handler types
|
|
42
37
|
Handler,
|
|
43
|
-
ScopedRouteMap,
|
|
44
38
|
HandlerContext,
|
|
45
39
|
ExtractParams,
|
|
46
40
|
GenericParams,
|
|
@@ -106,6 +100,7 @@ export type {
|
|
|
106
100
|
LayoutUseItem,
|
|
107
101
|
AllUseItems,
|
|
108
102
|
UseItems,
|
|
103
|
+
HandlerUseItem,
|
|
109
104
|
} from "./route-types.js";
|
|
110
105
|
|
|
111
106
|
// Handle API
|
|
@@ -120,9 +115,9 @@ export { nonce } from "./rsc/nonce.js";
|
|
|
120
115
|
// Pre-render handler API
|
|
121
116
|
export {
|
|
122
117
|
Prerender,
|
|
123
|
-
|
|
118
|
+
Passthrough,
|
|
124
119
|
type PrerenderHandlerDefinition,
|
|
125
|
-
type
|
|
120
|
+
type PassthroughHandlerDefinition,
|
|
126
121
|
type PrerenderOptions,
|
|
127
122
|
type BuildContext,
|
|
128
123
|
type StaticBuildContext,
|
|
@@ -130,16 +125,11 @@ export {
|
|
|
130
125
|
} from "./prerender.js";
|
|
131
126
|
|
|
132
127
|
// Static handler API
|
|
133
|
-
export {
|
|
134
|
-
Static,
|
|
135
|
-
isStaticHandler,
|
|
136
|
-
type StaticHandlerDefinition,
|
|
137
|
-
} from "./static-handler.js";
|
|
128
|
+
export { Static, type StaticHandlerDefinition } from "./static-handler.js";
|
|
138
129
|
|
|
139
130
|
// Django-style URL patterns (RSC/server context)
|
|
140
131
|
export {
|
|
141
132
|
urls,
|
|
142
|
-
RESPONSE_TYPE,
|
|
143
133
|
type PathHelpers,
|
|
144
134
|
type PathOptions,
|
|
145
135
|
type UrlPatterns,
|
|
@@ -171,6 +161,7 @@ export type { HandlerCacheConfig } from "./rsc/types.js";
|
|
|
171
161
|
|
|
172
162
|
// Built-in handles (server-side)
|
|
173
163
|
export { Meta } from "./handles/meta.js";
|
|
164
|
+
export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
|
|
174
165
|
|
|
175
166
|
// Request context (for accessing request data in server actions/components).
|
|
176
167
|
// Re-exported with a narrowed return type so that public consumers only see
|
|
@@ -181,6 +172,9 @@ export type { PublicRequestContext as RequestContext } from "./server/request-co
|
|
|
181
172
|
import type { PublicRequestContext } from "./server/request-context.js";
|
|
182
173
|
import type { DefaultEnv } from "./types/global-namespace.js";
|
|
183
174
|
|
|
175
|
+
// Shared base for every user-facing request context (mirrors index.ts).
|
|
176
|
+
export type { RequestScope, ExecutionContext } from "./types/request-scope.js";
|
|
177
|
+
|
|
184
178
|
export const getRequestContext: <
|
|
185
179
|
TEnv = DefaultEnv,
|
|
186
180
|
>() => PublicRequestContext<TEnv> = _getRequestContextInternal;
|
|
@@ -206,8 +200,6 @@ export type {
|
|
|
206
200
|
ReverseFunction,
|
|
207
201
|
ExtractLocalRoutes,
|
|
208
202
|
ParamsFor,
|
|
209
|
-
SanitizePrefix,
|
|
210
|
-
MergeRoutes,
|
|
211
203
|
} from "./reverse.js";
|
|
212
204
|
export { scopedReverse, createReverse } from "./reverse.js";
|
|
213
205
|
|
|
@@ -220,12 +212,6 @@ export type {
|
|
|
220
212
|
RouteParams,
|
|
221
213
|
} from "./search-params.js";
|
|
222
214
|
|
|
223
|
-
// Debug utilities for route matching (development only)
|
|
224
|
-
export {
|
|
225
|
-
enableMatchDebug,
|
|
226
|
-
getMatchDebugStats,
|
|
227
|
-
} from "./router/pattern-matching.js";
|
|
228
|
-
|
|
229
215
|
// Location state (universal)
|
|
230
216
|
export {
|
|
231
217
|
createLocationState,
|
|
@@ -241,20 +227,7 @@ export type { PathResponse } from "./href-client.js";
|
|
|
241
227
|
export { createConsoleSink } from "./router/telemetry.js";
|
|
242
228
|
export { createOTelSink } from "./router/telemetry-otel.js";
|
|
243
229
|
export type { OTelTracer, OTelSpan } from "./router/telemetry-otel.js";
|
|
244
|
-
export type {
|
|
245
|
-
TelemetrySink,
|
|
246
|
-
TelemetryEvent,
|
|
247
|
-
RequestStartEvent,
|
|
248
|
-
RequestEndEvent,
|
|
249
|
-
RequestErrorEvent,
|
|
250
|
-
RequestTimeoutEvent,
|
|
251
|
-
LoaderStartEvent,
|
|
252
|
-
LoaderEndEvent,
|
|
253
|
-
LoaderErrorEvent,
|
|
254
|
-
HandlerErrorEvent,
|
|
255
|
-
CacheDecisionEvent,
|
|
256
|
-
RevalidationDecisionEvent,
|
|
257
|
-
} from "./router/telemetry.js";
|
|
230
|
+
export type { TelemetrySink, TelemetryEvent } from "./router/telemetry.js";
|
|
258
231
|
|
|
259
232
|
// Timeout types and error class
|
|
260
233
|
export { RouterTimeoutError } from "./router/timeout.js";
|
package/src/index.ts
CHANGED
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
* import from "@rangojs/router/client"
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
// Universal rendering utilities (work on both server and client)
|
|
14
|
-
export { renderSegments } from "./segment-system.js";
|
|
15
|
-
|
|
16
13
|
// Error classes (can be used on both server and client)
|
|
17
14
|
export {
|
|
18
15
|
RouteNotFoundError,
|
|
@@ -22,9 +19,6 @@ export {
|
|
|
22
19
|
HandlerError,
|
|
23
20
|
BuildError,
|
|
24
21
|
InvalidHandlerError,
|
|
25
|
-
NetworkError,
|
|
26
|
-
isNetworkError,
|
|
27
|
-
sanitizeError,
|
|
28
22
|
RouterError,
|
|
29
23
|
Skip,
|
|
30
24
|
isSkip,
|
|
@@ -41,7 +35,6 @@ export type {
|
|
|
41
35
|
TrailingSlashMode,
|
|
42
36
|
// Handler types
|
|
43
37
|
Handler, // Supports params object, path pattern, or route name
|
|
44
|
-
ScopedRouteMap, // Scoped view of GeneratedRouteMap for Handler<"localName", ScopedRouteMap<"prefix">>
|
|
45
38
|
HandlerContext,
|
|
46
39
|
ExtractParams,
|
|
47
40
|
GenericParams,
|
|
@@ -95,6 +88,7 @@ export type {
|
|
|
95
88
|
LayoutUseItem,
|
|
96
89
|
AllUseItems,
|
|
97
90
|
UseItems,
|
|
91
|
+
HandlerUseItem,
|
|
98
92
|
} from "./route-types.js";
|
|
99
93
|
|
|
100
94
|
// Response route types (usable in both server and client contexts)
|
|
@@ -115,25 +109,32 @@ export type {
|
|
|
115
109
|
// Middleware context types
|
|
116
110
|
export type { MiddlewareContext, CookieOptions } from "./router/middleware.js";
|
|
117
111
|
|
|
112
|
+
function serverOnlyStubError(name: string): Error {
|
|
113
|
+
return new Error(
|
|
114
|
+
`${name}() is only available from "@rangojs/router" in a react-server/RSC environment. ` +
|
|
115
|
+
`For client hooks and components, import from "@rangojs/router/client".`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
118
119
|
/**
|
|
119
120
|
* Error-throwing stub for server-only `urls` function.
|
|
120
121
|
*/
|
|
121
122
|
export function urls(): never {
|
|
122
|
-
throw
|
|
123
|
+
throw serverOnlyStubError("urls");
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
127
|
* Error-throwing stub for server-only `createRouter` function.
|
|
127
128
|
*/
|
|
128
129
|
export function createRouter(): never {
|
|
129
|
-
throw
|
|
130
|
+
throw serverOnlyStubError("createRouter");
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
134
|
* Error-throwing stub for server-only `redirect` function.
|
|
134
135
|
*/
|
|
135
136
|
export function redirect(): never {
|
|
136
|
-
throw
|
|
137
|
+
throw serverOnlyStubError("redirect");
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
// Handle API (universal - works on both server and client)
|
|
@@ -146,110 +147,126 @@ export { createVar, type ContextVar } from "./context-var.js";
|
|
|
146
147
|
export { nonce } from "./rsc/nonce.js";
|
|
147
148
|
|
|
148
149
|
/**
|
|
149
|
-
*
|
|
150
|
+
* SSR/client stub for server-only `Prerender` function.
|
|
151
|
+
*
|
|
152
|
+
* Returns a lightweight stub object instead of throwing so that the
|
|
153
|
+
* production SSR build can safely bundle the RSC entry chunk — the SSR
|
|
154
|
+
* bundler resolves `@rangojs/router` to this (SSR) entry, so Prerender
|
|
155
|
+
* calls in RSC code must not crash at module-evaluation time.
|
|
150
156
|
*/
|
|
151
|
-
export function Prerender(
|
|
152
|
-
|
|
157
|
+
export function Prerender(
|
|
158
|
+
_handler?: any,
|
|
159
|
+
_optionsOrId?: any,
|
|
160
|
+
__injectedId?: string,
|
|
161
|
+
): any {
|
|
162
|
+
const id =
|
|
163
|
+
typeof _optionsOrId === "string" ? _optionsOrId : __injectedId || "";
|
|
164
|
+
return { __brand: "prerenderHandler" as const, $$id: id };
|
|
153
165
|
}
|
|
154
166
|
|
|
155
167
|
/**
|
|
156
|
-
*
|
|
168
|
+
* SSR/client stub for server-only `Passthrough` function.
|
|
157
169
|
*/
|
|
158
|
-
export function
|
|
159
|
-
|
|
170
|
+
export function Passthrough(
|
|
171
|
+
_handler?: any,
|
|
172
|
+
_optionsOrId?: any,
|
|
173
|
+
__injectedId?: string,
|
|
174
|
+
): any {
|
|
175
|
+
const id =
|
|
176
|
+
typeof _optionsOrId === "string" ? _optionsOrId : __injectedId || "";
|
|
177
|
+
return { __brand: "passthroughHandler" as const, $$id: id };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* SSR/client stub for server-only `Static` function.
|
|
182
|
+
*
|
|
183
|
+
* Returns a lightweight stub object instead of throwing so that the
|
|
184
|
+
* production SSR build can safely bundle the RSC entry chunk — the SSR
|
|
185
|
+
* bundler resolves `@rangojs/router` to this (SSR) entry, so Static
|
|
186
|
+
* calls in RSC code must not crash at module-evaluation time.
|
|
187
|
+
*/
|
|
188
|
+
export function Static(
|
|
189
|
+
_handler?: any,
|
|
190
|
+
_optionsOrId?: any,
|
|
191
|
+
__injectedId?: string,
|
|
192
|
+
): any {
|
|
193
|
+
const id =
|
|
194
|
+
typeof _optionsOrId === "string" ? _optionsOrId : __injectedId || "";
|
|
195
|
+
return { __brand: "staticHandler" as const, $$id: id };
|
|
160
196
|
}
|
|
161
197
|
|
|
162
198
|
/**
|
|
163
199
|
* Error-throwing stub for server-only `getRequestContext` function.
|
|
164
200
|
*/
|
|
165
201
|
export function getRequestContext(): never {
|
|
166
|
-
throw
|
|
167
|
-
"getRequestContext() is server-only and requires RSC context.",
|
|
168
|
-
);
|
|
202
|
+
throw serverOnlyStubError("getRequestContext");
|
|
169
203
|
}
|
|
170
204
|
|
|
171
205
|
/**
|
|
172
206
|
* Error-throwing stub for server-only `cookies` function.
|
|
173
207
|
*/
|
|
174
208
|
export function cookies(): never {
|
|
175
|
-
throw
|
|
209
|
+
throw serverOnlyStubError("cookies");
|
|
176
210
|
}
|
|
177
211
|
|
|
178
212
|
/**
|
|
179
213
|
* Error-throwing stub for server-only `headers` function.
|
|
180
214
|
*/
|
|
181
215
|
export function headers(): never {
|
|
182
|
-
throw
|
|
216
|
+
throw serverOnlyStubError("headers");
|
|
183
217
|
}
|
|
184
218
|
|
|
185
219
|
/**
|
|
186
220
|
* Error-throwing stub for server-only `createReverse` function.
|
|
187
221
|
*/
|
|
188
222
|
export function createReverse(): never {
|
|
189
|
-
throw
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Error-throwing stub for server-only `enableMatchDebug` function.
|
|
194
|
-
*/
|
|
195
|
-
export function enableMatchDebug(): never {
|
|
196
|
-
throw new Error(
|
|
197
|
-
"enableMatchDebug() is server-only and requires RSC context.",
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Error-throwing stub for server-only `getMatchDebugStats` function.
|
|
203
|
-
*/
|
|
204
|
-
export function getMatchDebugStats(): never {
|
|
205
|
-
throw new Error(
|
|
206
|
-
"getMatchDebugStats() is server-only and requires RSC context.",
|
|
207
|
-
);
|
|
223
|
+
throw serverOnlyStubError("createReverse");
|
|
208
224
|
}
|
|
209
225
|
|
|
210
226
|
// Error-throwing stubs for server-only route helpers
|
|
211
227
|
export function layout(): never {
|
|
212
|
-
throw
|
|
228
|
+
throw serverOnlyStubError("layout");
|
|
213
229
|
}
|
|
214
230
|
export function cache(): never {
|
|
215
|
-
throw
|
|
231
|
+
throw serverOnlyStubError("cache");
|
|
216
232
|
}
|
|
217
233
|
export function middleware(): never {
|
|
218
|
-
throw
|
|
234
|
+
throw serverOnlyStubError("middleware");
|
|
219
235
|
}
|
|
220
236
|
export function revalidate(): never {
|
|
221
|
-
throw
|
|
237
|
+
throw serverOnlyStubError("revalidate");
|
|
222
238
|
}
|
|
223
239
|
export function loader(): never {
|
|
224
|
-
throw
|
|
240
|
+
throw serverOnlyStubError("loader");
|
|
225
241
|
}
|
|
226
242
|
export function loading(): never {
|
|
227
|
-
throw
|
|
243
|
+
throw serverOnlyStubError("loading");
|
|
228
244
|
}
|
|
229
245
|
export function parallel(): never {
|
|
230
|
-
throw
|
|
246
|
+
throw serverOnlyStubError("parallel");
|
|
231
247
|
}
|
|
232
248
|
export function intercept(): never {
|
|
233
|
-
throw
|
|
249
|
+
throw serverOnlyStubError("intercept");
|
|
234
250
|
}
|
|
235
251
|
export function when(): never {
|
|
236
|
-
throw
|
|
252
|
+
throw serverOnlyStubError("when");
|
|
237
253
|
}
|
|
238
254
|
export function errorBoundary(): never {
|
|
239
|
-
throw
|
|
255
|
+
throw serverOnlyStubError("errorBoundary");
|
|
240
256
|
}
|
|
241
257
|
export function notFoundBoundary(): never {
|
|
242
|
-
throw
|
|
243
|
-
"notFoundBoundary() is server-only and requires RSC context.",
|
|
244
|
-
);
|
|
258
|
+
throw serverOnlyStubError("notFoundBoundary");
|
|
245
259
|
}
|
|
246
260
|
export function transition(): never {
|
|
247
|
-
throw
|
|
261
|
+
throw serverOnlyStubError("transition");
|
|
248
262
|
}
|
|
249
263
|
|
|
250
264
|
// Request context type (safe for client)
|
|
251
265
|
export type { PublicRequestContext as RequestContext } from "./server/request-context.js";
|
|
252
266
|
|
|
267
|
+
// Shared base for every user-facing request context.
|
|
268
|
+
export type { RequestScope, ExecutionContext } from "./types/request-scope.js";
|
|
269
|
+
|
|
253
270
|
// Cookie store types (safe for client)
|
|
254
271
|
export type {
|
|
255
272
|
CookieStore,
|
|
@@ -257,17 +274,22 @@ export type {
|
|
|
257
274
|
ReadonlyHeaders,
|
|
258
275
|
} from "./server/cookie-store.js";
|
|
259
276
|
|
|
277
|
+
// Built-in handles (universal — work on both server and client)
|
|
278
|
+
export { Meta } from "./handles/meta.js";
|
|
279
|
+
export { Breadcrumbs } from "./handles/breadcrumbs.js";
|
|
280
|
+
|
|
260
281
|
// Meta types
|
|
261
282
|
export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
|
|
262
283
|
|
|
284
|
+
// Breadcrumb types
|
|
285
|
+
export type { BreadcrumbItem } from "./handles/breadcrumbs.js";
|
|
286
|
+
|
|
263
287
|
// Reverse type utilities for type-safe URL generation (Django-style URL reversal)
|
|
264
288
|
export type {
|
|
265
289
|
ScopedReverseFunction,
|
|
266
290
|
ReverseFunction,
|
|
267
291
|
ExtractLocalRoutes,
|
|
268
292
|
ParamsFor,
|
|
269
|
-
SanitizePrefix,
|
|
270
|
-
MergeRoutes,
|
|
271
293
|
} from "./reverse.js";
|
|
272
294
|
// scopedReverse() helper for handlers to get locally-typed reverse
|
|
273
295
|
export { scopedReverse } from "./reverse.js";
|
|
@@ -287,20 +309,7 @@ export type { PathResponse } from "./href-client.js";
|
|
|
287
309
|
export { createConsoleSink } from "./router/telemetry.js";
|
|
288
310
|
export { createOTelSink } from "./router/telemetry-otel.js";
|
|
289
311
|
export type { OTelTracer, OTelSpan } from "./router/telemetry-otel.js";
|
|
290
|
-
export type {
|
|
291
|
-
TelemetrySink,
|
|
292
|
-
TelemetryEvent,
|
|
293
|
-
RequestStartEvent,
|
|
294
|
-
RequestEndEvent,
|
|
295
|
-
RequestErrorEvent,
|
|
296
|
-
RequestTimeoutEvent,
|
|
297
|
-
LoaderStartEvent,
|
|
298
|
-
LoaderEndEvent,
|
|
299
|
-
LoaderErrorEvent,
|
|
300
|
-
HandlerErrorEvent,
|
|
301
|
-
CacheDecisionEvent,
|
|
302
|
-
RevalidationDecisionEvent,
|
|
303
|
-
} from "./router/telemetry.js";
|
|
312
|
+
export type { TelemetrySink, TelemetryEvent } from "./router/telemetry.js";
|
|
304
313
|
|
|
305
314
|
// Timeout types and error class
|
|
306
315
|
export { RouterTimeoutError } from "./router/timeout.js";
|
package/src/outlet-context.ts
CHANGED
package/src/prerender/store.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Prerender Store
|
|
3
3
|
*
|
|
4
4
|
* Reads pre-rendered segment data from the worker bundle at build time.
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The manifest module is lazily loaded via globalThis.__loadPrerenderManifestModule,
|
|
6
|
+
* a function injected into the RSC entry that returns the manifest module
|
|
7
|
+
* containing a key-to-specifier map and a `loadPrerenderAsset` function
|
|
8
|
+
* that anchors import() resolution relative to the manifest file.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import type {
|
|
@@ -34,11 +35,20 @@ export interface StaticStore {
|
|
|
34
35
|
get(handlerId: string): Promise<StaticEntry | null>;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
interface PrerenderManifestModule {
|
|
39
|
+
default: Record<string, string>;
|
|
40
|
+
loadPrerenderAsset: (
|
|
41
|
+
specifier: string,
|
|
42
|
+
) => Promise<{ default: PrerenderEntry }>;
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
declare global {
|
|
38
|
-
// Injected by closeBundle post-processing:
|
|
46
|
+
// Injected by closeBundle post-processing: lazy loader for the prerender
|
|
47
|
+
// manifest module. The module exports a key→specifier map and a
|
|
48
|
+
// loadPrerenderAsset function that anchors import() relative to the manifest.
|
|
39
49
|
// eslint-disable-next-line no-var
|
|
40
|
-
var
|
|
41
|
-
|
|
|
50
|
+
var __loadPrerenderManifestModule:
|
|
51
|
+
| (() => Promise<PrerenderManifestModule>)
|
|
42
52
|
| undefined;
|
|
43
53
|
// Injected by closeBundle post-processing: map of handlerId -> () => import("./assets/__st-*.js")
|
|
44
54
|
// Asset default export is either a string (no handles) or { encoded, handles } object.
|
|
@@ -78,17 +88,28 @@ export function createDevPrerenderStore(devUrl: string): PrerenderStore {
|
|
|
78
88
|
/**
|
|
79
89
|
* Create a prerender store.
|
|
80
90
|
* Dev mode: on-demand fetch from Vite dev server (node:fs works there).
|
|
81
|
-
* Production: backed by globalThis.
|
|
91
|
+
* Production: backed by globalThis.__loadPrerenderManifestModule which lazily
|
|
92
|
+
* loads the manifest module on first access.
|
|
82
93
|
* Returns null if no prerender data is available.
|
|
83
94
|
*/
|
|
84
95
|
export function createPrerenderStore(): PrerenderStore | null {
|
|
85
96
|
if (globalThis.__PRERENDER_DEV_URL) {
|
|
86
97
|
return createDevPrerenderStore(globalThis.__PRERENDER_DEV_URL);
|
|
87
98
|
}
|
|
88
|
-
|
|
89
|
-
if (!manifest || Object.keys(manifest).length === 0) return null;
|
|
99
|
+
if (!globalThis.__loadPrerenderManifestModule) return null;
|
|
90
100
|
|
|
91
101
|
const cache = new Map<string, Promise<PrerenderEntry | null>>();
|
|
102
|
+
let manifestModulePromise: Promise<PrerenderManifestModule | null> | null =
|
|
103
|
+
null;
|
|
104
|
+
|
|
105
|
+
function loadManifestModule(): Promise<PrerenderManifestModule | null> {
|
|
106
|
+
if (!manifestModulePromise) {
|
|
107
|
+
manifestModulePromise = globalThis.__loadPrerenderManifestModule!().catch(
|
|
108
|
+
() => null,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return manifestModulePromise;
|
|
112
|
+
}
|
|
92
113
|
|
|
93
114
|
return {
|
|
94
115
|
get(routeName: string, paramHash: string): Promise<PrerenderEntry | null> {
|
|
@@ -96,18 +117,39 @@ export function createPrerenderStore(): PrerenderStore | null {
|
|
|
96
117
|
const cached = cache.get(key);
|
|
97
118
|
if (cached) return cached;
|
|
98
119
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
const promise = loadManifestModule().then((mod) => {
|
|
121
|
+
if (!mod) return null;
|
|
122
|
+
const specifier = mod.default[key];
|
|
123
|
+
if (!specifier) return null;
|
|
124
|
+
// Let asset load errors propagate — a missing/corrupted artifact
|
|
125
|
+
// for a key that exists in the manifest is a build/deploy error
|
|
126
|
+
// and should surface as a 500, not be silently swallowed as null
|
|
127
|
+
// (which the handler stub would misreport as a 404).
|
|
128
|
+
return mod.loadPrerenderAsset(specifier).then((asset) => asset.default);
|
|
129
|
+
});
|
|
105
130
|
cache.set(key, promise);
|
|
106
131
|
return promise;
|
|
107
132
|
},
|
|
108
133
|
};
|
|
109
134
|
}
|
|
110
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Load the prerender manifest index for test introspection.
|
|
138
|
+
* Returns the key→specifier map or null if unavailable.
|
|
139
|
+
*/
|
|
140
|
+
export async function loadPrerenderManifestIndex(): Promise<Record<
|
|
141
|
+
string,
|
|
142
|
+
string
|
|
143
|
+
> | null> {
|
|
144
|
+
if (!globalThis.__loadPrerenderManifestModule) return null;
|
|
145
|
+
try {
|
|
146
|
+
const mod = await globalThis.__loadPrerenderManifestModule();
|
|
147
|
+
return mod.default;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
111
153
|
/**
|
|
112
154
|
* Create a static segment store.
|
|
113
155
|
* Production only: backed by globalThis.__STATIC_MANIFEST injected at build time.
|