@rangojs/router 0.0.0-experimental.0f44aca1
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 +5 -0
- package/README.md +899 -0
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +5214 -0
- package/package.json +176 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +220 -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 +645 -0
- package/src/browser/navigation-client.ts +215 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +550 -0
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +360 -0
- package/src/browser/react/NavigationProvider.tsx +386 -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 +431 -0
- package/src/browser/scroll-restoration.ts +400 -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 +538 -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 +469 -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 +540 -0
- package/src/cache/cf/index.ts +25 -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 +43 -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 +275 -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 +158 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +267 -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 +192 -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 +748 -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 +316 -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 +1239 -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 +289 -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 +1002 -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 +235 -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 +914 -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 +102 -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 +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +16 -0
- package/src/vite/plugin-types.ts +131 -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 +365 -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 +254 -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 +510 -0
- package/src/vite/router-discovery.ts +785 -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,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme type definitions for rsc-router theme system.
|
|
3
|
+
*
|
|
4
|
+
* The theme system provides:
|
|
5
|
+
* - Opt-in via router config
|
|
6
|
+
* - FOUC prevention via inline script
|
|
7
|
+
* - Server-side theme access via ctx.theme/ctx.setTheme
|
|
8
|
+
* - Client-side theme access via useTheme hook
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Theme value - stored in cookies/localStorage
|
|
13
|
+
*/
|
|
14
|
+
export type Theme = "light" | "dark" | "system";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolved theme - actual visual appearance (system preference resolved)
|
|
18
|
+
*/
|
|
19
|
+
export type ResolvedTheme = "light" | "dark";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Attribute used to apply theme to HTML element
|
|
23
|
+
* - "class": Adds theme value as CSS class (e.g., <html class="dark">)
|
|
24
|
+
* - "data-*": Sets data attribute (e.g., <html data-theme="dark">)
|
|
25
|
+
*/
|
|
26
|
+
export type ThemeAttribute = "class" | `data-${string}`;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Theme configuration for router
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const router = createRouter<Env>({
|
|
34
|
+
* theme: {
|
|
35
|
+
* defaultTheme: "system",
|
|
36
|
+
* themes: ["light", "dark"],
|
|
37
|
+
* attribute: "class",
|
|
38
|
+
* storageKey: "theme",
|
|
39
|
+
* }
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export interface ThemeConfig {
|
|
44
|
+
/**
|
|
45
|
+
* Default theme when no preference is stored
|
|
46
|
+
* @default "system"
|
|
47
|
+
*/
|
|
48
|
+
defaultTheme?: Theme;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Available theme options
|
|
52
|
+
* @default ["light", "dark"]
|
|
53
|
+
*/
|
|
54
|
+
themes?: string[];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Attribute to apply to HTML element
|
|
58
|
+
* @default "class"
|
|
59
|
+
*/
|
|
60
|
+
attribute?: ThemeAttribute;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Key for cookie and localStorage
|
|
64
|
+
* @default "theme"
|
|
65
|
+
*/
|
|
66
|
+
storageKey?: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Enable system preference detection
|
|
70
|
+
* When true, "system" theme will resolve based on prefers-color-scheme
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
enableSystem?: boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Set CSS color-scheme property on HTML element
|
|
77
|
+
* This enables native dark mode for form controls, scrollbars, etc.
|
|
78
|
+
* @default true
|
|
79
|
+
*/
|
|
80
|
+
enableColorScheme?: boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Custom mapping of theme names to attribute values
|
|
84
|
+
* Useful when theme names don't match desired attribute values
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* value: {
|
|
89
|
+
* light: "light-mode",
|
|
90
|
+
* dark: "dark-mode",
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
value?: Record<string, string>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resolved theme configuration with defaults applied
|
|
99
|
+
*/
|
|
100
|
+
export interface ResolvedThemeConfig {
|
|
101
|
+
defaultTheme: Theme;
|
|
102
|
+
themes: string[];
|
|
103
|
+
attribute: ThemeAttribute;
|
|
104
|
+
storageKey: string;
|
|
105
|
+
enableSystem: boolean;
|
|
106
|
+
enableColorScheme: boolean;
|
|
107
|
+
value: Record<string, string>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Return type from useTheme hook
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* function ThemeToggle() {
|
|
116
|
+
* const { theme, setTheme, resolvedTheme, themes } = useTheme();
|
|
117
|
+
*
|
|
118
|
+
* return (
|
|
119
|
+
* <select value={theme} onChange={e => setTheme(e.target.value as Theme)}>
|
|
120
|
+
* {themes.map(t => <option key={t}>{t}</option>)}
|
|
121
|
+
* </select>
|
|
122
|
+
* );
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export interface UseThemeReturn {
|
|
127
|
+
/**
|
|
128
|
+
* Current theme setting ("light" | "dark" | "system")
|
|
129
|
+
*/
|
|
130
|
+
theme: Theme;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Set the theme
|
|
134
|
+
*/
|
|
135
|
+
setTheme: (theme: Theme) => void;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Resolved theme based on system preference
|
|
139
|
+
* When theme is "system", this reflects the actual appearance
|
|
140
|
+
*/
|
|
141
|
+
resolvedTheme: ResolvedTheme;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Current system preference ("light" | "dark")
|
|
145
|
+
*/
|
|
146
|
+
systemTheme: ResolvedTheme;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Available theme options (includes "system" if enableSystem is true)
|
|
150
|
+
*/
|
|
151
|
+
themes: string[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Props for ThemeProvider component
|
|
156
|
+
*/
|
|
157
|
+
export interface ThemeProviderProps {
|
|
158
|
+
/**
|
|
159
|
+
* Theme configuration
|
|
160
|
+
*/
|
|
161
|
+
config: ResolvedThemeConfig;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Initial theme from server (from cookie)
|
|
165
|
+
*/
|
|
166
|
+
initialTheme?: Theme;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Children to render
|
|
170
|
+
*/
|
|
171
|
+
children: React.ReactNode;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Context value for ThemeContext
|
|
176
|
+
*/
|
|
177
|
+
export interface ThemeContextValue extends UseThemeReturn {
|
|
178
|
+
/**
|
|
179
|
+
* Full theme configuration
|
|
180
|
+
*/
|
|
181
|
+
config: ResolvedThemeConfig;
|
|
182
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useTheme - Hook for accessing theme state in client components.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useTheme } from "@rangojs/router/theme";
|
|
9
|
+
*
|
|
10
|
+
* function ThemeToggle() {
|
|
11
|
+
* const { theme, setTheme, resolvedTheme, themes } = useTheme();
|
|
12
|
+
*
|
|
13
|
+
* return (
|
|
14
|
+
* <select value={theme} onChange={e => setTheme(e.target.value)}>
|
|
15
|
+
* {themes.map(t => <option key={t}>{t}</option>)}
|
|
16
|
+
* </select>
|
|
17
|
+
* );
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { requireThemeContext } from "./theme-context.js";
|
|
23
|
+
import type { UseThemeReturn } from "./types.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Hook to access theme state and methods.
|
|
27
|
+
*
|
|
28
|
+
* Must be used within a ThemeProvider (which is automatically included
|
|
29
|
+
* in NavigationProvider when theme is enabled in router config).
|
|
30
|
+
*
|
|
31
|
+
* @returns Theme state and methods
|
|
32
|
+
* @throws Error if used outside ThemeProvider
|
|
33
|
+
*/
|
|
34
|
+
export function useTheme(): UseThemeReturn {
|
|
35
|
+
const ctx = requireThemeContext();
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
theme: ctx.theme,
|
|
39
|
+
setTheme: ctx.setTheme,
|
|
40
|
+
resolvedTheme: ctx.resolvedTheme,
|
|
41
|
+
systemTheme: ctx.systemTheme,
|
|
42
|
+
themes: ctx.themes,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error information passed to error boundary fallback components
|
|
5
|
+
*/
|
|
6
|
+
export interface ErrorInfo {
|
|
7
|
+
/** Error message (always available) */
|
|
8
|
+
message: string;
|
|
9
|
+
/** Error name/type (e.g., "RouteNotFoundError", "MiddlewareError") */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Optional error code for programmatic handling */
|
|
12
|
+
code?: string;
|
|
13
|
+
/** Stack trace (only in development) */
|
|
14
|
+
stack?: string;
|
|
15
|
+
/** Original error cause if available */
|
|
16
|
+
cause?: unknown;
|
|
17
|
+
/** Segment ID where the error occurred */
|
|
18
|
+
segmentId: string;
|
|
19
|
+
/** Segment type where the error occurred */
|
|
20
|
+
segmentType:
|
|
21
|
+
| "layout"
|
|
22
|
+
| "route"
|
|
23
|
+
| "parallel"
|
|
24
|
+
| "loader"
|
|
25
|
+
| "middleware"
|
|
26
|
+
| "cache";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Props passed to server-side error boundary fallback components
|
|
31
|
+
*
|
|
32
|
+
* Server error boundaries don't have a reset function since the error
|
|
33
|
+
* occurred during server rendering. Users can navigate away or refresh.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* function ProductErrorFallback({ error }: ErrorBoundaryFallbackProps) {
|
|
38
|
+
* return (
|
|
39
|
+
* <div>
|
|
40
|
+
* <h2>Something went wrong loading the product</h2>
|
|
41
|
+
* <p>{error.message}</p>
|
|
42
|
+
* <a href="/">Go home</a>
|
|
43
|
+
* </div>
|
|
44
|
+
* );
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export interface ErrorBoundaryFallbackProps {
|
|
49
|
+
/** Error information */
|
|
50
|
+
error: ErrorInfo;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Error boundary handler - receives error info and returns fallback UI
|
|
55
|
+
*/
|
|
56
|
+
export type ErrorBoundaryHandler = (
|
|
57
|
+
props: ErrorBoundaryFallbackProps,
|
|
58
|
+
) => ReactNode;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Props passed to client-side error boundary fallback components
|
|
62
|
+
*
|
|
63
|
+
* Client error boundaries have a reset function that clears the error state
|
|
64
|
+
* and re-renders the children.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* function ClientErrorFallback({ error, reset }: ClientErrorBoundaryFallbackProps) {
|
|
69
|
+
* return (
|
|
70
|
+
* <div>
|
|
71
|
+
* <h2>Something went wrong</h2>
|
|
72
|
+
* <p>{error.message}</p>
|
|
73
|
+
* <button onClick={reset}>Try again</button>
|
|
74
|
+
* </div>
|
|
75
|
+
* );
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export interface ClientErrorBoundaryFallbackProps {
|
|
80
|
+
/** Error information */
|
|
81
|
+
error: ErrorInfo;
|
|
82
|
+
/** Function to reset error state and retry rendering */
|
|
83
|
+
reset: () => void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Wrapped loader data result for deferred resolution with error handling.
|
|
88
|
+
* When loaders are deferred to client-side resolution, errors need to be
|
|
89
|
+
* wrapped so the client can handle them appropriately.
|
|
90
|
+
*/
|
|
91
|
+
export type LoaderDataResult<T = unknown> =
|
|
92
|
+
| { __loaderResult: true; ok: true; data: T }
|
|
93
|
+
| {
|
|
94
|
+
__loaderResult: true;
|
|
95
|
+
ok: false;
|
|
96
|
+
error: ErrorInfo;
|
|
97
|
+
fallback: ReactNode | null;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Type guard to check if a value is a wrapped loader result
|
|
102
|
+
*/
|
|
103
|
+
export function isLoaderDataResult(value: unknown): value is LoaderDataResult {
|
|
104
|
+
return (
|
|
105
|
+
typeof value === "object" &&
|
|
106
|
+
value !== null &&
|
|
107
|
+
"__loaderResult" in value &&
|
|
108
|
+
(value as any).__loaderResult === true
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Not found information passed to notFound boundary fallback components
|
|
114
|
+
*/
|
|
115
|
+
export interface NotFoundInfo {
|
|
116
|
+
/** Not found message */
|
|
117
|
+
message: string;
|
|
118
|
+
/** Segment ID where notFound was thrown */
|
|
119
|
+
segmentId: string;
|
|
120
|
+
/** Segment type where notFound was thrown */
|
|
121
|
+
segmentType:
|
|
122
|
+
| "layout"
|
|
123
|
+
| "route"
|
|
124
|
+
| "parallel"
|
|
125
|
+
| "loader"
|
|
126
|
+
| "middleware"
|
|
127
|
+
| "cache";
|
|
128
|
+
/** The pathname that triggered the not found */
|
|
129
|
+
pathname?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Props passed to notFound boundary fallback components
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* function ProductNotFound({ notFound }: NotFoundBoundaryFallbackProps) {
|
|
138
|
+
* return (
|
|
139
|
+
* <div>
|
|
140
|
+
* <h2>Product Not Found</h2>
|
|
141
|
+
* <p>{notFound.message}</p>
|
|
142
|
+
* <a href="/products">Browse all products</a>
|
|
143
|
+
* </div>
|
|
144
|
+
* );
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export interface NotFoundBoundaryFallbackProps {
|
|
149
|
+
/** Not found information */
|
|
150
|
+
notFound: NotFoundInfo;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* NotFound boundary handler - receives not found info and returns fallback UI
|
|
155
|
+
*/
|
|
156
|
+
export type NotFoundBoundaryHandler = (
|
|
157
|
+
props: NotFoundBoundaryFallbackProps,
|
|
158
|
+
) => ReactNode;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context passed to cache condition/key/tags functions.
|
|
3
|
+
*
|
|
4
|
+
* This is a subset of RequestContext that's guaranteed to be available
|
|
5
|
+
* during cache key generation (before middleware runs).
|
|
6
|
+
*
|
|
7
|
+
* Note: While the full RequestContext is passed, middleware-set variables
|
|
8
|
+
* (ctx.var, ctx.get()) may not be populated yet since cache lookup
|
|
9
|
+
* happens before middleware execution.
|
|
10
|
+
*/
|
|
11
|
+
export type { RequestContext as CacheContext } from "../server/request-context.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Cache configuration options for cache() DSL
|
|
15
|
+
*
|
|
16
|
+
* Controls how segments, layouts, and loaders are cached.
|
|
17
|
+
* Cache configuration inherits down the route tree unless overridden.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Basic caching with TTL
|
|
22
|
+
* cache({ ttl: 60 }, () => [
|
|
23
|
+
* layout(<BlogLayout />),
|
|
24
|
+
* route("post/:slug"),
|
|
25
|
+
* ])
|
|
26
|
+
*
|
|
27
|
+
* // With stale-while-revalidate
|
|
28
|
+
* cache({ ttl: 60, swr: 300 }, () => [
|
|
29
|
+
* route("product/:id"),
|
|
30
|
+
* ])
|
|
31
|
+
*
|
|
32
|
+
* // Conditional caching
|
|
33
|
+
* cache({
|
|
34
|
+
* ttl: 300,
|
|
35
|
+
* condition: (ctx) => !ctx.request.headers.get('x-preview'),
|
|
36
|
+
* }, () => [...])
|
|
37
|
+
*
|
|
38
|
+
* // Custom cache key
|
|
39
|
+
* cache({
|
|
40
|
+
* ttl: 300,
|
|
41
|
+
* key: (ctx) => `product-${ctx.params.id}-${ctx.searchParams.get('variant')}`,
|
|
42
|
+
* }, () => [...])
|
|
43
|
+
*
|
|
44
|
+
* // With tags for invalidation
|
|
45
|
+
* cache({
|
|
46
|
+
* ttl: 300,
|
|
47
|
+
* tags: (ctx) => [`product:${ctx.params.id}`, 'products'],
|
|
48
|
+
* }, () => [...])
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export interface CacheOptions<TEnv = unknown> {
|
|
52
|
+
/**
|
|
53
|
+
* Time-to-live in seconds.
|
|
54
|
+
* After this period, cached content is considered stale.
|
|
55
|
+
*/
|
|
56
|
+
ttl: number;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Stale-while-revalidate window in seconds (after TTL).
|
|
60
|
+
* During this window, stale content is served immediately while
|
|
61
|
+
* fresh content is fetched in the background via waitUntil.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // TTL: 60s, SWR: 300s
|
|
65
|
+
* // 0-60s: FRESH (serve from cache)
|
|
66
|
+
* // 60-360s: STALE (serve from cache, revalidate in background)
|
|
67
|
+
* // 360s+: EXPIRED (cache miss, fetch fresh)
|
|
68
|
+
*/
|
|
69
|
+
swr?: number;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Override the cache store for this boundary.
|
|
73
|
+
* When specified, this boundary and its children use this store
|
|
74
|
+
* instead of the app-level store from handler config.
|
|
75
|
+
*
|
|
76
|
+
* Useful for:
|
|
77
|
+
* - Different backends per route section (memory vs KV vs Redis)
|
|
78
|
+
* - Loader-specific caching strategies
|
|
79
|
+
* - Hot data in fast cache, cold data in larger/slower cache
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const kvStore = new CloudflareKVStore(env.CACHE_KV);
|
|
84
|
+
* const memoryStore = new MemorySegmentCacheStore({ defaults: { ttl: 10 } });
|
|
85
|
+
*
|
|
86
|
+
* // Fast memory cache for hot data
|
|
87
|
+
* cache({ store: memoryStore }, () => [
|
|
88
|
+
* route("dashboard"),
|
|
89
|
+
* ])
|
|
90
|
+
*
|
|
91
|
+
* // KV for larger, less frequently accessed data
|
|
92
|
+
* cache({ store: kvStore, ttl: 3600 }, () => [
|
|
93
|
+
* route("archive/:year"),
|
|
94
|
+
* ])
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
store?: import("../cache/types.js").SegmentCacheStore;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Conditional cache read function.
|
|
101
|
+
* Return false to skip cache for this request (always fetch fresh).
|
|
102
|
+
*
|
|
103
|
+
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
104
|
+
* Note: Middleware-set variables (ctx.var) may not be populated yet.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* condition: (ctx) => {
|
|
109
|
+
* // Skip cache for preview mode
|
|
110
|
+
* if (ctx.request.headers.get('x-preview')) return false;
|
|
111
|
+
* // Skip cache for authenticated users
|
|
112
|
+
* if (ctx.request.headers.has('authorization')) return false;
|
|
113
|
+
* return true;
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
condition?: (
|
|
118
|
+
ctx: import("../server/request-context.js").RequestContext<TEnv>,
|
|
119
|
+
) => boolean;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Custom cache key function - FULL OVERRIDE.
|
|
123
|
+
* Bypasses default key generation AND store's keyGenerator.
|
|
124
|
+
*
|
|
125
|
+
* Has access to full RequestContext including env, request, params, cookies, etc.
|
|
126
|
+
* Note: Middleware-set variables (ctx.var) may not be populated yet.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* // Include query params in cache key
|
|
131
|
+
* key: (ctx) => `product-${ctx.params.id}-${ctx.searchParams.get('variant')}`
|
|
132
|
+
*
|
|
133
|
+
* // Include env bindings
|
|
134
|
+
* key: (ctx) => `${ctx.env.REGION}:product:${ctx.params.id}`
|
|
135
|
+
*
|
|
136
|
+
* // Include cookies
|
|
137
|
+
* key: (ctx) => `${cookies().get('locale')?.value ?? 'en'}:${ctx.pathname}`
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
key?: (
|
|
141
|
+
ctx: import("../server/request-context.js").RequestContext<TEnv>,
|
|
142
|
+
) => string | Promise<string>;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Tags for cache invalidation.
|
|
146
|
+
* Can be a static array or a function that returns tags.
|
|
147
|
+
*
|
|
148
|
+
* Note: Tags are passed through to the store but built-in stores
|
|
149
|
+
* (MemorySegmentCacheStore, CFCacheStore) do not yet index or
|
|
150
|
+
* invalidate by tag. Effective tag-based invalidation requires a
|
|
151
|
+
* custom store implementation with secondary indices.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // Static tags
|
|
156
|
+
* tags: ['products', 'catalog']
|
|
157
|
+
*
|
|
158
|
+
* // Dynamic tags
|
|
159
|
+
* tags: (ctx) => [`product:${ctx.params.id}`, 'products']
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
tags?:
|
|
163
|
+
| string[]
|
|
164
|
+
| ((
|
|
165
|
+
ctx: import("../server/request-context.js").RequestContext<TEnv>,
|
|
166
|
+
) => string[]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Partial cache options for cache() DSL.
|
|
171
|
+
*
|
|
172
|
+
* When `ttl` is not specified, it will use the default from cache config.
|
|
173
|
+
* This allows cache() calls to inherit app-level defaults:
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* // App-level default (in handler config)
|
|
178
|
+
* cache: { store: myStore, defaults: { ttl: 60 } }
|
|
179
|
+
*
|
|
180
|
+
* // Route-level (inherits ttl from defaults)
|
|
181
|
+
* cache(() => [
|
|
182
|
+
* route("products"),
|
|
183
|
+
* ])
|
|
184
|
+
*
|
|
185
|
+
* // Override with explicit ttl
|
|
186
|
+
* cache({ ttl: 300 }, () => [...])
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export type PartialCacheOptions<TEnv = unknown> = Partial<CacheOptions<TEnv>>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Cache entry configuration stored in EntryData.
|
|
193
|
+
* Represents the resolved cache config for a segment.
|
|
194
|
+
*/
|
|
195
|
+
export interface EntryCacheConfig {
|
|
196
|
+
/** Cache options (false means caching disabled for this entry) - ttl is optional, uses defaults */
|
|
197
|
+
options: PartialCacheOptions | false;
|
|
198
|
+
}
|