@rangojs/router 0.0.0-experimental.32 → 0.0.0-experimental.3232cd17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/README.md +198 -44
- package/dist/bin/rango.js +287 -105
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3248 -1117
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +73 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +107 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +245 -21
- package/skills/caching/SKILL.md +302 -6
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +270 -30
- package/skills/host-router/SKILL.md +82 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +49 -5
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +294 -30
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +203 -7
- package/skills/prerender/SKILL.md +123 -100
- package/skills/rango/SKILL.md +250 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +122 -47
- package/skills/route/SKILL.md +97 -5
- package/skills/router-setup/SKILL.md +90 -5
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +329 -27
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +67 -40
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +86 -147
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +148 -19
- package/src/browser/navigation-client.ts +187 -67
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +76 -67
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/partial-update.ts +123 -94
- package/src/browser/prefetch/cache.ts +214 -36
- package/src/browser/prefetch/fetch.ts +260 -38
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +126 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +93 -11
- package/src/browser/react/NavigationProvider.tsx +115 -34
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +49 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +23 -69
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +22 -5
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +46 -11
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +215 -76
- package/src/browser/scroll-restoration.ts +46 -39
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +176 -50
- package/src/browser/types.ts +95 -11
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +137 -32
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +9 -2
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +278 -96
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +149 -43
- package/src/cache/cache-scope.ts +148 -81
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2550 -93
- package/src/cache/cf/index.ts +11 -17
- package/src/cache/document-cache.ts +78 -27
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +108 -290
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +52 -26
- package/src/index.ts +100 -38
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +37 -41
- package/src/prerender.ts +198 -82
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +437 -274
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +113 -37
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +52 -10
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -17
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +108 -9
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +45 -22
- package/src/router/handler-context.ts +83 -41
- package/src/router/intercept-resolution.ts +25 -23
- package/src/router/lazy-includes.ts +19 -53
- package/src/router/loader-resolution.ts +213 -30
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +49 -45
- package/src/router/match-api.ts +120 -204
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +27 -6
- package/src/router/match-middleware/cache-lookup.ts +205 -249
- package/src/router/match-middleware/cache-store.ts +45 -32
- package/src/router/match-middleware/intercept-resolution.ts +8 -28
- package/src/router/match-middleware/segment-resolution.ts +52 -18
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +104 -40
- package/src/router/metrics.ts +5 -34
- package/src/router/middleware-types.ts +13 -142
- package/src/router/middleware.ts +173 -143
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +109 -63
- package/src/router/prerender-match.ts +190 -54
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +63 -55
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +6 -28
- package/src/router/router-interfaces.ts +100 -35
- package/src/router/router-options.ts +91 -11
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +242 -75
- package/src/router/segment-resolution/helpers.ts +63 -24
- package/src/router/segment-resolution/loader-cache.ts +41 -37
- package/src/router/segment-resolution/revalidation.ts +456 -372
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +2 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +91 -46
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +134 -43
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +492 -383
- package/src/rsc/helpers.ts +162 -46
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +30 -3
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +90 -63
- package/src/rsc/rsc-rendering.ts +56 -54
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +74 -67
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/types.ts +25 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +134 -0
- package/src/segment-system.tsx +272 -129
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +309 -61
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +26 -24
- package/src/server/loader-registry.ts +10 -28
- package/src/server/request-context.ts +338 -126
- package/src/ssr/index.tsx +23 -15
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +233 -81
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +107 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +37 -14
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +58 -11
- package/src/urls/path-helper.ts +57 -111
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +346 -89
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +36 -38
- package/src/vite/discovery/discover-routers.ts +130 -85
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +192 -99
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +51 -6
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin-types.ts +187 -69
- package/src/vite/plugins/cjs-to-esm.ts +8 -18
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +49 -98
- package/src/vite/plugins/expose-id-utils.ts +11 -50
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
- package/src/vite/plugins/expose-internal-ids.ts +554 -317
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +89 -27
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +21 -25
- package/src/vite/plugins/version-plugin.ts +41 -20
- package/src/vite/plugins/virtual-entries.ts +2 -17
- package/src/vite/rango.ts +257 -289
- package/src/vite/router-discovery.ts +930 -140
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +27 -29
- package/src/vite/utils/shared-utils.ts +92 -42
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -37,7 +37,10 @@ import type {
|
|
|
37
37
|
UseItems,
|
|
38
38
|
} from "../route-types.js";
|
|
39
39
|
import type { SearchSchema } from "../search-params.js";
|
|
40
|
-
import type {
|
|
40
|
+
import type {
|
|
41
|
+
PrerenderHandlerDefinition,
|
|
42
|
+
PassthroughHandlerDefinition,
|
|
43
|
+
} from "../prerender.js";
|
|
41
44
|
import type { StaticHandlerDefinition } from "../static-handler.js";
|
|
42
45
|
import type { InterceptWhenFn } from "../server/context";
|
|
43
46
|
import type {
|
|
@@ -70,6 +73,7 @@ export type PathFn<TEnv> = <
|
|
|
70
73
|
ctx: HandlerContext<TParams, TEnv, TSearch>,
|
|
71
74
|
) => ReactNode | Promise<ReactNode> | Response | Promise<Response>)
|
|
72
75
|
| PrerenderHandlerDefinition<TParams>
|
|
76
|
+
| PassthroughHandlerDefinition<TParams, TEnv>
|
|
73
77
|
| StaticHandlerDefinition<TParams>,
|
|
74
78
|
optionsOrUse?: PathOptions<TName, TSearch> | (() => UseItems<RouteUseItem>),
|
|
75
79
|
use?: () => UseItems<RouteUseItem>,
|
|
@@ -110,6 +114,12 @@ export type ResponsePathFn<TEnv> = <
|
|
|
110
114
|
* Path function for JSON response routes (path.json()).
|
|
111
115
|
* Handler can return plain JSON-serializable values or Response.
|
|
112
116
|
* TData is inferred from the handler's return type (excluding Response/Promise wrappers).
|
|
117
|
+
*
|
|
118
|
+
* Note: a nested Promise in the return (a forgotten await) is caught at runtime
|
|
119
|
+
* by response-route-handler.ts (it throws instead of silently emitting `{}`). A
|
|
120
|
+
* compile-time JsonValue constraint was evaluated and rejected — it breaks
|
|
121
|
+
* interface-typed returns (interfaces lack the index signature JsonValue
|
|
122
|
+
* requires) and preserves literal types in the inferred response shape.
|
|
113
123
|
*/
|
|
114
124
|
export type JsonResponsePathFn<TEnv> = <
|
|
115
125
|
const TPattern extends string,
|
|
@@ -229,12 +239,27 @@ export type PathHelpers<TEnv> = {
|
|
|
229
239
|
include: IncludeFn<TEnv>;
|
|
230
240
|
|
|
231
241
|
/**
|
|
232
|
-
* Define parallel routes that render simultaneously in named slots
|
|
242
|
+
* Define parallel routes that render simultaneously in named slots.
|
|
243
|
+
*
|
|
244
|
+
* A slot value can be a Handler / ReactNode / StaticHandlerDefinition
|
|
245
|
+
* (legacy form, broadcast use applies to every slot) or a slot descriptor
|
|
246
|
+
* `{ handler, use? }` whose `use` is scoped to that slot only. Per-slot
|
|
247
|
+
* merge order is `handler.use` → shared `use` → slot-local `use`, with
|
|
248
|
+
* narrowest scope winning for last-write-wins items like `loading()`.
|
|
233
249
|
*/
|
|
234
250
|
parallel: <
|
|
235
251
|
TSlots extends Record<
|
|
236
252
|
`@${string}`,
|
|
237
|
-
Handler<any, any, TEnv>
|
|
253
|
+
| Handler<any, any, TEnv>
|
|
254
|
+
| ReactNode
|
|
255
|
+
| StaticHandlerDefinition
|
|
256
|
+
| {
|
|
257
|
+
handler:
|
|
258
|
+
| Handler<any, any, TEnv>
|
|
259
|
+
| ReactNode
|
|
260
|
+
| StaticHandlerDefinition;
|
|
261
|
+
use?: () => ParallelUseItem[];
|
|
262
|
+
}
|
|
238
263
|
>,
|
|
239
264
|
>(
|
|
240
265
|
slots: TSlots,
|
|
@@ -245,7 +270,7 @@ export type PathHelpers<TEnv> = {
|
|
|
245
270
|
* Define an intercepting route for soft navigation
|
|
246
271
|
* Note: routeName must match a named path() in this urlpatterns
|
|
247
272
|
*/
|
|
248
|
-
intercept: keyof
|
|
273
|
+
intercept: keyof Rango.GeneratedRouteMap extends never
|
|
249
274
|
? (
|
|
250
275
|
slotName: `@${string}`,
|
|
251
276
|
routeName: string,
|
|
@@ -254,15 +279,26 @@ export type PathHelpers<TEnv> = {
|
|
|
254
279
|
) => InterceptItem
|
|
255
280
|
: (
|
|
256
281
|
slotName: `@${string}`,
|
|
257
|
-
routeName: (keyof
|
|
282
|
+
routeName: (keyof Rango.GeneratedRouteMap & string) | `.${string}`,
|
|
258
283
|
handler: ReactNode | Handler<any, any, TEnv>,
|
|
259
284
|
use?: () => InterceptUseItem[],
|
|
260
285
|
) => InterceptItem;
|
|
261
286
|
|
|
262
287
|
/**
|
|
263
|
-
* Attach middleware to the current route/layout
|
|
288
|
+
* Attach middleware to the current route/layout, or wrap child segments
|
|
264
289
|
*/
|
|
265
|
-
middleware:
|
|
290
|
+
middleware: {
|
|
291
|
+
(fn: MiddlewareFn<TEnv>): MiddlewareItem;
|
|
292
|
+
(
|
|
293
|
+
fn: MiddlewareFn<TEnv>,
|
|
294
|
+
children: () => UseItems<LayoutUseItem>,
|
|
295
|
+
): MiddlewareItem;
|
|
296
|
+
(fns: MiddlewareFn<TEnv>[]): MiddlewareItem;
|
|
297
|
+
(
|
|
298
|
+
fns: MiddlewareFn<TEnv>[],
|
|
299
|
+
children: () => UseItems<LayoutUseItem>,
|
|
300
|
+
): MiddlewareItem;
|
|
301
|
+
};
|
|
266
302
|
|
|
267
303
|
/**
|
|
268
304
|
* Control when a segment should revalidate during navigation
|
|
@@ -280,7 +316,10 @@ export type PathHelpers<TEnv> = {
|
|
|
280
316
|
/**
|
|
281
317
|
* Attach a loading component to the current route/layout
|
|
282
318
|
*/
|
|
283
|
-
loading: (
|
|
319
|
+
loading: (
|
|
320
|
+
component: ReactNode | (() => ReactNode),
|
|
321
|
+
options?: { ssr?: boolean },
|
|
322
|
+
) => LoadingItem;
|
|
284
323
|
|
|
285
324
|
/**
|
|
286
325
|
* Attach an error boundary to catch errors in this segment
|
|
@@ -309,15 +348,23 @@ export type PathHelpers<TEnv> = {
|
|
|
309
348
|
<const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
|
|
310
349
|
children: () => TChildren,
|
|
311
350
|
): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
|
|
312
|
-
(options: PartialCacheOptions | false): TypedCacheItem<{}, {}>;
|
|
351
|
+
(options: PartialCacheOptions<TEnv> | false): TypedCacheItem<{}, {}>;
|
|
313
352
|
<const TChildren extends readonly (AllUseItems | readonly AllUseItems[])[]>(
|
|
314
|
-
options: PartialCacheOptions | false,
|
|
353
|
+
options: PartialCacheOptions<TEnv> | false,
|
|
315
354
|
use: () => TChildren,
|
|
316
355
|
): TypedCacheItem<ExtractRoutes<TChildren>, ExtractResponses<TChildren>>;
|
|
317
356
|
};
|
|
318
357
|
|
|
319
358
|
/**
|
|
320
|
-
*
|
|
359
|
+
* Opt a route (or group of routes) into transition-driven navigation.
|
|
360
|
+
*
|
|
361
|
+
* Two independent layers: (1) startTransition, on all React versions, holds
|
|
362
|
+
* the previous content across a same-route nav (no skeleton flash) and is the
|
|
363
|
+
* precondition for any view transition; (2) on experimental React, an
|
|
364
|
+
* additional `<ViewTransition>` boundary cross-fades/morphs the swap. Pass
|
|
365
|
+
* `{ viewTransition: false }` to keep #1 without the router boundary. A view
|
|
366
|
+
* transition cannot fire without a startTransition. See
|
|
367
|
+
* skills/view-transitions for the startTransition x ViewTransition matrix.
|
|
321
368
|
*/
|
|
322
369
|
transition: {
|
|
323
370
|
(): TransitionItem;
|
package/src/urls/path-helper.ts
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { Handler } from "../types.js";
|
|
3
|
-
import type {
|
|
4
|
-
AllUseItems,
|
|
5
|
-
RouteItem,
|
|
6
|
-
RouteUseItem,
|
|
7
|
-
UseItems,
|
|
8
|
-
} from "../route-types.js";
|
|
3
|
+
import type { RouteItem, RouteUseItem, UseItems } from "../route-types.js";
|
|
9
4
|
import {
|
|
10
|
-
getContext,
|
|
11
5
|
getUrlPrefix,
|
|
12
6
|
getNamePrefix,
|
|
13
7
|
getRootScoped,
|
|
8
|
+
requireDslContext,
|
|
14
9
|
} from "../server/context";
|
|
15
|
-
import { invariant } from "../errors";
|
|
10
|
+
import { invariant, DataNotFoundError } from "../errors";
|
|
16
11
|
import { validateUserRouteName } from "../route-name.js";
|
|
17
12
|
import {
|
|
18
13
|
isPrerenderHandler,
|
|
14
|
+
isPassthroughHandler,
|
|
19
15
|
type PrerenderHandlerDefinition,
|
|
20
16
|
} from "../prerender.js";
|
|
21
17
|
import {
|
|
@@ -34,40 +30,15 @@ import type {
|
|
|
34
30
|
JsonResponsePathFn,
|
|
35
31
|
TextResponsePathFn,
|
|
36
32
|
} from "./path-helper-types.js";
|
|
33
|
+
import {
|
|
34
|
+
resolveHandlerUse,
|
|
35
|
+
mergeHandlerUse,
|
|
36
|
+
} from "../route-definition/resolve-handler-use.js";
|
|
37
|
+
import {
|
|
38
|
+
emptySegmentBase,
|
|
39
|
+
runAndValidateUseItems,
|
|
40
|
+
} from "../route-definition/dsl-helpers.js";
|
|
37
41
|
|
|
38
|
-
/**
|
|
39
|
-
* Check if a value is a valid use item
|
|
40
|
-
*/
|
|
41
|
-
const isValidUseItem = (item: any): item is AllUseItems | undefined | null => {
|
|
42
|
-
return (
|
|
43
|
-
typeof item === "undefined" ||
|
|
44
|
-
item === null ||
|
|
45
|
-
(item &&
|
|
46
|
-
typeof item === "object" &&
|
|
47
|
-
"type" in item &&
|
|
48
|
-
[
|
|
49
|
-
"layout",
|
|
50
|
-
"route",
|
|
51
|
-
"middleware",
|
|
52
|
-
"revalidate",
|
|
53
|
-
"parallel",
|
|
54
|
-
"intercept",
|
|
55
|
-
"loader",
|
|
56
|
-
"loading",
|
|
57
|
-
"errorBoundary",
|
|
58
|
-
"notFoundBoundary",
|
|
59
|
-
"when",
|
|
60
|
-
"cache",
|
|
61
|
-
"transition",
|
|
62
|
-
"include",
|
|
63
|
-
].includes(item.type))
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Apply URL prefix to a pattern
|
|
69
|
-
* Handles edge cases like "/" patterns and double slashes
|
|
70
|
-
*/
|
|
71
42
|
function applyUrlPrefix(prefix: string, pattern: string): string {
|
|
72
43
|
if (!prefix) return pattern;
|
|
73
44
|
if (pattern === "/") return prefix;
|
|
@@ -77,29 +48,17 @@ function applyUrlPrefix(prefix: string, pattern: string): string {
|
|
|
77
48
|
return prefix + pattern;
|
|
78
49
|
}
|
|
79
50
|
|
|
80
|
-
/**
|
|
81
|
-
* Apply name prefix to a route name
|
|
82
|
-
*/
|
|
83
51
|
function applyNamePrefix(prefix: string | undefined, name: string): string {
|
|
84
52
|
if (!prefix) return name;
|
|
85
53
|
return `${prefix}.${name}`;
|
|
86
54
|
}
|
|
87
55
|
|
|
88
|
-
/**
|
|
89
|
-
* Resolve response type from path options (set by path.json(), path.text(), etc.)
|
|
90
|
-
*/
|
|
91
56
|
function resolveResponseType(
|
|
92
57
|
options: PathOptions | undefined,
|
|
93
58
|
): string | undefined {
|
|
94
59
|
return options?.[RESPONSE_TYPE];
|
|
95
60
|
}
|
|
96
61
|
|
|
97
|
-
/**
|
|
98
|
-
* Create path() helper
|
|
99
|
-
*
|
|
100
|
-
* The path() function is the key new feature - it combines URL pattern
|
|
101
|
-
* with handler at the definition site.
|
|
102
|
-
*/
|
|
103
62
|
export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
104
63
|
return ((
|
|
105
64
|
pattern: string,
|
|
@@ -107,17 +66,15 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
107
66
|
optionsOrUse?: PathOptions | (() => UseItems<RouteUseItem>),
|
|
108
67
|
maybeUse?: () => UseItems<RouteUseItem>,
|
|
109
68
|
): RouteItem => {
|
|
110
|
-
const store =
|
|
111
|
-
|
|
112
|
-
|
|
69
|
+
const { store, ctx } = requireDslContext(
|
|
70
|
+
"path() must be called inside urls()",
|
|
71
|
+
);
|
|
113
72
|
|
|
114
73
|
invariant(
|
|
115
74
|
!ctx.parent || ctx.parent.type !== "parallel",
|
|
116
75
|
"path() cannot be used inside parallel()",
|
|
117
76
|
);
|
|
118
77
|
|
|
119
|
-
// Walk the parent chain to prevent path() nested under another path(),
|
|
120
|
-
// even when separated by intermediate layouts (e.g. path(layout(path())))
|
|
121
78
|
{
|
|
122
79
|
let ancestor = ctx.parent;
|
|
123
80
|
while (ancestor) {
|
|
@@ -129,7 +86,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
129
86
|
}
|
|
130
87
|
}
|
|
131
88
|
|
|
132
|
-
// Determine options and use based on argument types
|
|
133
89
|
let options: PathOptions | undefined;
|
|
134
90
|
let use: (() => UseItems<RouteUseItem>) | undefined;
|
|
135
91
|
|
|
@@ -142,73 +98,74 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
142
98
|
use = maybeUse;
|
|
143
99
|
}
|
|
144
100
|
|
|
145
|
-
|
|
101
|
+
const handlerUseFn = resolveHandlerUse(handler);
|
|
102
|
+
const mountSite = resolveResponseType(options) ? "response" : "path";
|
|
103
|
+
const mergedUse = mergeHandlerUse(handlerUseFn, use, mountSite);
|
|
104
|
+
|
|
146
105
|
const urlPrefix = getUrlPrefix();
|
|
147
106
|
const namePrefix = getNamePrefix();
|
|
148
107
|
|
|
149
|
-
// Apply URL prefix to pattern
|
|
150
108
|
const prefixedPattern = applyUrlPrefix(urlPrefix, pattern);
|
|
151
109
|
|
|
152
|
-
// Generate route name - use provided name or generate from pattern
|
|
153
110
|
const localName =
|
|
154
111
|
options?.name || `$path_${pattern.replace(/[/:*?]/g, "_")}`;
|
|
155
112
|
if (options?.name) {
|
|
156
113
|
validateUserRouteName(options.name);
|
|
157
114
|
}
|
|
158
|
-
// Apply name prefix if set (from include())
|
|
159
115
|
const routeName = applyNamePrefix(namePrefix, localName);
|
|
160
116
|
|
|
161
117
|
const namespace = `${ctx.namespace}.${store.getNextIndex("route")}.${routeName}`;
|
|
162
118
|
|
|
163
|
-
// Per-request pruning: skip registration for routes that won't be rendered.
|
|
164
|
-
// forRoute is set by loadManifest() to the matched route name. During
|
|
165
|
-
// evaluateLazyEntry() (route matching), forRoute is unset so all routes
|
|
166
|
-
// register normally. We still increment counters to keep shortCodes stable
|
|
167
|
-
// across different routes (needed for segment reconciliation on navigation).
|
|
168
|
-
//
|
|
169
|
-
// include() does not need its own forRoute pruning. include() creates lazy
|
|
170
|
-
// entries that defer handler execution until route matching. When the lazy
|
|
171
|
-
// handler eventually runs inside loadManifest(), this path() check already
|
|
172
|
-
// covers all routes defined inside the include.
|
|
173
119
|
if (ctx.forRoute && routeName !== ctx.forRoute) {
|
|
174
120
|
store.getShortCode("route");
|
|
175
121
|
return { type: "route" } as RouteItem;
|
|
176
122
|
}
|
|
177
123
|
|
|
178
|
-
// Ensure handler is always a function (wrap ReactNode or extract from prerender/static def)
|
|
179
124
|
const wrappedHandler: Handler<any, any, TEnv> =
|
|
180
125
|
typeof handler === "function"
|
|
181
126
|
? (handler as Handler<any, any, TEnv>)
|
|
182
|
-
:
|
|
183
|
-
?
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
127
|
+
: isPassthroughHandler(handler)
|
|
128
|
+
? typeof handler.prerenderDef.handler === "function"
|
|
129
|
+
? (handler.prerenderDef.handler as Handler<any, any, TEnv>)
|
|
130
|
+
: () => {
|
|
131
|
+
throw new DataNotFoundError(
|
|
132
|
+
"No prerender data found for this route",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
: isPrerenderHandler(handler)
|
|
136
|
+
? typeof handler.handler === "function"
|
|
137
|
+
? (handler.handler as Handler<any, any, TEnv>)
|
|
138
|
+
: () => {
|
|
139
|
+
throw new DataNotFoundError(
|
|
140
|
+
"No prerender data found for this route",
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
: isStaticHandler(handler)
|
|
144
|
+
? (handler.handler as Handler<any, any, TEnv>)
|
|
145
|
+
: () => handler;
|
|
187
146
|
|
|
188
147
|
const entry = {
|
|
148
|
+
...emptySegmentBase(),
|
|
189
149
|
id: namespace,
|
|
190
150
|
shortCode: store.getShortCode("route"),
|
|
191
151
|
type: "route" as const,
|
|
192
152
|
parent: ctx.parent,
|
|
193
153
|
handler: wrappedHandler,
|
|
194
|
-
// Store the PREFIXED pattern for route matching
|
|
195
154
|
pattern: prefixedPattern,
|
|
196
|
-
loading: undefined,
|
|
197
|
-
middleware: [],
|
|
198
|
-
revalidate: [],
|
|
199
|
-
errorBoundary: [],
|
|
200
|
-
notFoundBoundary: [],
|
|
201
|
-
layout: [],
|
|
202
|
-
parallel: [],
|
|
203
|
-
intercept: [],
|
|
204
|
-
loader: [],
|
|
205
155
|
...(urlPrefix ? { mountPath: urlPrefix } : {}),
|
|
206
|
-
...(
|
|
156
|
+
...(isPassthroughHandler(handler)
|
|
207
157
|
? {
|
|
208
158
|
isPrerender: true as const,
|
|
209
|
-
prerenderDef: handler as PrerenderHandlerDefinition,
|
|
159
|
+
prerenderDef: handler.prerenderDef as PrerenderHandlerDefinition,
|
|
160
|
+
isPassthrough: true as const,
|
|
161
|
+
liveHandler: handler.liveHandler as Handler<any, any, TEnv>,
|
|
210
162
|
}
|
|
211
|
-
:
|
|
163
|
+
: isPrerenderHandler(handler)
|
|
164
|
+
? {
|
|
165
|
+
isPrerender: true as const,
|
|
166
|
+
prerenderDef: handler as PrerenderHandlerDefinition,
|
|
167
|
+
}
|
|
168
|
+
: {}),
|
|
212
169
|
...(isStaticHandler(handler)
|
|
213
170
|
? {
|
|
214
171
|
isStaticPrerender: true as const,
|
|
@@ -220,29 +177,23 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
220
177
|
: {}),
|
|
221
178
|
};
|
|
222
179
|
|
|
223
|
-
// Capture namespace prefix on static handler for build-time reverse() resolution
|
|
224
180
|
if (isStaticHandler(handler) && handler.$$id && ctx.namePrefix) {
|
|
225
181
|
(handler as any).$$routePrefix = ctx.namePrefix;
|
|
226
182
|
}
|
|
227
183
|
|
|
228
|
-
// Check for duplicate route names (TypeScript should catch this, but runtime check too)
|
|
229
184
|
invariant(
|
|
230
185
|
ctx.manifest.get(routeName) === undefined,
|
|
231
186
|
`Duplicate route name: ${routeName} at ${namespace}`,
|
|
232
187
|
);
|
|
233
188
|
|
|
234
|
-
// Register route entry with prefixed name
|
|
235
189
|
ctx.manifest.set(routeName, entry);
|
|
236
190
|
|
|
237
|
-
// Register root-scope flag for dot-local reverse resolution
|
|
238
191
|
registerRouteRootScope(routeName, getRootScoped());
|
|
239
192
|
|
|
240
|
-
// Also store pattern in a separate map for URL generation
|
|
241
193
|
if (ctx.patterns) {
|
|
242
194
|
ctx.patterns.set(routeName, prefixedPattern);
|
|
243
195
|
}
|
|
244
196
|
|
|
245
|
-
// Store pattern grouped by URL prefix for separate entry creation
|
|
246
197
|
if (ctx.patternsByPrefix) {
|
|
247
198
|
const urlPrefix = getUrlPrefix() || "";
|
|
248
199
|
if (!ctx.patternsByPrefix.has(urlPrefix)) {
|
|
@@ -251,12 +202,10 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
251
202
|
ctx.patternsByPrefix.get(urlPrefix)!.set(routeName, prefixedPattern);
|
|
252
203
|
}
|
|
253
204
|
|
|
254
|
-
// Store trailing slash config if specified
|
|
255
205
|
if (options?.trailingSlash && ctx.trailingSlash) {
|
|
256
206
|
ctx.trailingSlash.set(routeName, options.trailingSlash);
|
|
257
207
|
}
|
|
258
208
|
|
|
259
|
-
// Store search schema if specified
|
|
260
209
|
if (options?.search) {
|
|
261
210
|
if (ctx.searchSchemas) {
|
|
262
211
|
ctx.searchSchemas.set(routeName, options.search);
|
|
@@ -264,12 +213,14 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
264
213
|
registerSearchSchema(routeName, options.search);
|
|
265
214
|
}
|
|
266
215
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
216
|
+
if (mergedUse) {
|
|
217
|
+
const result = runAndValidateUseItems(
|
|
218
|
+
store,
|
|
219
|
+
namespace,
|
|
220
|
+
entry,
|
|
221
|
+
mergedUse,
|
|
222
|
+
"path",
|
|
223
|
+
"use",
|
|
273
224
|
);
|
|
274
225
|
return { name: namespace, type: "route", uses: result } as RouteItem;
|
|
275
226
|
}
|
|
@@ -278,10 +229,6 @@ export function createPathHelper<TEnv>(): PathFn<TEnv> {
|
|
|
278
229
|
}) as PathFn<TEnv>;
|
|
279
230
|
}
|
|
280
231
|
|
|
281
|
-
/**
|
|
282
|
-
* Attach response type tag methods (.json, .text, .html, .xml, .md, .image, .stream, .any) to a path helper.
|
|
283
|
-
* Each tag wraps the original path() call with the RESPONSE_TYPE option set.
|
|
284
|
-
*/
|
|
285
232
|
export function attachPathResponseTags<TEnv>(
|
|
286
233
|
pathFn: PathFn<TEnv>,
|
|
287
234
|
): PathFn<TEnv> & {
|
|
@@ -303,7 +250,6 @@ export function attachPathResponseTags<TEnv>(
|
|
|
303
250
|
) => {
|
|
304
251
|
let options: PathOptions;
|
|
305
252
|
let use: (() => any[]) | undefined;
|
|
306
|
-
|
|
307
253
|
if (typeof optionsOrUse === "function") {
|
|
308
254
|
options = { [RESPONSE_TYPE]: responseType };
|
|
309
255
|
use = optionsOrUse;
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
AllUseItems,
|
|
5
|
-
RouteUseItem,
|
|
6
|
-
UrlPatternsBrand,
|
|
7
|
-
} from "../route-types.js";
|
|
1
|
+
import type { TrailingSlashMode } from "../types.js";
|
|
2
|
+
import type { AllUseItems, UrlPatternsBrand } from "../route-types.js";
|
|
8
3
|
import type { SearchSchema } from "../search-params.js";
|
|
9
4
|
import { RESPONSE_TYPE } from "./response-types.js";
|
|
5
|
+
import type { DefaultEnv } from "../types.js";
|
|
6
|
+
import type { PathHelpers } from "./path-helper-types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Builder function accepted by urls() and as a shorthand for routes()/urls option.
|
|
10
|
+
* When passed directly to routes() or createRouter({ urls }), it is wrapped in urls() automatically.
|
|
11
|
+
*/
|
|
12
|
+
export type UrlBuilder<
|
|
13
|
+
TEnv = DefaultEnv,
|
|
14
|
+
TItems extends readonly (AllUseItems | readonly AllUseItems[])[] =
|
|
15
|
+
readonly AllUseItems[],
|
|
16
|
+
> = (helpers: PathHelpers<TEnv>) => TItems;
|
|
10
17
|
|
|
11
18
|
/**
|
|
12
19
|
* Sentinel type for unnamed routes.
|
|
@@ -42,16 +49,6 @@ export interface PathOptions<
|
|
|
42
49
|
[RESPONSE_TYPE]?: string;
|
|
43
50
|
}
|
|
44
51
|
|
|
45
|
-
/**
|
|
46
|
-
* Internal representation of a URL pattern definition
|
|
47
|
-
*/
|
|
48
|
-
export interface PathDefinition {
|
|
49
|
-
pattern: string;
|
|
50
|
-
name?: string;
|
|
51
|
-
handler: ReactNode | Handler<any, any, any>;
|
|
52
|
-
use?: RouteUseItem[];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
52
|
/**
|
|
56
53
|
* Result of urls() - contains the route definitions
|
|
57
54
|
*/
|
|
@@ -60,8 +57,6 @@ export interface UrlPatterns<
|
|
|
60
57
|
TRoutes extends Record<string, any> = Record<string, string>,
|
|
61
58
|
TResponses extends Record<string, unknown> = Record<string, unknown>,
|
|
62
59
|
> {
|
|
63
|
-
/** Internal: route definitions */
|
|
64
|
-
readonly definitions: PathDefinition[];
|
|
65
60
|
/** Internal: compiled handler function */
|
|
66
61
|
readonly handler: () => AllUseItems[];
|
|
67
62
|
/** Internal: trailing slash config per route name */
|
|
@@ -76,6 +71,40 @@ export interface UrlPatterns<
|
|
|
76
71
|
readonly _responses?: TResponses;
|
|
77
72
|
}
|
|
78
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Extract the phantom env type carried by a UrlPatterns value.
|
|
76
|
+
*/
|
|
77
|
+
export type UrlPatternsEnv<T> =
|
|
78
|
+
T extends UrlPatterns<infer TEnv, any, any> ? TEnv : never;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Guards `routes()` env compatibility without over-constraining.
|
|
82
|
+
*
|
|
83
|
+
* - An env-agnostic block (its env is `unknown` — e.g. a shared urls() module,
|
|
84
|
+
* or an app that does not augment `Rango.Env`) attaches to any router.
|
|
85
|
+
* - A block carrying a concrete env is accepted only when the router env
|
|
86
|
+
* (`TRouterEnv`) satisfies it; resolves to `never` otherwise, so a
|
|
87
|
+
* `urls<{ DB: D1Database }>()` cannot be mounted on a `createRouter<{}>()`.
|
|
88
|
+
*
|
|
89
|
+
* Use as `patterns: T & EnvCompatible<T, TEnv>` so `T` still infers from the
|
|
90
|
+
* argument — a bare `EnvCompatible<T, TEnv>` parameter sits in a non-inferrable
|
|
91
|
+
* conditional position and would collapse `T` to its constraint.
|
|
92
|
+
*
|
|
93
|
+
* Known limitation: `TRouterEnv extends ...` distributes over a union router env,
|
|
94
|
+
* so a `urls<A>()` block is accepted on `createRouter<A | B>()` even though the
|
|
95
|
+
* `B` arm cannot supply `A`'s env. Suppressing distribution with
|
|
96
|
+
* `[TRouterEnv] extends [...]` would close that edge but breaks the common
|
|
97
|
+
* generic-`TEnv` call sites (a deferred type parameter can't resolve the tuple
|
|
98
|
+
* conditional, so the intersection stops reducing to `T`). A router has one env,
|
|
99
|
+
* so a union env is not a supported pattern; the distributive form is kept.
|
|
100
|
+
*/
|
|
101
|
+
export type EnvCompatible<TPatterns, TRouterEnv> =
|
|
102
|
+
unknown extends UrlPatternsEnv<TPatterns>
|
|
103
|
+
? TPatterns
|
|
104
|
+
: TRouterEnv extends UrlPatternsEnv<TPatterns>
|
|
105
|
+
? TPatterns
|
|
106
|
+
: never;
|
|
107
|
+
|
|
79
108
|
/**
|
|
80
109
|
* Options for include()
|
|
81
110
|
*/
|
|
@@ -4,6 +4,8 @@ import type {
|
|
|
4
4
|
DefaultReverseRouteMap,
|
|
5
5
|
DefaultVars,
|
|
6
6
|
} from "../types/global-namespace.js";
|
|
7
|
+
import type { UseItems, ResponseRouteUseItem } from "../route-types.js";
|
|
8
|
+
import type { RequestScope } from "../types/request-scope.js";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Reverse function for response handler contexts.
|
|
@@ -30,17 +32,31 @@ type ResponseReverseFunction = [DefaultReverseRouteMap] extends [
|
|
|
30
32
|
* Symbol marking a route as a response route (non-RSC).
|
|
31
33
|
* Stored on PathOptions and UrlPatterns to signal the trie to short-circuit.
|
|
32
34
|
*/
|
|
33
|
-
export const RESPONSE_TYPE: unique symbol = Symbol.for(
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
export const RESPONSE_TYPE: unique symbol = Symbol.for("rangojs.responseType");
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Shared shape of a response-route handler: a function returning TReturn (or a
|
|
39
|
+
* promise of it), plus an optional composable `use` thunk merged at mount time.
|
|
40
|
+
*/
|
|
41
|
+
type ResponseHandlerOf<
|
|
42
|
+
TReturn,
|
|
43
|
+
TParams = Record<string, string>,
|
|
44
|
+
TEnv = any,
|
|
45
|
+
> = ((
|
|
46
|
+
ctx: ResponseHandlerContext<TParams, TEnv>,
|
|
47
|
+
) => TReturn | Promise<TReturn>) & {
|
|
48
|
+
/** Composable default DSL items merged when the handler is mounted. */
|
|
49
|
+
use?: () => UseItems<ResponseRouteUseItem>;
|
|
50
|
+
};
|
|
36
51
|
|
|
37
52
|
/**
|
|
38
53
|
* Handler that must return Response (not ReactNode).
|
|
39
54
|
* Used by path.image(), path.stream(), path.any() (binary/streaming data).
|
|
40
55
|
*/
|
|
41
|
-
export type ResponseHandler<
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
export type ResponseHandler<
|
|
57
|
+
TParams = Record<string, string>,
|
|
58
|
+
TEnv = any,
|
|
59
|
+
> = ResponseHandlerOf<Response, TParams, TEnv>;
|
|
44
60
|
|
|
45
61
|
/**
|
|
46
62
|
* JSON-serializable value type for auto-wrap support.
|
|
@@ -60,9 +76,7 @@ export type JsonValue =
|
|
|
60
76
|
export type JsonResponseHandler<
|
|
61
77
|
TParams = Record<string, string>,
|
|
62
78
|
TEnv = any,
|
|
63
|
-
> =
|
|
64
|
-
ctx: ResponseHandlerContext<TParams, TEnv>,
|
|
65
|
-
) => JsonValue | Response | Promise<JsonValue | Response>;
|
|
79
|
+
> = ResponseHandlerOf<JsonValue | Response, TParams, TEnv>;
|
|
66
80
|
|
|
67
81
|
/**
|
|
68
82
|
* Handler for text-based response routes (text, html, xml).
|
|
@@ -71,9 +85,7 @@ export type JsonResponseHandler<
|
|
|
71
85
|
export type TextResponseHandler<
|
|
72
86
|
TParams = Record<string, string>,
|
|
73
87
|
TEnv = any,
|
|
74
|
-
> =
|
|
75
|
-
ctx: ResponseHandlerContext<TParams, TEnv>,
|
|
76
|
-
) => string | Response | Promise<string | Response>;
|
|
88
|
+
> = ResponseHandlerOf<string | Response, TParams, TEnv>;
|
|
77
89
|
|
|
78
90
|
/**
|
|
79
91
|
* Lighter handler context for response routes.
|
|
@@ -83,19 +95,10 @@ export type TextResponseHandler<
|
|
|
83
95
|
export interface ResponseHandlerContext<
|
|
84
96
|
TParams = Record<string, string>,
|
|
85
97
|
TEnv = any,
|
|
86
|
-
> {
|
|
87
|
-
request: Request;
|
|
98
|
+
> extends RequestScope<TEnv> {
|
|
88
99
|
params: TParams;
|
|
89
100
|
/** @internal Phantom property for params type invariance. Prevents mounting handlers on wrong routes. */
|
|
90
101
|
readonly _paramCheck?: (params: TParams) => TParams;
|
|
91
|
-
/** Platform bindings (DB, KV, secrets, etc.). */
|
|
92
|
-
env: TEnv;
|
|
93
|
-
/** Query parameters from the URL (system params like `_rsc*` are filtered). */
|
|
94
|
-
searchParams: URLSearchParams;
|
|
95
|
-
/** The full URL object (with system params filtered). */
|
|
96
|
-
url: URL;
|
|
97
|
-
/** The pathname portion of the request URL. */
|
|
98
|
-
pathname: string;
|
|
99
102
|
reverse: ResponseReverseFunction;
|
|
100
103
|
/** Read a variable set by middleware via ctx.set(key, value) or ctx.set(ContextVar, value). */
|
|
101
104
|
get: {
|