@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa
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 +8 -4
- package/README.md +296 -887
- package/dist/bin/rango.js +459 -91
- package/dist/testing/vitest.js +36 -2
- package/dist/vite/index.js +1708 -414
- package/package.json +35 -10
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +82 -5
- package/skills/bundle-analysis/SKILL.md +2 -2
- package/skills/cache-guide/SKILL.md +14 -9
- package/skills/caching/SKILL.md +221 -12
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +83 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +11 -3
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +9 -9
- package/skills/hooks/SKILL.md +73 -900
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +84 -7
- package/skills/i18n/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +51 -17
- package/skills/layout/SKILL.md +38 -16
- package/skills/links/SKILL.md +1 -1
- package/skills/loader/SKILL.md +48 -20
- package/skills/middleware/SKILL.md +11 -5
- package/skills/migrate-nextjs/SKILL.md +203 -20
- package/skills/migrate-react-router/SKILL.md +59 -675
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +3 -3
- package/skills/observability/SKILL.md +70 -5
- package/skills/parallel/SKILL.md +32 -8
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +59 -28
- package/skills/rango/SKILL.md +124 -50
- package/skills/response-routes/SKILL.md +78 -46
- package/skills/route/SKILL.md +85 -6
- package/skills/router-setup/SKILL.md +41 -6
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +28 -3
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +1 -1
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +68 -654
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -918
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +47 -17
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +44 -1
- package/src/__augment-tests__/augmented.check.ts +2 -3
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +178 -100
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +81 -68
- package/src/browser/navigation-client.ts +115 -70
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +153 -88
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +157 -144
- package/src/browser/prefetch/cache.ts +148 -81
- package/src/browser/prefetch/fetch.ts +231 -51
- package/src/browser/prefetch/queue.ts +25 -7
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +40 -7
- package/src/browser/react/NavigationProvider.tsx +140 -99
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +17 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +14 -15
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-router.ts +6 -4
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +74 -8
- package/src/browser/rsc-router.tsx +97 -22
- package/src/browser/scroll-restoration.ts +15 -8
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/server-action-bridge.ts +216 -38
- package/src/browser/types.ts +94 -22
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/generate-manifest.ts +155 -131
- package/src/build/generate-route-types.ts +1 -1
- package/src/build/index.ts +11 -5
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -22
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +12 -1
- package/src/build/route-types/include-resolution.ts +455 -61
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +15 -2
- package/src/build/route-types/router-processing.ts +77 -41
- package/src/build/route-types/source-scan.ts +105 -7
- package/src/build/runtime-discovery.ts +4 -1
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +454 -101
- package/src/cache/cache-scope.ts +159 -54
- package/src/cache/cache-tag.ts +149 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2170 -377
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +39 -22
- package/src/client.tsx +28 -58
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +13 -1
- package/src/decode-loader-results.ts +18 -2
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +0 -3
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +57 -40
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +7 -0
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +7 -12
- package/src/index.rsc.ts +88 -8
- package/src/index.ts +90 -16
- package/src/internal-debug.ts +11 -10
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +75 -7
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +25 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +13 -49
- package/src/route-definition/dsl-helpers.ts +60 -53
- package/src/route-definition/helper-factories.ts +0 -2
- package/src/route-definition/helpers-types.ts +46 -46
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +6 -1
- package/src/route-definition/use-item-types.ts +3 -6
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +0 -5
- package/src/router/content-negotiation.ts +58 -23
- package/src/router/error-handling.ts +44 -17
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +6 -1
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +35 -2
- package/src/router/lazy-includes.ts +79 -56
- package/src/router/loader-resolution.ts +151 -73
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +76 -52
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +181 -178
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +115 -194
- package/src/router/match-middleware/cache-store.ts +61 -50
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +36 -67
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +231 -120
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +99 -152
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +111 -66
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +47 -42
- package/src/router/revalidation.ts +75 -81
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +70 -8
- package/src/router/router-options.ts +126 -4
- package/src/router/segment-resolution/fresh.ts +104 -80
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +215 -304
- 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 +35 -15
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +54 -35
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +9 -23
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -64
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +13 -5
- package/src/router.ts +119 -48
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +267 -152
- package/src/rsc/helpers.ts +78 -4
- package/src/rsc/index.ts +1 -4
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +11 -15
- package/src/rsc/progressive-enhancement.ts +120 -13
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +58 -141
- package/src/rsc/rsc-rendering.ts +492 -49
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +268 -82
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +45 -3
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +31 -26
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +260 -95
- package/src/server/context.ts +99 -9
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +125 -2
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +379 -138
- package/src/ssr/index.tsx +491 -182
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +14 -31
- package/src/testing/dispatch.ts +533 -160
- package/src/testing/e2e/fixture.ts +45 -11
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/e2e/parity.ts +85 -4
- package/src/testing/e2e/server.ts +12 -0
- package/src/testing/flight-matchers.ts +7 -14
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +36 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +30 -0
- package/src/testing/flight.ts +145 -70
- package/src/testing/generated-routes.ts +26 -50
- package/src/testing/index.ts +18 -19
- package/src/testing/internal/context.ts +184 -68
- 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 +357 -0
- package/src/testing/render-route.tsx +134 -115
- package/src/testing/run-loader.ts +140 -51
- package/src/testing/run-middleware.ts +59 -33
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
- package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
- package/src/testing/vitest.ts +138 -16
- package/src/theme/ThemeProvider.tsx +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +15 -15
- package/src/types/handler-context.ts +45 -15
- package/src/types/index.ts +2 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +8 -22
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +100 -13
- package/src/urls/include-helper.ts +10 -12
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -8
- package/src/urls/path-helper-types.ts +52 -14
- package/src/urls/path-helper.ts +5 -54
- package/src/urls/pattern-types.ts +36 -0
- package/src/urls/type-extraction.ts +76 -42
- package/src/urls/urls-function.ts +0 -14
- package/src/use-loader.tsx +0 -186
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +34 -43
- package/src/vite/discovery/discovery-errors.ts +61 -0
- package/src/vite/discovery/prerender-collection.ts +33 -46
- package/src/vite/discovery/state.ts +12 -1
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/index.ts +9 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +143 -10
- package/src/vite/plugins/cjs-to-esm.ts +8 -12
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +85 -56
- package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
- package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
- package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
- package/src/vite/plugins/expose-internal-ids.ts +10 -1
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +22 -27
- package/src/vite/plugins/version-plugin.ts +6 -66
- package/src/vite/plugins/virtual-entries.ts +137 -26
- package/src/vite/rango.ts +146 -135
- package/src/vite/router-discovery.ts +189 -48
- package/src/vite/utils/ast-handler-extract.ts +11 -20
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +4 -75
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +71 -44
- package/src/vite/utils/shared-utils.ts +55 -37
- 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/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
package/src/router/logging.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { INTERNAL_RANGO_DEBUG } from "../internal-debug.js";
|
|
3
3
|
|
|
4
|
-
// -- Revalidation trace types --
|
|
5
|
-
|
|
6
4
|
export interface RevalidationTraceEntry {
|
|
7
5
|
segmentId: string;
|
|
8
6
|
segmentType: string;
|
|
@@ -36,8 +34,6 @@ export interface RevalidationTrace {
|
|
|
36
34
|
entries: RevalidationTraceEntry[];
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
// -- Log context --
|
|
40
|
-
|
|
41
37
|
interface RouterLogContext {
|
|
42
38
|
requestId: string;
|
|
43
39
|
transactionId: string;
|
|
@@ -195,8 +191,6 @@ export function debugWarn(
|
|
|
195
191
|
console.warn(`${prefix} ${message}`);
|
|
196
192
|
}
|
|
197
193
|
|
|
198
|
-
// -- Revalidation trace helpers --
|
|
199
|
-
|
|
200
194
|
export function isTraceActive(): boolean {
|
|
201
195
|
if (!INTERNAL_RANGO_DEBUG) return false;
|
|
202
196
|
const ctx = routerLogContext.getStore();
|
package/src/router/manifest.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Router Manifest Loading
|
|
3
|
-
*
|
|
4
|
-
* Handles lazy loading and validation of route manifests.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import { invariant, RouteNotFoundError } from "../errors";
|
|
8
2
|
import { createRouteHelpers } from "../route-definition";
|
|
9
3
|
import {
|
|
@@ -14,29 +8,38 @@ import {
|
|
|
14
8
|
type MetricsStore,
|
|
15
9
|
} from "../server/context";
|
|
16
10
|
import MapRootLayout from "../server/root-layout";
|
|
11
|
+
import { joinPrefix } from "./pattern-matching.js";
|
|
17
12
|
import type { RouteEntry } from "../types";
|
|
18
13
|
import type { UrlPatterns } from "../urls";
|
|
14
|
+
import {
|
|
15
|
+
isIncludeProvider,
|
|
16
|
+
resolveIncludeModule,
|
|
17
|
+
} from "../urls/include-provider.js";
|
|
19
18
|
import { VERSION } from "@rangojs/router:version";
|
|
20
19
|
|
|
20
|
+
// Tags an error thrown while dynamically importing an async include's module
|
|
21
|
+
// (`() => import("./routes")`) so loadManifest's outer catch re-raises it as a
|
|
22
|
+
// server error rather than masking it as a RouteNotFoundError (404).
|
|
23
|
+
const MODULE_LOAD_FAILURE = Symbol.for("rango.moduleLoadFailure");
|
|
24
|
+
|
|
21
25
|
// Module-level manifest cache: avoids re-executing DSL handler on every request.
|
|
22
26
|
// Handler execution is deterministic (components, loaders, middleware are module-level
|
|
23
27
|
// stable references), so the resulting EntryData tree can be safely cached and reused
|
|
24
28
|
// across requests within the same isolate.
|
|
25
29
|
//
|
|
26
|
-
// Cache is keyed by (VERSION, mountIndex, routeKey, isSSR).
|
|
30
|
+
// Cache is keyed by (VERSION, routerId, mountIndex, routeKey, isSSR). routeKey is
|
|
31
|
+
// REQUIRED in the key: loadManifest() runs the handler with forRoute=routeKey, and
|
|
32
|
+
// path-helper.ts prunes (skips registering) every route except forRoute, so the
|
|
33
|
+
// resulting Store.manifest is pruned to the requested route — NOT the full include.
|
|
34
|
+
// Dropping routeKey would make a sibling route miss and overwrite this entry with its
|
|
35
|
+
// own pruned manifest, so alternating sibling requests would thrash (re-run the
|
|
36
|
+
// handler every time). Running the include handler once per isolate instead of once
|
|
37
|
+
// per route is possible but needs an unpruned manifest cache with prune-on-read — see
|
|
38
|
+
// LP1 in docs/internal/matching-and-lazy-discovery.md. VERSION comes from the
|
|
27
39
|
// @rangojs/router:version virtual module which Vite invalidates on RSC module HMR.
|
|
28
40
|
// When VERSION changes, this module re-evaluates and the cache is recreated empty.
|
|
29
|
-
// Including VERSION in the key is additional defense against stale entries.
|
|
30
41
|
const manifestModuleCache = new Map<string, Map<string, EntryData>>();
|
|
31
42
|
|
|
32
|
-
/**
|
|
33
|
-
* Load manifest from route entry with AsyncLocalStorage context
|
|
34
|
-
* Handles lazy imports, unwrapping, and validation
|
|
35
|
-
*
|
|
36
|
-
* Results are cached at module level after first execution. Subsequent calls
|
|
37
|
-
* for the same (routeKey, isSSR) within the same isolate return cached data
|
|
38
|
-
* without re-executing the DSL handler.
|
|
39
|
-
*/
|
|
40
43
|
/**
|
|
41
44
|
* Clear the module-level manifest cache.
|
|
42
45
|
* Called on HMR to ensure stale handler references are discarded.
|
|
@@ -65,9 +68,11 @@ export async function loadManifest(
|
|
|
65
68
|
|
|
66
69
|
const mountIndex = entry.mountIndex;
|
|
67
70
|
|
|
68
|
-
// Check module-level cache (persists across requests within same isolate)
|
|
71
|
+
// Check module-level cache (persists across requests within same isolate).
|
|
69
72
|
// Include routerId so multi-router setups (host routing) don't share cached
|
|
70
73
|
// EntryData across routers with overlapping mountIndex + routeKey combinations.
|
|
74
|
+
// routeKey is in the key because loadManifest() builds a manifest pruned to
|
|
75
|
+
// forRoute=routeKey (see path-helper.ts) — see the cache comment above.
|
|
71
76
|
const cacheKey = `${VERSION}:${entry.routerId ?? ""}:${mountIndex ?? ""}:${routeKey}:${isSSR ? 1 : 0}`;
|
|
72
77
|
const cached = manifestModuleCache.get(cacheKey);
|
|
73
78
|
if (cached) {
|
|
@@ -77,10 +82,14 @@ export async function loadManifest(
|
|
|
77
82
|
Store.mountIndex = mountIndex;
|
|
78
83
|
Store.isSSR = isSSR;
|
|
79
84
|
if (metricsStore) Store.metrics = metricsStore;
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
// Alias the request-scoped Store to the cached Map instead of copying it
|
|
86
|
+
// entry-by-entry. At request time this Store is throwaway (no ambient
|
|
87
|
+
// RangoContext store spans classify->match->render, so getOrCreateStore
|
|
88
|
+
// returns a fresh detached store here), so nothing mutates it in place after
|
|
89
|
+
// loadManifest returns. The fresh path below REASSIGNS Store.manifest rather
|
|
90
|
+
// than clearing it in place, so a later fresh load sharing this Store cannot
|
|
91
|
+
// poison the cached Map.
|
|
92
|
+
Store.manifest = cached;
|
|
84
93
|
pushMetric?.("manifest:cache-hit", cacheStart);
|
|
85
94
|
return cached.get(routeKey)!;
|
|
86
95
|
}
|
|
@@ -88,22 +97,21 @@ export async function loadManifest(
|
|
|
88
97
|
const storeSetupStart = performance.now();
|
|
89
98
|
const Store = getContext().getOrCreateStore(routeKey);
|
|
90
99
|
|
|
91
|
-
// Set mount index in store for unique shortCode prefixes
|
|
92
100
|
Store.mountIndex = mountIndex;
|
|
93
|
-
|
|
94
|
-
// Set isSSR flag so loading() can check if we're in SSR
|
|
95
101
|
Store.isSSR = isSSR;
|
|
96
102
|
|
|
97
|
-
// Attach metrics store to context if provided
|
|
98
103
|
if (metricsStore) {
|
|
99
104
|
Store.metrics = metricsStore;
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
pushMetric?.("manifest:store-setup", storeSetupStart);
|
|
103
108
|
|
|
104
|
-
// Clear manifest before rebuilding to prevent stale entry mutations
|
|
105
109
|
const clearStart = performance.now();
|
|
106
|
-
|
|
110
|
+
// Reassign rather than clear() in place: a prior cache-hit may have aliased
|
|
111
|
+
// Store.manifest to a shared module-cache Map (see cache-hit branch above),
|
|
112
|
+
// and clearing it in place would poison that cache. A fresh Map isolates this
|
|
113
|
+
// build; the cache still receives an independent copy at the end.
|
|
114
|
+
Store.manifest = new Map();
|
|
107
115
|
pushMetric?.("manifest:clear", clearStart);
|
|
108
116
|
|
|
109
117
|
try {
|
|
@@ -174,9 +182,35 @@ export async function loadManifest(
|
|
|
174
182
|
// not exist in the non-lazy (root handler) path and would produce
|
|
175
183
|
// mismatched shortCodes.
|
|
176
184
|
if (entry.lazy && entry.lazyPatterns) {
|
|
185
|
+
// Resolve an async include provider (`() => import("./routes")`) before
|
|
186
|
+
// running its handler. The match-time precomputed shortcut can skip
|
|
187
|
+
// evaluateLazyEntry's resolution, so render-time must resolve it here;
|
|
188
|
+
// cache the resolved patterns on the entry so later renders reuse them.
|
|
189
|
+
if (isIncludeProvider(entry.lazyPatterns)) {
|
|
190
|
+
try {
|
|
191
|
+
entry.lazyPatterns = resolveIncludeModule(
|
|
192
|
+
await entry.lazyPatterns(),
|
|
193
|
+
entry.staticPrefix,
|
|
194
|
+
) as unknown as UrlPatterns<any>;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
// A failed dynamic import of a REAL, matched route's module is a
|
|
197
|
+
// server error, not a missing route. Tag it so the outer catch
|
|
198
|
+
// surfaces it as a 5xx instead of masking it as a
|
|
199
|
+
// RouteNotFoundError — which renders the 404 page (monitoring
|
|
200
|
+
// misses the failure and a CDN could cache the 404).
|
|
201
|
+
if (err && typeof err === "object") {
|
|
202
|
+
(err as Record<PropertyKey, unknown>)[MODULE_LOAD_FAILURE] =
|
|
203
|
+
true;
|
|
204
|
+
}
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
177
208
|
const lazyPatterns = entry.lazyPatterns as UrlPatterns<any>;
|
|
178
209
|
const includePrefix = (entry as any)._lazyPrefix || "";
|
|
179
|
-
|
|
210
|
+
// Slash-collapsing join so a trailing-slash parent prefix does not
|
|
211
|
+
// bake a double slash into the registered route patterns (must match
|
|
212
|
+
// the same join in evaluateLazyEntry / the build-time runWithPrefixes).
|
|
213
|
+
const fullPrefix = joinPrefix(lazyContext?.urlPrefix, includePrefix);
|
|
180
214
|
|
|
181
215
|
if (fullPrefix || lazyContext?.namePrefix) {
|
|
182
216
|
return runWithPrefixes(fullPrefix, lazyContext?.namePrefix, () =>
|
|
@@ -186,28 +220,19 @@ export async function loadManifest(
|
|
|
186
220
|
return lazyPatterns.handler();
|
|
187
221
|
}
|
|
188
222
|
|
|
189
|
-
// Wrap handler execution in root layout so routes get correct parent
|
|
190
|
-
// This ensures all routes are registered with the layout as their parent
|
|
191
223
|
let promiseResult: Promise<any> | null = null;
|
|
192
224
|
const wrappedItems = helpers.layout(MapRootLayout, () => {
|
|
193
225
|
const result = entry.handler();
|
|
194
226
|
if (result instanceof Promise) {
|
|
195
|
-
// Lazy handler detected - capture promise for async handling
|
|
196
227
|
promiseResult = result;
|
|
197
|
-
return [];
|
|
228
|
+
return [];
|
|
198
229
|
}
|
|
199
230
|
return result;
|
|
200
231
|
});
|
|
201
232
|
|
|
202
|
-
// Handle lazy (Promise-based) handlers
|
|
203
233
|
if (promiseResult !== null) {
|
|
204
234
|
const load = await (promiseResult as Promise<any>);
|
|
205
|
-
if (
|
|
206
|
-
load &&
|
|
207
|
-
load !== null &&
|
|
208
|
-
typeof load === "object" &&
|
|
209
|
-
"default" in load
|
|
210
|
-
) {
|
|
235
|
+
if (load && typeof load === "object" && "default" in load) {
|
|
211
236
|
// Promise<{ default: () => Array }> - e.g., dynamic import
|
|
212
237
|
if (typeof load.default !== "function") {
|
|
213
238
|
throw new Error(
|
|
@@ -233,7 +258,6 @@ export async function loadManifest(
|
|
|
233
258
|
);
|
|
234
259
|
}
|
|
235
260
|
|
|
236
|
-
// Inline handler - routes were registered with correct parent inside layout
|
|
237
261
|
return [wrappedItems].flat(3);
|
|
238
262
|
},
|
|
239
263
|
);
|
|
@@ -266,6 +290,16 @@ export async function loadManifest(
|
|
|
266
290
|
|
|
267
291
|
return Store.manifest.get(routeKey)!;
|
|
268
292
|
} catch (e) {
|
|
293
|
+
// A tagged async-include module-load failure is a server error for a REAL
|
|
294
|
+
// matched route — re-raise it unchanged (becomes a 5xx) instead of masking
|
|
295
|
+
// it as a RouteNotFoundError (which renders/caches a 404).
|
|
296
|
+
if (
|
|
297
|
+
e &&
|
|
298
|
+
typeof e === "object" &&
|
|
299
|
+
(e as Record<PropertyKey, unknown>)[MODULE_LOAD_FAILURE]
|
|
300
|
+
) {
|
|
301
|
+
throw e;
|
|
302
|
+
}
|
|
269
303
|
throw new RouteNotFoundError(
|
|
270
304
|
`Failed to load route handlers for ${path}: ${(e as Error).message}`,
|
|
271
305
|
{
|
package/src/router/match-api.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Match API
|
|
3
|
-
*
|
|
4
|
-
* Extracted from createRouter closure. Contains match context creation functions
|
|
5
|
-
* and the matchError function for error boundary resolution.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import { CacheScope, createCacheScope } from "../cache/cache-scope.js";
|
|
9
2
|
import { RouteNotFoundError } from "../errors";
|
|
10
3
|
import {
|
|
@@ -33,6 +26,7 @@ import type { MatchContext } from "./match-context.js";
|
|
|
33
26
|
import type { MatchApiDeps, ActionContext } from "./types.js";
|
|
34
27
|
import {
|
|
35
28
|
getRequestContext,
|
|
29
|
+
_getRequestContext,
|
|
36
30
|
setRequestContextPrevRouteKey,
|
|
37
31
|
} from "../server/request-context.js";
|
|
38
32
|
import { isAutoGeneratedRouteName } from "../route-name.js";
|
|
@@ -54,44 +48,74 @@ export async function createMatchContextForFull<TEnv>(
|
|
|
54
48
|
deps: MatchApiDeps<TEnv>,
|
|
55
49
|
findInterceptForRoute: MatchApiDeps<TEnv>["findInterceptForRoute"],
|
|
56
50
|
): Promise<MatchContext<TEnv> | { type: "redirect"; redirectUrl: string }> {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
51
|
+
const reqCtx = _getRequestContext();
|
|
52
|
+
const cleanUrl = reqCtx?.url ?? stripInternalParams(new URL(request.url));
|
|
53
|
+
const pathname = cleanUrl.pathname;
|
|
59
54
|
|
|
60
55
|
const metricsStore = deps.getMetricsStore();
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
const isHmr = !!request.headers.get("X-RSC-HMR");
|
|
58
|
+
// HMR: clear the manifest cache so stale handler references are discarded.
|
|
59
|
+
if (isHmr) {
|
|
60
|
+
clearManifestCache();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Reuse the snapshot classifyRequest already resolved when it is a full-render
|
|
64
|
+
// snapshot (isSSR:true) and HMR has not invalidated it — mirrors the partial
|
|
65
|
+
// path. A partial-mode snapshot (isSSR:false) carries the wrong loading()
|
|
66
|
+
// entries and lives in a different manifest partition, so it is NOT reusable.
|
|
67
|
+
const classified = reqCtx?._classifiedRoute;
|
|
68
|
+
const classifiedRoute =
|
|
69
|
+
!isHmr && classified?.isSSR === true ? classified : undefined;
|
|
70
|
+
|
|
71
|
+
// On the reuse path, findMatch + manifest-loading already ran during
|
|
72
|
+
// classifyRequest (which carries no metricsStore), so only the cheap
|
|
73
|
+
// entries/cacheScope materialization is timed here under a distinct label. On
|
|
74
|
+
// the fresh path, resolveRoute emits route-matching + manifest-loading as usual.
|
|
75
|
+
const routeMatchStart = metricsStore ? performance.now() : 0;
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
let snapshot: RouteSnapshot<TEnv>;
|
|
78
|
+
if (classifiedRoute && classifiedRoute.manifestEntry) {
|
|
79
|
+
snapshot = ensureFullRouteSnapshot(classifiedRoute);
|
|
80
|
+
if (metricsStore) {
|
|
81
|
+
metricsStore.metrics.push({
|
|
82
|
+
label: "route-matching:reuse",
|
|
83
|
+
duration: performance.now() - routeMatchStart,
|
|
84
|
+
startTime: routeMatchStart - metricsStore.requestStart,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const result = await resolveRoute<TEnv>(pathname, {
|
|
89
|
+
findMatch: (p) => deps.findMatch(p, metricsStore),
|
|
90
|
+
metricsStore,
|
|
91
|
+
isSSR: true,
|
|
73
92
|
});
|
|
74
|
-
}
|
|
75
93
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
94
|
+
if (!result) {
|
|
95
|
+
throw new RouteNotFoundError(`No route matched for ${pathname}`, {
|
|
96
|
+
cause: { pathname, method: request.method },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (result.type === "redirect") {
|
|
101
|
+
// Preserve the raw query string (including internal _rsc* params) on the
|
|
102
|
+
// redirect target, matching the pre-reuse behavior of `url.search`.
|
|
103
|
+
const rawSearch = (reqCtx?.originalUrl ?? new URL(request.url)).search;
|
|
104
|
+
return {
|
|
105
|
+
type: "redirect",
|
|
106
|
+
redirectUrl: result.redirectTo + rawSearch,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
82
109
|
|
|
83
|
-
|
|
110
|
+
snapshot = result.snapshot;
|
|
111
|
+
}
|
|
84
112
|
|
|
85
113
|
const { matched } = snapshot;
|
|
86
114
|
|
|
87
|
-
// Backward compat: downstream middleware reads matched.pt
|
|
88
115
|
if (snapshot.isPassthrough) {
|
|
89
116
|
matched.pt = true;
|
|
90
117
|
}
|
|
91
118
|
|
|
92
|
-
// Clean URL without internal _rsc* params for userland access
|
|
93
|
-
const cleanUrl = stripInternalParams(url);
|
|
94
|
-
|
|
95
119
|
const handlerContext = createHandlerContext(
|
|
96
120
|
matched.params,
|
|
97
121
|
request,
|
|
@@ -175,8 +199,13 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
175
199
|
findInterceptForRoute: MatchApiDeps<TEnv>["findInterceptForRoute"],
|
|
176
200
|
actionContext?: ActionContext,
|
|
177
201
|
): Promise<MatchContext<TEnv> | null> {
|
|
178
|
-
const
|
|
179
|
-
|
|
202
|
+
const reqCtx = _getRequestContext();
|
|
203
|
+
// resolveNavigation needs the raw URL (reads internal _rsc_segments /
|
|
204
|
+
// _rsc_stale params that stripInternalParams removes); the clean URL feeds the
|
|
205
|
+
// handler context. Both come off the request context when present.
|
|
206
|
+
const rawUrl = reqCtx?.originalUrl ?? new URL(request.url);
|
|
207
|
+
const cleanUrl = reqCtx?.url ?? stripInternalParams(rawUrl);
|
|
208
|
+
const pathname = cleanUrl.pathname;
|
|
180
209
|
|
|
181
210
|
const metricsStore = deps.getMetricsStore();
|
|
182
211
|
|
|
@@ -188,11 +217,13 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
188
217
|
}
|
|
189
218
|
|
|
190
219
|
// Reuse the classified snapshot when available and not invalidated by HMR.
|
|
191
|
-
// classifyRequest
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
220
|
+
// classifyRequest resolves a partial request with isSSR=false, matching this
|
|
221
|
+
// path. Never reuse an isSSR:true (full-render) snapshot — its loading()
|
|
222
|
+
// entries and manifest partition are wrong here. On HMR, discard to pick up
|
|
223
|
+
// manifest changes.
|
|
224
|
+
const classified = reqCtx?._classifiedRoute;
|
|
225
|
+
const classifiedRoute =
|
|
226
|
+
!isHmr && classified?.isSSR !== true ? classified : undefined;
|
|
196
227
|
|
|
197
228
|
// Time route matching. On the reuse path, only nav findMatch calls are new
|
|
198
229
|
// (current-route findMatch and manifest-loading were already timed during
|
|
@@ -231,18 +262,13 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
231
262
|
matched.pt = true;
|
|
232
263
|
}
|
|
233
264
|
|
|
234
|
-
|
|
235
|
-
const nav = resolveNavigation(request, url, matched.routeKey, {
|
|
265
|
+
const nav = await resolveNavigation(request, rawUrl, matched.routeKey, {
|
|
236
266
|
findMatch: deps.findMatch,
|
|
237
267
|
});
|
|
238
268
|
if (!nav) {
|
|
239
269
|
return null;
|
|
240
270
|
}
|
|
241
271
|
|
|
242
|
-
// Push route-matching metric. On the fresh path this covers all findMatch
|
|
243
|
-
// calls (current + prev + intercept-source). On the reuse path, current-route
|
|
244
|
-
// findMatch was already timed during classification, so this only covers
|
|
245
|
-
// the nav lookups (prev + intercept-source).
|
|
246
272
|
if (metricsStore) {
|
|
247
273
|
const isReuse = !!classifiedRoute;
|
|
248
274
|
metricsStore.metrics.push({
|
|
@@ -259,9 +285,6 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
259
285
|
});
|
|
260
286
|
}
|
|
261
287
|
|
|
262
|
-
// Clean URL without internal _rsc* params for userland access
|
|
263
|
-
const cleanUrl = stripInternalParams(url);
|
|
264
|
-
|
|
265
288
|
const handlerContext = createHandlerContext(
|
|
266
289
|
matched.params,
|
|
267
290
|
request,
|
|
@@ -304,10 +327,11 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
304
327
|
});
|
|
305
328
|
}
|
|
306
329
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
330
|
+
setRequestContextPrevRouteKey(
|
|
331
|
+
nav.effectiveFromMatch?.routeKey,
|
|
332
|
+
nav.effectiveFromUrl,
|
|
333
|
+
nav.effectiveFromMatch?.params ?? nav.prevParams,
|
|
334
|
+
);
|
|
311
335
|
|
|
312
336
|
const interceptSelectorContext: InterceptSelectorContext = {
|
|
313
337
|
from: nav.effectiveFromUrl,
|
|
@@ -420,7 +444,7 @@ export async function matchError<TEnv>(
|
|
|
420
444
|
|
|
421
445
|
debugLog("matchError", "matching error", { pathname });
|
|
422
446
|
|
|
423
|
-
const matched = deps.findMatch(pathname);
|
|
447
|
+
const matched = await deps.findMatch(pathname);
|
|
424
448
|
if (!matched) {
|
|
425
449
|
debugWarn("matchError", "no route matched", { pathname });
|
|
426
450
|
return null;
|
|
@@ -242,25 +242,3 @@ export function createPipelineState(): MatchPipelineState {
|
|
|
242
242
|
slots: {},
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Input parameters for createMatchContext
|
|
248
|
-
*/
|
|
249
|
-
export interface CreateMatchContextInput<TEnv = any> {
|
|
250
|
-
request: Request;
|
|
251
|
-
env: TEnv;
|
|
252
|
-
actionContext?: ActionContext;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Result from createMatchContext - either a context or null (fall back to full match)
|
|
257
|
-
*/
|
|
258
|
-
export type CreateMatchContextResult<TEnv = any> =
|
|
259
|
-
| { type: "context"; ctx: MatchContext<TEnv> }
|
|
260
|
-
| { type: "fallback"; reason: string }
|
|
261
|
-
| { type: "error"; error: Error };
|
|
262
|
-
|
|
263
|
-
// Note: createMatchContext() will be implemented in Step J10 when we wire everything together.
|
|
264
|
-
// It requires access to RouterContext (findMatch, loadManifest, etc.) which are closure
|
|
265
|
-
// functions from createRouter(). The implementation will live in router.ts initially
|
|
266
|
-
// and call getRouterContext() to access these dependencies.
|