@rangojs/router 0.0.0-experimental.002d056c
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 +899 -0
- package/dist/bin/rango.js +1606 -0
- package/dist/vite/index.js +5153 -0
- package/package.json +177 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +253 -0
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +182 -0
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +704 -0
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +313 -0
- package/skills/layout/SKILL.md +310 -0
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +596 -0
- package/skills/middleware/SKILL.md +339 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +305 -0
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +118 -0
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +385 -0
- package/skills/router-setup/SKILL.md +439 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +79 -0
- package/skills/typesafety/SKILL.md +623 -0
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +273 -0
- 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/event-controller.ts +899 -0
- package/src/browser/history-state.ts +80 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +141 -0
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +134 -0
- package/src/browser/navigation-bridge.ts +638 -0
- package/src/browser/navigation-client.ts +261 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +582 -0
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +145 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +368 -0
- package/src/browser/react/NavigationProvider.tsx +413 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +59 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +162 -0
- package/src/browser/react/location-state.ts +107 -0
- package/src/browser/react/mount-context.ts +37 -0
- 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 +218 -0
- package/src/browser/react/use-client-cache.ts +58 -0
- package/src/browser/react/use-handle.ts +162 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +135 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +99 -0
- 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 +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +171 -0
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +464 -0
- package/src/browser/scroll-restoration.ts +397 -0
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +667 -0
- package/src/browser/shallow.ts +40 -0
- package/src/browser/types.ts +547 -0
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -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 +411 -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 +479 -0
- package/src/build/route-types/scan-filter.ts +78 -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 +338 -0
- package/src/cache/cache-scope.ts +382 -0
- package/src/cache/cf/cf-cache-store.ts +982 -0
- package/src/cache/cf/index.ts +29 -0
- package/src/cache/document-cache.ts +369 -0
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +44 -0
- package/src/cache/memory-segment-store.ts +328 -0
- 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 +98 -0
- package/src/cache/types.ts +342 -0
- package/src/client.rsc.tsx +85 -0
- package/src/client.tsx +601 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +27 -0
- package/src/context-var.ts +86 -0
- package/src/debug.ts +243 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +365 -0
- package/src/handle.ts +135 -0
- package/src/handles/MetaTags.tsx +246 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +7 -0
- package/src/handles/meta.ts +264 -0
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +222 -0
- package/src/index.rsc.ts +233 -0
- package/src/index.ts +277 -0
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +89 -0
- package/src/loader.ts +64 -0
- package/src/network-error-thrower.tsx +23 -0
- package/src/outlet-context.ts +15 -0
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +289 -0
- package/src/route-content-wrapper.tsx +196 -0
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -0
- package/src/route-map-builder.ts +281 -0
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +259 -0
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +397 -0
- package/src/router/lazy-includes.ts +236 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +269 -0
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +266 -0
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +223 -0
- package/src/router/match-middleware/cache-lookup.ts +634 -0
- package/src/router/match-middleware/cache-store.ts +295 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +306 -0
- package/src/router/match-middleware/segment-resolution.ts +193 -0
- package/src/router/match-pipelines.ts +179 -0
- package/src/router/match-result.ts +219 -0
- package/src/router/metrics.ts +282 -0
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +749 -0
- package/src/router/pattern-matching.ts +563 -0
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +289 -0
- package/src/router/router-context.ts +320 -0
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1242 -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 +170 -0
- package/src/router.ts +1006 -0
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +1089 -0
- package/src/rsc/helpers.ts +198 -0
- package/src/rsc/index.ts +36 -0
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +32 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +237 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +263 -0
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +454 -0
- package/src/server/context.ts +591 -0
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +308 -0
- package/src/server/loader-registry.ts +133 -0
- package/src/server/request-context.ts +920 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +51 -0
- package/src/ssr/index.tsx +365 -0
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +297 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +62 -0
- package/src/theme/index.ts +48 -0
- package/src/theme/theme-context.ts +44 -0
- package/src/theme/theme-script.ts +155 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- 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 +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +109 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -0
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -0
- package/src/use-loader.tsx +354 -0
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -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 +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +16 -0
- package/src/vite/plugin-types.ts +48 -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/plugins/expose-action-id.ts +363 -0
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -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 +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -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/plugins/version.d.ts +12 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -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/utils/package-resolution.ts +121 -0
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component utilities for RSC
|
|
3
|
+
*
|
|
4
|
+
* Helpers for working with React Server Components and client components.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ComponentType } from "react";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Symbol used by React to mark client component references.
|
|
11
|
+
* When a file has "use client" directive, the bundler transforms the exports
|
|
12
|
+
* to include this symbol on $$typeof.
|
|
13
|
+
*/
|
|
14
|
+
const CLIENT_REFERENCE = Symbol.for("react.client.reference");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Check if a component is a client component (has "use client" directive).
|
|
18
|
+
*
|
|
19
|
+
* Client components are marked by the bundler with:
|
|
20
|
+
* - $$typeof: Symbol.for("react.client.reference")
|
|
21
|
+
* - $$id: string (module identifier)
|
|
22
|
+
*
|
|
23
|
+
* @param component - The component to check
|
|
24
|
+
* @returns true if the component has client reference marker
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { MyComponent } from "./my-component"; // has "use client"
|
|
29
|
+
*
|
|
30
|
+
* if (!isClientComponent(MyComponent)) {
|
|
31
|
+
* throw new Error("MyComponent must be a client component");
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function isClientComponent(
|
|
36
|
+
component: ComponentType<unknown> | unknown,
|
|
37
|
+
): boolean {
|
|
38
|
+
if (typeof component !== "function") {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const withMeta = component as { $$typeof?: symbol };
|
|
42
|
+
return withMeta.$$typeof === CLIENT_REFERENCE;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Assert that a component is a client component.
|
|
47
|
+
* Throws a descriptive error if not.
|
|
48
|
+
*
|
|
49
|
+
* @param component - The component to check
|
|
50
|
+
* @param name - Name to use in error message (e.g., "document")
|
|
51
|
+
* @throws Error if the component is not a client component
|
|
52
|
+
*/
|
|
53
|
+
export function assertClientComponent(
|
|
54
|
+
component: ComponentType<unknown> | unknown,
|
|
55
|
+
name: string,
|
|
56
|
+
): asserts component is ComponentType<unknown> {
|
|
57
|
+
if (typeof component !== "function") {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`${name} must be a client component function with "use client" directive. ` +
|
|
60
|
+
`Make sure to pass the component itself, not a JSX element: ` +
|
|
61
|
+
`${name}: My${capitalize(name)} (correct) vs ${name}: <My${capitalize(name)} /> (incorrect)`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!isClientComponent(component)) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`${name} must be a client component with "use client" directive at the top of the file. ` +
|
|
68
|
+
`Server components cannot be used as the ${name} because their function reference ` +
|
|
69
|
+
`cannot be serialized in the RSC payload. Add "use client" to your ${name} file.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function capitalize(str: string): string {
|
|
75
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
76
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode, ReactElement } from "react";
|
|
4
|
+
import { MetaTags } from "../handles/MetaTags.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default document component that provides a basic HTML structure.
|
|
8
|
+
* Used when no custom document is provided to createRouter.
|
|
9
|
+
* Includes MetaTags for automatic charset, viewport, and route meta support.
|
|
10
|
+
*
|
|
11
|
+
* Uses suppressHydrationWarning on <html> because the theme script
|
|
12
|
+
* may modify class/style attributes before React hydrates.
|
|
13
|
+
*/
|
|
14
|
+
export function DefaultDocument({
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}): ReactElement {
|
|
19
|
+
return (
|
|
20
|
+
<html lang="en" suppressHydrationWarning>
|
|
21
|
+
<head>
|
|
22
|
+
<MetaTags />
|
|
23
|
+
</head>
|
|
24
|
+
<body>{children}</body>
|
|
25
|
+
</html>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed context variables for ctx.set() / ctx.get().
|
|
3
|
+
*
|
|
4
|
+
* createVar<T>() produces a typed token that handlers set and layouts/middleware
|
|
5
|
+
* read. The token carries a unique Symbol used as the property key on the
|
|
6
|
+
* per-request variables object — no build-time processing, no IDs.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createVar } from "@rangojs/router";
|
|
11
|
+
*
|
|
12
|
+
* interface PaginationData { current: number; total: number }
|
|
13
|
+
* export const Pagination = createVar<PaginationData>();
|
|
14
|
+
*
|
|
15
|
+
* // handler
|
|
16
|
+
* ctx.set(Pagination, { current: 1, total: 4 });
|
|
17
|
+
*
|
|
18
|
+
* // layout
|
|
19
|
+
* const pg = ctx.get(Pagination); // PaginationData | undefined
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export interface ContextVar<T> {
|
|
24
|
+
readonly __brand: "context-var";
|
|
25
|
+
readonly key: symbol;
|
|
26
|
+
/** Phantom field to carry the type parameter. Never set at runtime. */
|
|
27
|
+
readonly __type?: T;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a typed context variable token.
|
|
32
|
+
*
|
|
33
|
+
* The returned object is used with ctx.set(token, value) and ctx.get(token)
|
|
34
|
+
* for compile-time-checked data flow between handlers, layouts, and middleware.
|
|
35
|
+
*/
|
|
36
|
+
export function createVar<T>(): ContextVar<T> {
|
|
37
|
+
return { __brand: "context-var" as const, key: Symbol() };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Type guard: is the value a ContextVar token?
|
|
42
|
+
*/
|
|
43
|
+
export function isContextVar(value: unknown): value is ContextVar<unknown> {
|
|
44
|
+
return (
|
|
45
|
+
typeof value === "object" &&
|
|
46
|
+
value !== null &&
|
|
47
|
+
"__brand" in value &&
|
|
48
|
+
(value as { __brand: unknown }).__brand === "context-var"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Read a variable from the variables store.
|
|
54
|
+
* Accepts either a string key (legacy) or a ContextVar token (typed).
|
|
55
|
+
*/
|
|
56
|
+
export function contextGet(
|
|
57
|
+
variables: any,
|
|
58
|
+
keyOrVar: string | ContextVar<any>,
|
|
59
|
+
): any {
|
|
60
|
+
if (typeof keyOrVar === "string") return variables[keyOrVar];
|
|
61
|
+
return variables[keyOrVar.key];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Keys that must never be used as string variable names */
|
|
65
|
+
const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Write a variable to the variables store.
|
|
69
|
+
* Accepts either a string key (legacy) or a ContextVar token (typed).
|
|
70
|
+
*/
|
|
71
|
+
export function contextSet(
|
|
72
|
+
variables: any,
|
|
73
|
+
keyOrVar: string | ContextVar<any>,
|
|
74
|
+
value: any,
|
|
75
|
+
): void {
|
|
76
|
+
if (typeof keyOrVar === "string") {
|
|
77
|
+
if (FORBIDDEN_KEYS.has(keyOrVar)) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`ctx.set(): "${keyOrVar}" is a reserved key and cannot be used as a variable name.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
variables[keyOrVar] = value;
|
|
83
|
+
} else {
|
|
84
|
+
variables[keyOrVar.key] = value;
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/debug.ts
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug utilities for manifest inspection and comparison
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { EntryData } from "./server/context";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Serialized entry for debug output
|
|
9
|
+
*/
|
|
10
|
+
export interface SerializedEntry {
|
|
11
|
+
id: string;
|
|
12
|
+
shortCode: string;
|
|
13
|
+
type: string;
|
|
14
|
+
parentShortCode: string | null;
|
|
15
|
+
pattern?: string;
|
|
16
|
+
hasLoader: boolean;
|
|
17
|
+
hasMiddleware: boolean;
|
|
18
|
+
hasErrorBoundary: boolean;
|
|
19
|
+
parallelCount: number;
|
|
20
|
+
interceptCount: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Serialized manifest structure
|
|
25
|
+
*/
|
|
26
|
+
export interface SerializedManifest {
|
|
27
|
+
routes: Record<string, SerializedEntry>;
|
|
28
|
+
layouts: Record<string, SerializedEntry>;
|
|
29
|
+
totalRoutes: number;
|
|
30
|
+
totalLayouts: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Serialize a manifest Map into a JSON-friendly structure
|
|
35
|
+
*/
|
|
36
|
+
export function serializeManifest(
|
|
37
|
+
manifest: Map<string, EntryData>,
|
|
38
|
+
): SerializedManifest {
|
|
39
|
+
const routes: Record<string, SerializedEntry> = {};
|
|
40
|
+
const layouts: Record<string, SerializedEntry> = {};
|
|
41
|
+
|
|
42
|
+
// Collect all entries including parents
|
|
43
|
+
const allEntries = new Map<string, EntryData>();
|
|
44
|
+
|
|
45
|
+
for (const [key, entry] of manifest.entries()) {
|
|
46
|
+
allEntries.set(key, entry);
|
|
47
|
+
|
|
48
|
+
// Walk up parent chain to collect all layouts
|
|
49
|
+
let parent = entry.parent;
|
|
50
|
+
while (parent) {
|
|
51
|
+
if (!allEntries.has(parent.id)) {
|
|
52
|
+
allEntries.set(parent.id, parent);
|
|
53
|
+
}
|
|
54
|
+
parent = parent.parent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const [key, entry] of allEntries.entries()) {
|
|
59
|
+
const serialized: SerializedEntry = {
|
|
60
|
+
id: entry.id,
|
|
61
|
+
shortCode: entry.shortCode,
|
|
62
|
+
type: entry.type,
|
|
63
|
+
parentShortCode: entry.parent?.shortCode ?? null,
|
|
64
|
+
hasLoader: entry.loader?.length > 0,
|
|
65
|
+
hasMiddleware: entry.middleware?.length > 0,
|
|
66
|
+
hasErrorBoundary: entry.errorBoundary?.length > 0,
|
|
67
|
+
parallelCount: entry.parallel?.length ?? 0,
|
|
68
|
+
interceptCount: entry.intercept?.length ?? 0,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
if (entry.type === "route" && "pattern" in entry) {
|
|
72
|
+
serialized.pattern = entry.pattern;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (entry.type === "route") {
|
|
76
|
+
routes[key] = serialized;
|
|
77
|
+
} else if (entry.type === "layout" || entry.type === "cache") {
|
|
78
|
+
layouts[key] = serialized;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
routes,
|
|
84
|
+
layouts,
|
|
85
|
+
totalRoutes: Object.keys(routes).length,
|
|
86
|
+
totalLayouts: Object.keys(layouts).length,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Compare two manifests and return differences
|
|
92
|
+
*/
|
|
93
|
+
export function compareManifests(
|
|
94
|
+
oldManifest: SerializedManifest,
|
|
95
|
+
newManifest: SerializedManifest,
|
|
96
|
+
): {
|
|
97
|
+
addedRoutes: string[];
|
|
98
|
+
removedRoutes: string[];
|
|
99
|
+
changedRoutes: Array<{
|
|
100
|
+
key: string;
|
|
101
|
+
field: string;
|
|
102
|
+
old: any;
|
|
103
|
+
new: any;
|
|
104
|
+
}>;
|
|
105
|
+
addedLayouts: string[];
|
|
106
|
+
removedLayouts: string[];
|
|
107
|
+
changedLayouts: Array<{
|
|
108
|
+
key: string;
|
|
109
|
+
field: string;
|
|
110
|
+
old: any;
|
|
111
|
+
new: any;
|
|
112
|
+
}>;
|
|
113
|
+
} {
|
|
114
|
+
const addedRoutes: string[] = [];
|
|
115
|
+
const removedRoutes: string[] = [];
|
|
116
|
+
const changedRoutes: Array<{
|
|
117
|
+
key: string;
|
|
118
|
+
field: string;
|
|
119
|
+
old: any;
|
|
120
|
+
new: any;
|
|
121
|
+
}> = [];
|
|
122
|
+
const addedLayouts: string[] = [];
|
|
123
|
+
const removedLayouts: string[] = [];
|
|
124
|
+
const changedLayouts: Array<{
|
|
125
|
+
key: string;
|
|
126
|
+
field: string;
|
|
127
|
+
old: any;
|
|
128
|
+
new: any;
|
|
129
|
+
}> = [];
|
|
130
|
+
|
|
131
|
+
// Compare routes
|
|
132
|
+
const oldRouteKeys = new Set(Object.keys(oldManifest.routes));
|
|
133
|
+
const newRouteKeys = new Set(Object.keys(newManifest.routes));
|
|
134
|
+
|
|
135
|
+
for (const key of newRouteKeys) {
|
|
136
|
+
if (!oldRouteKeys.has(key)) {
|
|
137
|
+
addedRoutes.push(key);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const key of oldRouteKeys) {
|
|
142
|
+
if (!newRouteKeys.has(key)) {
|
|
143
|
+
removedRoutes.push(key);
|
|
144
|
+
} else {
|
|
145
|
+
// Compare fields
|
|
146
|
+
const oldEntry = oldManifest.routes[key];
|
|
147
|
+
const newEntry = newManifest.routes[key];
|
|
148
|
+
for (const field of Object.keys(oldEntry) as (keyof SerializedEntry)[]) {
|
|
149
|
+
if (oldEntry[field] !== newEntry[field]) {
|
|
150
|
+
changedRoutes.push({
|
|
151
|
+
key,
|
|
152
|
+
field,
|
|
153
|
+
old: oldEntry[field],
|
|
154
|
+
new: newEntry[field],
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Compare layouts
|
|
162
|
+
const oldLayoutKeys = new Set(Object.keys(oldManifest.layouts));
|
|
163
|
+
const newLayoutKeys = new Set(Object.keys(newManifest.layouts));
|
|
164
|
+
|
|
165
|
+
for (const key of newLayoutKeys) {
|
|
166
|
+
if (!oldLayoutKeys.has(key)) {
|
|
167
|
+
addedLayouts.push(key);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const key of oldLayoutKeys) {
|
|
172
|
+
if (!newLayoutKeys.has(key)) {
|
|
173
|
+
removedLayouts.push(key);
|
|
174
|
+
} else {
|
|
175
|
+
const oldEntry = oldManifest.layouts[key];
|
|
176
|
+
const newEntry = newManifest.layouts[key];
|
|
177
|
+
for (const field of Object.keys(oldEntry) as (keyof SerializedEntry)[]) {
|
|
178
|
+
if (oldEntry[field] !== newEntry[field]) {
|
|
179
|
+
changedLayouts.push({
|
|
180
|
+
key,
|
|
181
|
+
field,
|
|
182
|
+
old: oldEntry[field],
|
|
183
|
+
new: newEntry[field],
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
addedRoutes,
|
|
192
|
+
removedRoutes,
|
|
193
|
+
changedRoutes,
|
|
194
|
+
addedLayouts,
|
|
195
|
+
removedLayouts,
|
|
196
|
+
changedLayouts,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Format manifest diff as a human-readable string
|
|
202
|
+
*/
|
|
203
|
+
export function formatManifestDiff(
|
|
204
|
+
diff: ReturnType<typeof compareManifests>,
|
|
205
|
+
): string {
|
|
206
|
+
const lines: string[] = [];
|
|
207
|
+
|
|
208
|
+
if (diff.addedRoutes.length > 0) {
|
|
209
|
+
lines.push("Added routes:");
|
|
210
|
+
diff.addedRoutes.forEach((r) => lines.push(` + ${r}`));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (diff.removedRoutes.length > 0) {
|
|
214
|
+
lines.push("Removed routes:");
|
|
215
|
+
diff.removedRoutes.forEach((r) => lines.push(` - ${r}`));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (diff.changedRoutes.length > 0) {
|
|
219
|
+
lines.push("Changed routes:");
|
|
220
|
+
diff.changedRoutes.forEach((c) =>
|
|
221
|
+
lines.push(` ~ ${c.key}.${c.field}: ${c.old} -> ${c.new}`),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (diff.addedLayouts.length > 0) {
|
|
226
|
+
lines.push("Added layouts:");
|
|
227
|
+
diff.addedLayouts.forEach((l) => lines.push(` + ${l}`));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (diff.removedLayouts.length > 0) {
|
|
231
|
+
lines.push("Removed layouts:");
|
|
232
|
+
diff.removedLayouts.forEach((l) => lines.push(` - ${l}`));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (diff.changedLayouts.length > 0) {
|
|
236
|
+
lines.push("Changed layouts:");
|
|
237
|
+
diff.changedLayouts.forEach((c) =>
|
|
238
|
+
lines.push(` ~ ${c.key}.${c.field}: ${c.old} -> ${c.new}`),
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return lines.length > 0 ? lines.join("\n") : "No differences found";
|
|
243
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ErrorBoundaryFallbackProps } from "./types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Default error boundary fallback component
|
|
6
|
+
*
|
|
7
|
+
* This is rendered when an error occurs and no custom error boundary
|
|
8
|
+
* is defined in the route tree. Shows a simple "Internal Server Error"
|
|
9
|
+
* message with the error details in development.
|
|
10
|
+
*/
|
|
11
|
+
export function DefaultErrorFallback({
|
|
12
|
+
error,
|
|
13
|
+
}: ErrorBoundaryFallbackProps): ReactNode {
|
|
14
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
style={{
|
|
19
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
20
|
+
padding: "2rem",
|
|
21
|
+
maxWidth: "600px",
|
|
22
|
+
margin: "2rem auto",
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<h1
|
|
26
|
+
style={{
|
|
27
|
+
color: "#dc2626",
|
|
28
|
+
fontSize: "1.5rem",
|
|
29
|
+
marginBottom: "1rem",
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
Internal Server Error
|
|
33
|
+
</h1>
|
|
34
|
+
<p
|
|
35
|
+
style={{
|
|
36
|
+
color: "#374151",
|
|
37
|
+
marginBottom: "1rem",
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
An unexpected error occurred while processing your request.
|
|
41
|
+
</p>
|
|
42
|
+
{isDev && (
|
|
43
|
+
<div
|
|
44
|
+
style={{
|
|
45
|
+
background: "#fef2f2",
|
|
46
|
+
border: "1px solid #fecaca",
|
|
47
|
+
borderRadius: "0.5rem",
|
|
48
|
+
padding: "1rem",
|
|
49
|
+
marginBottom: "1rem",
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<p
|
|
53
|
+
style={{
|
|
54
|
+
fontWeight: 600,
|
|
55
|
+
color: "#991b1b",
|
|
56
|
+
marginBottom: "0.5rem",
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
{error.name}: {error.message}
|
|
60
|
+
</p>
|
|
61
|
+
{error.stack && (
|
|
62
|
+
<pre
|
|
63
|
+
style={{
|
|
64
|
+
fontSize: "0.75rem",
|
|
65
|
+
color: "#6b7280",
|
|
66
|
+
overflow: "auto",
|
|
67
|
+
whiteSpace: "pre-wrap",
|
|
68
|
+
wordBreak: "break-word",
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{error.stack}
|
|
72
|
+
</pre>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
76
|
+
<a
|
|
77
|
+
href="/"
|
|
78
|
+
style={{
|
|
79
|
+
display: "inline-block",
|
|
80
|
+
color: "#2563eb",
|
|
81
|
+
textDecoration: "underline",
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
Go to homepage
|
|
85
|
+
</a>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
package/src/deps/rsc.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="@vitejs/plugin-rsc/types" />
|
|
2
|
+
// Re-export @vitejs/plugin-rsc/rsc for internal use by virtual entries
|
|
3
|
+
export {
|
|
4
|
+
renderToReadableStream,
|
|
5
|
+
decodeReply,
|
|
6
|
+
createTemporaryReferenceSet,
|
|
7
|
+
loadServerAction,
|
|
8
|
+
decodeAction,
|
|
9
|
+
decodeFormState,
|
|
10
|
+
} from "@vitejs/plugin-rsc/rsc";
|
package/src/deps/ssr.ts
ADDED