@rangojs/router 0.0.0-experimental.7 → 0.0.0-experimental.70
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 +55 -33
- 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 +743 -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 +1373 -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 +150 -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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Global namespace (must be imported for side effects: `declare global`)
|
|
2
|
+
export type {
|
|
3
|
+
GetRegisteredRoutes,
|
|
4
|
+
DefaultHandlerRouteMap,
|
|
5
|
+
DefaultReverseRouteMap,
|
|
6
|
+
DefaultEnv,
|
|
7
|
+
} from "./global-namespace.js";
|
|
8
|
+
// Ensure the global namespace declaration is evaluated
|
|
9
|
+
import "./global-namespace.js";
|
|
10
|
+
|
|
11
|
+
// Route configuration
|
|
12
|
+
export type {
|
|
13
|
+
DocumentProps,
|
|
14
|
+
ExtractParams,
|
|
15
|
+
TrailingSlashMode,
|
|
16
|
+
RouteConfig,
|
|
17
|
+
RouteDefinitionOptions,
|
|
18
|
+
RouteDefinition,
|
|
19
|
+
ResolvedRouteMap,
|
|
20
|
+
} from "./route-config.js";
|
|
21
|
+
|
|
22
|
+
// Boundaries (error/notFound)
|
|
23
|
+
export type {
|
|
24
|
+
ErrorInfo,
|
|
25
|
+
ErrorBoundaryFallbackProps,
|
|
26
|
+
ErrorBoundaryHandler,
|
|
27
|
+
ClientErrorBoundaryFallbackProps,
|
|
28
|
+
LoaderDataResult,
|
|
29
|
+
NotFoundInfo,
|
|
30
|
+
NotFoundBoundaryFallbackProps,
|
|
31
|
+
NotFoundBoundaryHandler,
|
|
32
|
+
} from "./boundaries.js";
|
|
33
|
+
export { isLoaderDataResult } from "./boundaries.js";
|
|
34
|
+
|
|
35
|
+
// Handler context and related types
|
|
36
|
+
export type {
|
|
37
|
+
MiddlewareFn,
|
|
38
|
+
ScopedRouteMap,
|
|
39
|
+
Handler,
|
|
40
|
+
HandlerContext,
|
|
41
|
+
InternalHandlerContext,
|
|
42
|
+
GenericParams,
|
|
43
|
+
RevalidateParams,
|
|
44
|
+
ShouldRevalidateFn,
|
|
45
|
+
RouteKeys,
|
|
46
|
+
ExtractRouteParams,
|
|
47
|
+
HandlersForRouteMap,
|
|
48
|
+
Revalidate,
|
|
49
|
+
Middleware,
|
|
50
|
+
} from "./handler-context.js";
|
|
51
|
+
|
|
52
|
+
// Segments
|
|
53
|
+
export type {
|
|
54
|
+
ViewTransitionClass,
|
|
55
|
+
TransitionConfig,
|
|
56
|
+
ResolvedSegment,
|
|
57
|
+
SegmentMetadata,
|
|
58
|
+
SlotState,
|
|
59
|
+
RootLayoutProps,
|
|
60
|
+
MatchResult,
|
|
61
|
+
} from "./segments.js";
|
|
62
|
+
|
|
63
|
+
// Route entries
|
|
64
|
+
export type { LazyIncludeContext, RouteEntry } from "./route-entry.js";
|
|
65
|
+
|
|
66
|
+
// Loader types
|
|
67
|
+
export type {
|
|
68
|
+
LoaderContext,
|
|
69
|
+
LoaderFn,
|
|
70
|
+
FetchableLoaderOptions,
|
|
71
|
+
LoadOptions,
|
|
72
|
+
LoaderDefinition,
|
|
73
|
+
} from "./loader-types.js";
|
|
74
|
+
|
|
75
|
+
// Cache types
|
|
76
|
+
export type {
|
|
77
|
+
CacheContext,
|
|
78
|
+
CacheOptions,
|
|
79
|
+
PartialCacheOptions,
|
|
80
|
+
EntryCacheConfig,
|
|
81
|
+
} from "./cache-types.js";
|
|
82
|
+
|
|
83
|
+
// Error handling types
|
|
84
|
+
export type {
|
|
85
|
+
ErrorPhase,
|
|
86
|
+
OnErrorContext,
|
|
87
|
+
OnErrorCallback,
|
|
88
|
+
} from "./error-types.js";
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { ContextVar } from "../context-var.js";
|
|
2
|
+
import type { Handle } from "../handle.js";
|
|
3
|
+
import type { MiddlewareFn } from "../router/middleware.js";
|
|
4
|
+
import type { ScopedReverseFunction } from "../reverse.js";
|
|
5
|
+
import type { SearchSchema, ResolveSearchSchema } from "../search-params.js";
|
|
6
|
+
import type {
|
|
7
|
+
DefaultEnv,
|
|
8
|
+
DefaultReverseRouteMap,
|
|
9
|
+
DefaultVars,
|
|
10
|
+
} from "./global-namespace.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Context passed to loader functions during execution
|
|
14
|
+
*
|
|
15
|
+
* Loaders run after middleware but before handlers, so they have access
|
|
16
|
+
* to middleware-set variables via get().
|
|
17
|
+
*
|
|
18
|
+
* @template TParams - Route params type (e.g., { slug: string })
|
|
19
|
+
* @template TEnv - Environment type for bindings/variables
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const CartLoader = createLoader(async (ctx) => {
|
|
24
|
+
* "use server";
|
|
25
|
+
* const user = ctx.get("user"); // From auth middleware
|
|
26
|
+
* return await db.cart.get(user.id);
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // With typed params:
|
|
30
|
+
* const ProductLoader = createLoader<Product, { slug: string }>(async (ctx) => {
|
|
31
|
+
* "use server";
|
|
32
|
+
* const { slug } = ctx.params; // slug is typed as string
|
|
33
|
+
* return await db.products.findBySlug(slug);
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export type LoaderContext<
|
|
38
|
+
TParams = Record<string, string | undefined>,
|
|
39
|
+
TEnv = DefaultEnv,
|
|
40
|
+
TBody = unknown,
|
|
41
|
+
TSearch extends SearchSchema = {},
|
|
42
|
+
> = {
|
|
43
|
+
params: TParams;
|
|
44
|
+
/**
|
|
45
|
+
* Route params extracted from the URL pattern match (server-side only).
|
|
46
|
+
* Unlike `params`, these cannot be overridden by client-provided loader params.
|
|
47
|
+
* Use this when you need trusted, server-matched route params for auth or
|
|
48
|
+
* resource scoping.
|
|
49
|
+
*/
|
|
50
|
+
routeParams: Record<string, string>;
|
|
51
|
+
request: Request;
|
|
52
|
+
searchParams: URLSearchParams;
|
|
53
|
+
search: {} extends TSearch ? {} : ResolveSearchSchema<TSearch>;
|
|
54
|
+
pathname: string;
|
|
55
|
+
url: URL;
|
|
56
|
+
env: TEnv;
|
|
57
|
+
get: {
|
|
58
|
+
<T>(contextVar: ContextVar<T>): T | undefined;
|
|
59
|
+
} & (<K extends keyof DefaultVars>(key: K) => DefaultVars[K]);
|
|
60
|
+
/**
|
|
61
|
+
* Access another loader's data, or read handle data after rendered().
|
|
62
|
+
*
|
|
63
|
+
* For loaders: returns a promise (loaders run in parallel).
|
|
64
|
+
* For handles: returns collected data (only after `await ctx.rendered()`).
|
|
65
|
+
*/
|
|
66
|
+
use: {
|
|
67
|
+
<T, TLoaderParams = any>(
|
|
68
|
+
loader: LoaderDefinition<T, TLoaderParams>,
|
|
69
|
+
): Promise<T>;
|
|
70
|
+
<TData, TAccumulated = TData[]>(
|
|
71
|
+
handle: Handle<TData, TAccumulated>,
|
|
72
|
+
): TAccumulated;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* **Experimental.** Wait for all non-loader segments to settle.
|
|
76
|
+
*
|
|
77
|
+
* After the returned promise resolves, handle data is available via
|
|
78
|
+
* `ctx.use(handle)`. Only supported in DSL loaders on non-streaming
|
|
79
|
+
* trees (no `loading()`). Throws if called from a handler-invoked
|
|
80
|
+
* loader or when the tree uses streaming.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const PricesLoader = createLoader(async (ctx) => {
|
|
85
|
+
* "use server";
|
|
86
|
+
* await ctx.rendered();
|
|
87
|
+
* const products = ctx.use(Products); // reads handle data
|
|
88
|
+
* return pricing.getLive(products.map(p => p.id));
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
rendered: () => Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* HTTP method (GET, POST, PUT, PATCH, DELETE)
|
|
95
|
+
* Available when loader is called via load({ method: "POST", ... })
|
|
96
|
+
*/
|
|
97
|
+
method: string;
|
|
98
|
+
/**
|
|
99
|
+
* Request body for POST/PUT/PATCH/DELETE requests
|
|
100
|
+
* Available when loader is called via load({ method: "POST", body: {...} })
|
|
101
|
+
*/
|
|
102
|
+
body: TBody | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Form data when loader is invoked via action (fetchable loaders)
|
|
105
|
+
* Available when loader is called via form submission
|
|
106
|
+
*/
|
|
107
|
+
formData?: FormData;
|
|
108
|
+
/**
|
|
109
|
+
* Generate URLs from route names.
|
|
110
|
+
* Same scoped reverse as route handlers — `.name` resolves within the
|
|
111
|
+
* current include() scope, `name` resolves globally.
|
|
112
|
+
*/
|
|
113
|
+
reverse: ScopedReverseFunction<
|
|
114
|
+
Record<string, string>,
|
|
115
|
+
DefaultReverseRouteMap
|
|
116
|
+
>;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Loader function signature
|
|
121
|
+
*
|
|
122
|
+
* @template T - The return type of the loader
|
|
123
|
+
* @template TParams - Route params type (defaults to generic Record)
|
|
124
|
+
* @template TEnv - Environment type for bindings/variables
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const myLoader: LoaderFn<{ items: Item[] }> = async (ctx) => {
|
|
129
|
+
* "use server";
|
|
130
|
+
* return { items: await db.items.list() };
|
|
131
|
+
* };
|
|
132
|
+
*
|
|
133
|
+
* // With typed params:
|
|
134
|
+
* const productLoader: LoaderFn<Product, { slug: string }> = async (ctx) => {
|
|
135
|
+
* "use server";
|
|
136
|
+
* const { slug } = ctx.params; // typed as string
|
|
137
|
+
* return await db.products.findBySlug(slug);
|
|
138
|
+
* };
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export type LoaderFn<
|
|
142
|
+
T,
|
|
143
|
+
TParams = Record<string, string | undefined>,
|
|
144
|
+
TEnv = DefaultEnv,
|
|
145
|
+
> = (ctx: LoaderContext<TParams, TEnv>) => Promise<T> | T;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Options for fetchable loaders
|
|
149
|
+
*
|
|
150
|
+
* Middleware uses the same MiddlewareFn signature as route/app middleware,
|
|
151
|
+
* enabling reuse of the same middleware functions everywhere.
|
|
152
|
+
*/
|
|
153
|
+
export type FetchableLoaderOptions = {
|
|
154
|
+
fetchable?: true;
|
|
155
|
+
middleware?: MiddlewareFn[];
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Options for load() calls - type-safe union based on method
|
|
160
|
+
*/
|
|
161
|
+
export type LoadOptions =
|
|
162
|
+
| {
|
|
163
|
+
method?: "GET";
|
|
164
|
+
params?: Record<string, string>;
|
|
165
|
+
}
|
|
166
|
+
| {
|
|
167
|
+
method: "POST" | "PUT" | "PATCH" | "DELETE";
|
|
168
|
+
params?: Record<string, string>;
|
|
169
|
+
body?: FormData | Record<string, any>;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Loader definition object
|
|
174
|
+
*
|
|
175
|
+
* Created via createLoader(). Contains the loader name and function.
|
|
176
|
+
* On client builds, the fn is stripped by the bundler (via "use server" directive).
|
|
177
|
+
*
|
|
178
|
+
* @template T - The return type of the loader
|
|
179
|
+
* @template TParams - Route params type (for type-safe params access)
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* // Definition (same file works on server and client)
|
|
184
|
+
* export const CartLoader = createLoader(async (ctx) => {
|
|
185
|
+
* "use server";
|
|
186
|
+
* return await db.cart.get(ctx.get("user").id);
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* // With typed params:
|
|
190
|
+
* export const ProductLoader = createLoader<Product, { slug: string }>(async (ctx) => {
|
|
191
|
+
* "use server";
|
|
192
|
+
* const { slug } = ctx.params; // slug is typed as string
|
|
193
|
+
* return await db.products.findBySlug(slug);
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* // Client usage (preferred — cache-safe, always fresh)
|
|
197
|
+
* const { data } = useLoader(CartLoader);
|
|
198
|
+
*
|
|
199
|
+
* // Server escape hatch (handler needs data directly)
|
|
200
|
+
* const cart = await ctx.use(CartLoader);
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export type LoaderDefinition<
|
|
204
|
+
T = any,
|
|
205
|
+
TParams = Record<string, string | undefined>,
|
|
206
|
+
> = {
|
|
207
|
+
__brand: "loader";
|
|
208
|
+
$$id: string; // Injected by Vite plugin (exposeInternalIds) - unique identifier
|
|
209
|
+
fn?: LoaderFn<T, TParams, any>; // Optional - server-side only, stored in registry for RSC
|
|
210
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the Document component that wraps the entire application.
|
|
5
|
+
*/
|
|
6
|
+
export type DocumentProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse constraint values into a union type
|
|
12
|
+
* "a|b|c" -> "a" | "b" | "c"
|
|
13
|
+
*/
|
|
14
|
+
type ParseConstraint<T extends string> =
|
|
15
|
+
T extends `${infer First}|${infer Rest}` ? First | ParseConstraint<Rest> : T;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extract param info from a param segment
|
|
19
|
+
*
|
|
20
|
+
* Handles:
|
|
21
|
+
* - :param -> { name: "param", optional: false, type: string }
|
|
22
|
+
* - :param? -> { name: "param", optional: true, type: string }
|
|
23
|
+
* - :param(a|b) -> { name: "param", optional: false, type: "a" | "b" }
|
|
24
|
+
* - :param(a|b)? -> { name: "param", optional: true, type: "a" | "b" }
|
|
25
|
+
*/
|
|
26
|
+
type ExtractParamInfo<T extends string> =
|
|
27
|
+
// Optional + constrained (with optional suffix): :param(a|b)?suffix
|
|
28
|
+
T extends `${infer Name}(${infer Constraint})?${string}`
|
|
29
|
+
? { name: Name; optional: true; type: ParseConstraint<Constraint> }
|
|
30
|
+
: // Constrained (with optional suffix): :param(a|b)suffix
|
|
31
|
+
T extends `${infer Name}(${infer Constraint})${string}`
|
|
32
|
+
? { name: Name; optional: false; type: ParseConstraint<Constraint> }
|
|
33
|
+
: // Optional (with optional suffix): :param?suffix
|
|
34
|
+
T extends `${infer Name}?${string}`
|
|
35
|
+
? { name: Name; optional: true; type: string }
|
|
36
|
+
: // Param with dot-suffix: :param.html
|
|
37
|
+
T extends `${infer Name}.${string}`
|
|
38
|
+
? { name: Name; optional: false; type: string }
|
|
39
|
+
: // Param with dash-suffix: :param-slug
|
|
40
|
+
T extends `${infer Name}-${string}`
|
|
41
|
+
? { name: Name; optional: false; type: string }
|
|
42
|
+
: // Param with tilde-suffix: :param~v2
|
|
43
|
+
T extends `${infer Name}~${string}`
|
|
44
|
+
? { name: Name; optional: false; type: string }
|
|
45
|
+
: // Required: :param (no suffix)
|
|
46
|
+
{ name: T; optional: false; type: string };
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Build param object from info
|
|
50
|
+
*/
|
|
51
|
+
type ParamFromInfo<Info> = Info extends {
|
|
52
|
+
name: infer N extends string;
|
|
53
|
+
optional: true;
|
|
54
|
+
type: infer V;
|
|
55
|
+
}
|
|
56
|
+
? { [K in N]?: V }
|
|
57
|
+
: Info extends {
|
|
58
|
+
name: infer N extends string;
|
|
59
|
+
optional: false;
|
|
60
|
+
type: infer V;
|
|
61
|
+
}
|
|
62
|
+
? { [K in N]: V }
|
|
63
|
+
: never;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Merge two param objects preserving optionality
|
|
67
|
+
* Uses Pick to preserve the modifiers from source types
|
|
68
|
+
*/
|
|
69
|
+
type MergeParams<A, B> = Pick<A, keyof A> & Pick<B, keyof B> extends infer O
|
|
70
|
+
? { [K in keyof O]: O[K] }
|
|
71
|
+
: never;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Extract route params from a pattern with depth limit to prevent infinite recursion
|
|
75
|
+
*
|
|
76
|
+
* Supports:
|
|
77
|
+
* - Required params: /:slug -> { slug: string }
|
|
78
|
+
* - Optional params: /:locale? -> { locale?: string }
|
|
79
|
+
* - Constrained params: /:locale(en|gb) -> { locale: "en" | "gb" }
|
|
80
|
+
* - Optional + constrained: /:locale(en|gb)? -> { locale?: "en" | "gb" }
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ExtractParams<"/products/:id"> // { id: string }
|
|
84
|
+
* ExtractParams<"/:locale?/blog/:slug"> // { locale?: string; slug: string }
|
|
85
|
+
* ExtractParams<"/:locale(en|gb)/blog"> // { locale: "en" | "gb" }
|
|
86
|
+
* ExtractParams<"/:locale(en|gb)?/blog/:slug"> // { locale?: "en" | "gb"; slug: string }
|
|
87
|
+
*/
|
|
88
|
+
export type ExtractParams<
|
|
89
|
+
T extends string,
|
|
90
|
+
Depth extends readonly unknown[] = [],
|
|
91
|
+
> = Depth["length"] extends 10
|
|
92
|
+
? { [key: string]: string | undefined } // Fallback to generic params if too deep
|
|
93
|
+
: // Match param with remaining path: :param.../rest
|
|
94
|
+
T extends `${infer _Start}:${infer Param}/${infer Rest}`
|
|
95
|
+
? MergeParams<
|
|
96
|
+
ParamFromInfo<ExtractParamInfo<Param>>,
|
|
97
|
+
ExtractParams<`/${Rest}`, readonly [...Depth, unknown]>
|
|
98
|
+
>
|
|
99
|
+
: // Match param at end: :param...
|
|
100
|
+
T extends `${infer _Start}:${infer Param}`
|
|
101
|
+
? ParamFromInfo<ExtractParamInfo<Param>>
|
|
102
|
+
: {};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Trailing slash handling mode
|
|
106
|
+
* - "never": Redirect URLs with trailing slash to without
|
|
107
|
+
* - "always": Redirect URLs without trailing slash to with
|
|
108
|
+
* - "ignore": Match both with and without trailing slash
|
|
109
|
+
*/
|
|
110
|
+
export type TrailingSlashMode = "never" | "always" | "ignore";
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Route configuration object (alternative to string path)
|
|
114
|
+
*/
|
|
115
|
+
export type RouteConfig = {
|
|
116
|
+
path: string;
|
|
117
|
+
trailingSlash?: TrailingSlashMode;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Route definition options (global defaults)
|
|
122
|
+
*/
|
|
123
|
+
export type RouteDefinitionOptions = {
|
|
124
|
+
trailingSlash?: TrailingSlashMode;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type RouteDefinition = {
|
|
128
|
+
[key: string]: string | RouteConfig | RouteDefinition;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Recursively flatten nested routes with depth limit to prevent infinite recursion
|
|
133
|
+
* Transforms: { products: { detail: "/product/:slug" } } => { "products.detail": "/product/:slug" }
|
|
134
|
+
* Also handles RouteConfig objects: { api: { path: "/api" } } => { "api": "/api" }
|
|
135
|
+
*/
|
|
136
|
+
type FlattenRoutes<
|
|
137
|
+
T extends RouteDefinition,
|
|
138
|
+
Prefix extends string = "",
|
|
139
|
+
Depth extends readonly unknown[] = [],
|
|
140
|
+
> = Depth["length"] extends 5
|
|
141
|
+
? never
|
|
142
|
+
: {
|
|
143
|
+
[K in keyof T]: T[K] extends string
|
|
144
|
+
? Record<`${Prefix}${K & string}`, T[K]>
|
|
145
|
+
: T[K] extends RouteConfig
|
|
146
|
+
? Record<`${Prefix}${K & string}`, T[K]["path"]>
|
|
147
|
+
: T[K] extends RouteDefinition
|
|
148
|
+
? FlattenRoutes<
|
|
149
|
+
T[K],
|
|
150
|
+
`${Prefix}${K & string}.`,
|
|
151
|
+
readonly [...Depth, unknown]
|
|
152
|
+
>
|
|
153
|
+
: never;
|
|
154
|
+
}[keyof T];
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Union to intersection helper
|
|
158
|
+
*/
|
|
159
|
+
type UnionToIntersection<U> = (
|
|
160
|
+
U extends unknown ? (k: U) => void : never
|
|
161
|
+
) extends (k: infer I) => void
|
|
162
|
+
? I
|
|
163
|
+
: never;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Resolved route map - flattened route definitions with full paths
|
|
167
|
+
*/
|
|
168
|
+
export type ResolvedRouteMap<T extends RouteDefinition> = UnionToIntersection<
|
|
169
|
+
FlattenRoutes<T>
|
|
170
|
+
>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { AllUseItems } from "../route-types.js";
|
|
2
|
+
import type { TrailingSlashMode, ResolvedRouteMap } from "./route-config.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Context captured for lazy include evaluation
|
|
6
|
+
*/
|
|
7
|
+
export interface LazyIncludeContext {
|
|
8
|
+
urlPrefix: string;
|
|
9
|
+
namePrefix: string | undefined;
|
|
10
|
+
parent: unknown; // EntryData - avoid circular import
|
|
11
|
+
cacheProfiles?: Record<
|
|
12
|
+
string,
|
|
13
|
+
import("../cache/profile-registry.js").CacheProfile
|
|
14
|
+
>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal route entry stored in router
|
|
19
|
+
*/
|
|
20
|
+
export interface RouteEntry<TEnv = any> {
|
|
21
|
+
prefix: string;
|
|
22
|
+
/**
|
|
23
|
+
* Pre-computed static prefix for fast short-circuit matching.
|
|
24
|
+
* Extracted from prefix at registration time (everything before first param).
|
|
25
|
+
*
|
|
26
|
+
* Examples:
|
|
27
|
+
* - "/api" -> staticPrefix = "/api"
|
|
28
|
+
* - "/site/:locale" -> staticPrefix = "/site"
|
|
29
|
+
* - "/:locale" -> staticPrefix = "" (empty, can't optimize)
|
|
30
|
+
*
|
|
31
|
+
* At runtime: if staticPrefix && !pathname.startsWith(staticPrefix), skip entry.
|
|
32
|
+
*/
|
|
33
|
+
staticPrefix: string;
|
|
34
|
+
/**
|
|
35
|
+
* Route patterns map. For lazy entries, this starts as empty and is
|
|
36
|
+
* populated on first request.
|
|
37
|
+
*/
|
|
38
|
+
routes: ResolvedRouteMap<any>;
|
|
39
|
+
/**
|
|
40
|
+
* Trailing slash config per route key
|
|
41
|
+
* If not specified for a route, defaults to pattern-based detection
|
|
42
|
+
*/
|
|
43
|
+
trailingSlash?: Record<string, TrailingSlashMode>;
|
|
44
|
+
/**
|
|
45
|
+
* Supported handler shapes:
|
|
46
|
+
* - sync: () => Array<AllUseItems>
|
|
47
|
+
* - lazy import: () => Promise<{ default: () => Array<AllUseItems> }>
|
|
48
|
+
* - lazy function: () => Promise<() => Array<AllUseItems>>
|
|
49
|
+
*
|
|
50
|
+
* Direct Promise<Array> is NOT supported and rejected at runtime.
|
|
51
|
+
*/
|
|
52
|
+
handler: () =>
|
|
53
|
+
| Array<AllUseItems>
|
|
54
|
+
| Promise<{ default: () => Array<AllUseItems> }>
|
|
55
|
+
| Promise<() => Array<AllUseItems>>;
|
|
56
|
+
mountIndex: number;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Router ID that owns this entry. Used to namespace the manifest cache
|
|
60
|
+
* so multi-router setups (host routing) don't share cached EntryData
|
|
61
|
+
* across routers with overlapping mountIndex + routeKey combinations.
|
|
62
|
+
*/
|
|
63
|
+
routerId?: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Route keys in this entry that have pre-render handlers.
|
|
67
|
+
* Used by the non-trie match path to set the `pr` flag.
|
|
68
|
+
*/
|
|
69
|
+
prerenderRouteKeys?: Set<string>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Route keys in this entry that are wrapped with `Passthrough()`.
|
|
73
|
+
* Used by the non-trie match path to set the `pt` flag.
|
|
74
|
+
*/
|
|
75
|
+
passthroughRouteKeys?: Set<string>;
|
|
76
|
+
|
|
77
|
+
// === Lazy evaluation fields ===
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether this entry is lazily evaluated.
|
|
81
|
+
* When true, routes are populated on first matching request.
|
|
82
|
+
*/
|
|
83
|
+
lazy?: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* For lazy entries: the UrlPatterns to evaluate
|
|
87
|
+
*/
|
|
88
|
+
lazyPatterns?: unknown;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* For lazy entries: captured context at definition time
|
|
92
|
+
*/
|
|
93
|
+
lazyContext?: LazyIncludeContext;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* For lazy entries: whether patterns have been evaluated
|
|
97
|
+
*/
|
|
98
|
+
lazyEvaluated?: boolean;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Cache profiles for DSL-time cache("profileName") resolution.
|
|
102
|
+
* Set on all entries (lazy and non-lazy) so loadManifest() can
|
|
103
|
+
* propagate them into the HelperContext Store.
|
|
104
|
+
*/
|
|
105
|
+
cacheProfiles?: Record<
|
|
106
|
+
string,
|
|
107
|
+
import("../cache/profile-registry.js").CacheProfile
|
|
108
|
+
>;
|
|
109
|
+
}
|