@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.140
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 +17 -0
- package/README.md +432 -7
- package/dist/bin/rango.js +2073 -213
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +7258 -2714
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +140 -67
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +329 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +487 -0
- package/skills/caching/SKILL.md +357 -25
- 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 +246 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +16 -10
- package/skills/document-cache/SKILL.md +87 -62
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +557 -79
- package/skills/host-router/SKILL.md +320 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +207 -15
- package/skills/layout/SKILL.md +146 -6
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +616 -54
- package/skills/middleware/SKILL.md +217 -37
- package/skills/migrate-nextjs/SKILL.md +611 -0
- package/skills/migrate-react-router/SKILL.md +927 -0
- package/skills/mime-routes/SKILL.md +42 -11
- package/skills/observability/SKILL.md +194 -0
- package/skills/parallel/SKILL.md +284 -3
- package/skills/ppr/SKILL.md +426 -0
- package/skills/prerender/SKILL.md +437 -52
- package/skills/rango/SKILL.md +369 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +263 -121
- package/skills/route/SKILL.md +350 -21
- package/skills/router-setup/SKILL.md +246 -33
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +126 -222
- 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 +9 -8
- package/skills/typesafety/SKILL.md +532 -103
- package/skills/use-cache/SKILL.md +367 -0
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +77 -44
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +114 -0
- 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/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +293 -202
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +385 -576
- package/src/browser/navigation-client.ts +245 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +184 -118
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +88 -0
- package/src/browser/partial-update.ts +412 -364
- package/src/browser/prefetch/cache.ts +359 -0
- package/src/browser/prefetch/fetch.ts +452 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +209 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +275 -68
- package/src/browser/react/NavigationProvider.tsx +265 -109
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +70 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +272 -60
- package/src/browser/react/location-state.ts +90 -20
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +35 -66
- package/src/browser/react/use-handle.ts +39 -126
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +39 -13
- package/src/browser/react/use-navigation.ts +53 -69
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +98 -0
- package/src/browser/react/use-search-params.ts +51 -0
- package/src/browser/react/use-segments.ts +72 -99
- package/src/browser/response-adapter.ts +164 -0
- package/src/browser/rsc-router.tsx +300 -72
- package/src/browser/scroll-restoration.ts +138 -50
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +668 -613
- package/src/browser/types.ts +223 -51
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +252 -161
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +12 -7
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +225 -42
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +105 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +812 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +144 -0
- package/src/build/route-types/router-processing.ts +695 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +223 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +60 -0
- package/src/cache/cache-policy.ts +199 -0
- package/src/cache/cache-runtime.ts +525 -0
- package/src/cache/cache-scope.ts +298 -332
- package/src/cache/cache-tag.ts +103 -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 +2500 -158
- 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 +17 -17
- package/src/cache/document-cache.ts +199 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +111 -0
- package/src/cache/index.ts +29 -35
- package/src/cache/memory-segment-store.ts +363 -30
- package/src/cache/profile-registry.ts +88 -0
- package/src/cache/read-through-swr.ts +178 -0
- package/src/cache/segment-codec.ts +248 -0
- package/src/cache/shell-cache.ts +386 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +156 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1102 -0
- package/src/client.rsc.tsx +43 -21
- package/src/client.tsx +131 -347
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +23 -4
- package/src/components/DefaultDocument.tsx +13 -3
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +106 -10
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +110 -35
- package/src/handles/MetaTags.tsx +83 -59
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +93 -0
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +44 -53
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +20 -65
- package/src/host/errors.ts +21 -30
- package/src/host/index.ts +13 -9
- package/src/host/pattern-matcher.ts +50 -79
- package/src/host/router.ts +151 -121
- package/src/host/testing.ts +45 -32
- package/src/host/types.ts +52 -11
- package/src/host/utils.ts +2 -2
- package/src/href-client.ts +192 -57
- package/src/index.rsc.ts +177 -35
- package/src/index.ts +255 -71
- package/src/internal-debug.ts +9 -2
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +31 -99
- package/src/loader.ts +30 -12
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +16 -14
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +460 -26
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +22 -77
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +88 -0
- package/src/route-definition/helpers-types.ts +505 -0
- package/src/route-definition/index.ts +54 -0
- package/src/route-definition/redirect.ts +134 -0
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-definition.ts +1 -1481
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +71 -45
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +263 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +54 -27
- package/src/router/find-match.ts +245 -0
- package/src/router/handler-context.ts +377 -125
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +59 -28
- package/src/router/lazy-includes.ts +254 -0
- package/src/router/loader-resolution.ts +421 -157
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +131 -57
- package/src/router/match-api.ts +167 -246
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +117 -93
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +123 -51
- package/src/router/match-middleware/intercept-resolution.ts +44 -43
- package/src/router/match-middleware/segment-resolution.ts +64 -22
- package/src/router/match-pipelines.ts +11 -87
- package/src/router/match-result.ts +121 -50
- package/src/router/metrics.ts +219 -28
- package/src/router/middleware-types.ts +93 -0
- package/src/router/middleware.ts +505 -441
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +311 -142
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +547 -0
- package/src/router/preview-match.ts +102 -0
- package/src/router/request-classification.ts +278 -0
- package/src/router/revalidation.ts +203 -62
- package/src/router/route-snapshot.ts +246 -0
- package/src/router/router-context.ts +45 -48
- package/src/router/router-interfaces.ts +554 -0
- package/src/router/router-options.ts +779 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +772 -0
- package/src/router/segment-resolution/helpers.ts +348 -0
- package/src/router/segment-resolution/loader-cache.ts +250 -0
- package/src/router/segment-resolution/loader-mask.ts +44 -0
- package/src/router/segment-resolution/revalidation.ts +1331 -0
- package/src/router/segment-resolution/static-store.ts +81 -0
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +25 -1354
- package/src/router/segment-wrappers.ts +292 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +261 -0
- package/src/router/telemetry.ts +377 -0
- package/src/router/timeout.ts +128 -0
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +240 -61
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +781 -2378
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +905 -1142
- package/src/rsc/helpers.ts +275 -19
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +305 -0
- package/src/rsc/manifest-init.ts +77 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +155 -0
- package/src/rsc/progressive-enhancement.ts +502 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +257 -0
- package/src/rsc/rsc-rendering.ts +337 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +439 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +95 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +99 -82
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +349 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +452 -85
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +310 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +123 -42
- package/src/server/live.ts +130 -0
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +842 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +412 -136
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +701 -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 +257 -0
- package/src/testing/generated-routes.ts +199 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -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 +357 -0
- package/src/testing/render-route.tsx +584 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -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 +40 -72
- package/src/theme/ThemeScript.tsx +12 -14
- package/src/theme/constants.ts +57 -15
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +43 -39
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +123 -0
- package/src/types/cache-types.ts +207 -0
- package/src/types/error-types.ts +132 -0
- package/src/types/global-namespace.ts +113 -0
- package/src/types/handler-context.ts +839 -0
- package/src/types/index.ts +81 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +138 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +271 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +162 -0
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +43 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +275 -0
- package/src/urls/pattern-types.ts +124 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +316 -0
- package/src/urls/urls-function.ts +80 -0
- package/src/urls.ts +1 -1341
- package/src/use-loader.tsx +406 -141
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +182 -0
- package/src/vite/discovery/discover-routers.ts +389 -0
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +467 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +161 -0
- package/src/vite/discovery/virtual-module-codegen.ts +183 -0
- package/src/vite/index.ts +23 -2255
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +303 -0
- package/src/vite/plugins/cjs-to-esm.ts +90 -0
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +118 -0
- 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/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
- package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +805 -0
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +313 -0
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +94 -0
- package/src/vite/plugins/version-plugin.ts +263 -0
- package/src/vite/plugins/virtual-entries.ts +234 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +560 -0
- package/src/vite/router-discovery.ts +1638 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +132 -0
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +15 -0
- package/src/vite/utils/package-resolution.ts +89 -0
- package/src/vite/utils/prerender-utils.ts +249 -0
- package/src/vite/utils/shared-utils.ts +269 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/react/use-client-cache.ts +0 -56
- package/src/browser/request-controller.ts +0 -164
- package/src/browser/shallow.ts +0 -35
- package/src/cache/memory-store.ts +0 -253
- package/src/handles/index.ts +0 -6
- package/src/href-context.ts +0 -33
- package/src/network-error-thrower.tsx +0 -21
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- package/src/vite/package-resolution.ts +0 -125
- package/src/vite/virtual-entries.ts +0 -114
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* Falls back to null when no match is found (caller uses regex fallback).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
TrieNode,
|
|
10
|
+
TrieLeaf,
|
|
11
|
+
NegotiateVariant,
|
|
12
|
+
} from "../build/route-trie.js";
|
|
13
|
+
import { safeDecodeURIComponent } from "./url-params.js";
|
|
9
14
|
|
|
10
15
|
export interface TrieMatchResult {
|
|
11
16
|
/** Route name */
|
|
@@ -14,10 +19,6 @@ export interface TrieMatchResult {
|
|
|
14
19
|
sp: string;
|
|
15
20
|
/** Matched route params */
|
|
16
21
|
params: Record<string, string>;
|
|
17
|
-
/** Optional param names (absent params have empty string value) */
|
|
18
|
-
optionalParams?: string[];
|
|
19
|
-
/** Ancestry shortCodes for layout pruning */
|
|
20
|
-
ancestry: string[];
|
|
21
22
|
/** Redirect target if trailing slash requires it */
|
|
22
23
|
redirectTo?: string;
|
|
23
24
|
/** Route has pre-rendered data available */
|
|
@@ -27,7 +28,7 @@ export interface TrieMatchResult {
|
|
|
27
28
|
/** Response type for non-RSC routes (json, text, image, any) */
|
|
28
29
|
responseType?: string;
|
|
29
30
|
/** Negotiate variants: response-type routes sharing this path */
|
|
30
|
-
negotiateVariants?:
|
|
31
|
+
negotiateVariants?: NegotiateVariant[];
|
|
31
32
|
/** RSC-first: RSC route was defined before response-type variants */
|
|
32
33
|
rscFirst?: true;
|
|
33
34
|
}
|
|
@@ -42,25 +43,51 @@ export function tryTrieMatch(
|
|
|
42
43
|
): TrieMatchResult | null {
|
|
43
44
|
if (!trie) return null;
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const normalizedPath = pathnameHasTrailingSlash
|
|
46
|
+
const pathnameHasTrailingSlash =
|
|
47
|
+
pathname.length > 1 && pathname.endsWith("/");
|
|
48
|
+
const normalizedPath = pathnameHasTrailingSlash
|
|
49
|
+
? pathname.slice(0, -1)
|
|
50
|
+
: pathname;
|
|
48
51
|
|
|
49
|
-
// Handle root path
|
|
50
52
|
if (normalizedPath === "" || normalizedPath === "/") {
|
|
51
53
|
if (trie.r) {
|
|
52
|
-
return validateAndBuild(
|
|
54
|
+
return validateAndBuild(
|
|
55
|
+
trie.r,
|
|
56
|
+
[],
|
|
57
|
+
undefined,
|
|
58
|
+
pathname,
|
|
59
|
+
pathnameHasTrailingSlash,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
// A root-level wildcard ("/*") matches "/" with an empty remainder, the
|
|
63
|
+
// same value the regex matcher produces for the bare prefix. Without this
|
|
64
|
+
// the trie misses, the regex fallback runs, and its no-config branch emits
|
|
65
|
+
// a corrupt slice-off redirect. The static terminal still wins above.
|
|
66
|
+
// A one-or-more catch-all (`w1`, from `:name+`) rejects this empty case.
|
|
67
|
+
if (trie.w && !trie.w.w1) {
|
|
68
|
+
return validateAndBuild(
|
|
69
|
+
trie.w,
|
|
70
|
+
[],
|
|
71
|
+
"",
|
|
72
|
+
pathname,
|
|
73
|
+
pathnameHasTrailingSlash,
|
|
74
|
+
);
|
|
53
75
|
}
|
|
54
76
|
return null;
|
|
55
77
|
}
|
|
56
78
|
|
|
57
|
-
// Remove leading slash and split
|
|
58
79
|
const segments = normalizedPath.slice(1).split("/");
|
|
59
80
|
|
|
60
|
-
|
|
61
|
-
const result = walkTrie(trie, segments, 0, {});
|
|
81
|
+
const result = walkTrie(trie, segments, 0, []);
|
|
62
82
|
if (result) {
|
|
63
|
-
return validateAndBuild(
|
|
83
|
+
return validateAndBuild(
|
|
84
|
+
result.leaf,
|
|
85
|
+
result.paramValues,
|
|
86
|
+
result.wildcardValue,
|
|
87
|
+
pathname,
|
|
88
|
+
pathnameHasTrailingSlash,
|
|
89
|
+
result.validatedParams,
|
|
90
|
+
);
|
|
64
91
|
}
|
|
65
92
|
|
|
66
93
|
return null;
|
|
@@ -68,105 +95,257 @@ export function tryTrieMatch(
|
|
|
68
95
|
|
|
69
96
|
interface WalkResult {
|
|
70
97
|
leaf: TrieLeaf;
|
|
71
|
-
|
|
98
|
+
paramValues: string[];
|
|
99
|
+
wildcardValue?: string;
|
|
100
|
+
/**
|
|
101
|
+
* For a constraint-bearing leaf (leaf.cv set), the params map that
|
|
102
|
+
* leafConstraintsPass already decoded AND validated during the walk. Carried
|
|
103
|
+
* forward so validateAndBuild reuses it instead of re-decoding paramValues and
|
|
104
|
+
* re-running constraintsSatisfied a second time on the winning leaf. Undefined
|
|
105
|
+
* for unconstrained leaves (no decode/validate happened in the walk).
|
|
106
|
+
*/
|
|
107
|
+
validatedParams?: Record<string, string>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check a leaf's constraints (leaf.cv) against already-resolved named params.
|
|
112
|
+
* Empty/undefined values are exempt (optional params that were not bound).
|
|
113
|
+
*/
|
|
114
|
+
function constraintsSatisfied(
|
|
115
|
+
leaf: TrieLeaf,
|
|
116
|
+
params: Record<string, string>,
|
|
117
|
+
): boolean {
|
|
118
|
+
if (!leaf.cv) return true;
|
|
119
|
+
for (const paramName in leaf.cv) {
|
|
120
|
+
const allowed = leaf.cv[paramName]!;
|
|
121
|
+
const value = params[paramName];
|
|
122
|
+
if (value !== undefined && value !== "" && !allowed.includes(value)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
72
127
|
}
|
|
73
128
|
|
|
74
129
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
130
|
+
* Constraint check for a candidate terminal DURING the walk. Builds the named
|
|
131
|
+
* params from positional walk values (decoded the same way validateAndBuild
|
|
132
|
+
* does) and validates leaf.cv. Returning null lets walkTrie unwind to a
|
|
133
|
+
* lower-priority sibling instead of committing to a leaf that would only be
|
|
134
|
+
* rejected post-walk — that post-walk rejection is what forced the regex
|
|
135
|
+
* fallback (and its false "trie gap" R3 warning) for perfectly valid configs.
|
|
136
|
+
*
|
|
137
|
+
* On success returns the built+validated params for a constraint-bearing leaf so
|
|
138
|
+
* walkTrie can carry them to validateAndBuild (avoiding a second decode + a
|
|
139
|
+
* second constraintsSatisfied pass on the winner); returns the shared EMPTY_PASS
|
|
140
|
+
* sentinel for an unconstrained leaf (no work was done, nothing to carry).
|
|
141
|
+
*/
|
|
142
|
+
const EMPTY_PASS: Record<string, string> = {};
|
|
143
|
+
function leafConstraintsPass(
|
|
144
|
+
leaf: TrieLeaf,
|
|
145
|
+
paramValues: string[],
|
|
146
|
+
wildcardValue: string | undefined,
|
|
147
|
+
): Record<string, string> | null {
|
|
148
|
+
if (!leaf.cv) return EMPTY_PASS;
|
|
149
|
+
const params: Record<string, string> = {};
|
|
150
|
+
if (leaf.pa) {
|
|
151
|
+
for (let i = 0; i < leaf.pa.length && i < paramValues.length; i++) {
|
|
152
|
+
params[leaf.pa[i]] = safeDecodeURIComponent(paramValues[i]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (wildcardValue !== undefined && "pn" in leaf) {
|
|
156
|
+
params[(leaf as TrieLeaf & { pn: string }).pn] =
|
|
157
|
+
safeDecodeURIComponent(wildcardValue);
|
|
158
|
+
}
|
|
159
|
+
return constraintsSatisfied(leaf, params) ? params : null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Walk the trie by segments with priority: static > suffix-param > param >
|
|
164
|
+
* wildcard (Priority 1-4 below; matches the canonical M4 ordering in
|
|
165
|
+
* docs/internal/matching-and-lazy-discovery.md).
|
|
166
|
+
* Uses backtracking to try all possible matches. Per-leaf constraints are
|
|
167
|
+
* enforced at each candidate terminal so a constraint miss backtracks to a
|
|
168
|
+
* lower-priority sibling rather than aborting the whole match.
|
|
77
169
|
*/
|
|
78
170
|
function walkTrie(
|
|
79
171
|
node: TrieNode,
|
|
80
172
|
segments: string[],
|
|
81
173
|
index: number,
|
|
82
|
-
|
|
174
|
+
paramValues: string[],
|
|
83
175
|
): WalkResult | null {
|
|
84
|
-
// All segments consumed: check for terminal
|
|
85
176
|
if (index === segments.length) {
|
|
86
177
|
if (node.r) {
|
|
87
|
-
|
|
178
|
+
const validatedParams = leafConstraintsPass(
|
|
179
|
+
node.r,
|
|
180
|
+
paramValues,
|
|
181
|
+
undefined,
|
|
182
|
+
);
|
|
183
|
+
if (validatedParams) {
|
|
184
|
+
return {
|
|
185
|
+
leaf: node.r,
|
|
186
|
+
paramValues: [...paramValues],
|
|
187
|
+
validatedParams,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// A wildcard at this node matches the bare prefix with an empty remainder
|
|
192
|
+
// (e.g. "/files" against "/files/*"), mirroring the regex matcher's `*=""`.
|
|
193
|
+
// walkTrie otherwise only reaches node.w in the index<length branch below,
|
|
194
|
+
// so without this a request to the wildcard's own prefix misses the trie
|
|
195
|
+
// and the regex fallback emits a corrupt redirect. A static terminal
|
|
196
|
+
// (node.r) still wins. A one-or-more catch-all (`w1`, from `:name+`) rejects
|
|
197
|
+
// this empty case — it requires at least one trailing segment.
|
|
198
|
+
if (node.w && !node.w.w1) {
|
|
199
|
+
const validatedParams = leafConstraintsPass(node.w, paramValues, "");
|
|
200
|
+
if (validatedParams) {
|
|
201
|
+
return {
|
|
202
|
+
leaf: node.w,
|
|
203
|
+
paramValues: [...paramValues],
|
|
204
|
+
wildcardValue: "",
|
|
205
|
+
validatedParams,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
88
208
|
}
|
|
89
209
|
return null;
|
|
90
210
|
}
|
|
91
211
|
|
|
92
212
|
const segment = segments[index];
|
|
213
|
+
const staticChild = node.s?.[segment];
|
|
93
214
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const result = walkTrie(node.s[segment], segments, index + 1, params);
|
|
215
|
+
if (staticChild) {
|
|
216
|
+
const result = walkTrie(staticChild, segments, index + 1, paramValues);
|
|
97
217
|
if (result) return result;
|
|
98
218
|
}
|
|
99
219
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
220
|
+
if (node.xp) {
|
|
221
|
+
// node.xp keys are pre-sorted longest-suffix-first at build time
|
|
222
|
+
// (route-trie.ts sortSuffixParams), so the first match is the most specific
|
|
223
|
+
// suffix: `/app.min.js` matches `:file.min.js` before `:file.js`.
|
|
224
|
+
for (const suffix in node.xp) {
|
|
225
|
+
if (segment.endsWith(suffix) && segment.length > suffix.length) {
|
|
226
|
+
const paramValue = segment.slice(0, -suffix.length);
|
|
227
|
+
paramValues.push(paramValue);
|
|
228
|
+
const result = walkTrie(
|
|
229
|
+
node.xp[suffix].c,
|
|
230
|
+
segments,
|
|
231
|
+
index + 1,
|
|
232
|
+
paramValues,
|
|
233
|
+
);
|
|
234
|
+
paramValues.pop();
|
|
235
|
+
if (result) return result;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// A required single-segment param captures 1+ chars (the regex matcher emits
|
|
241
|
+
// `([^/]+)`), so an empty path segment from a double slash (`/a//b`) must NOT
|
|
242
|
+
// bind `:s` to "". Reject it here so the trie matches the regex contract and
|
|
243
|
+
// a malformed URL 404s instead of running the handler with an empty param.
|
|
244
|
+
// The suffix-param branch above already requires `segment.length > suffix`,
|
|
245
|
+
// and node.w may legitimately be empty, so only this branch needs the guard.
|
|
246
|
+
if (node.p && segment !== "") {
|
|
247
|
+
paramValues.push(segment);
|
|
248
|
+
const result = walkTrie(node.p.c, segments, index + 1, paramValues);
|
|
249
|
+
paramValues.pop();
|
|
106
250
|
if (result) return result;
|
|
107
251
|
}
|
|
108
252
|
|
|
109
|
-
// Priority 3: Wildcard match (consumes rest)
|
|
110
253
|
if (node.w) {
|
|
111
|
-
const rest = segments
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
254
|
+
const rest = joinRemainingSegments(segments, index);
|
|
255
|
+
// A one-or-more catch-all (`w1`, from `:name+`) requires at least one
|
|
256
|
+
// non-empty trailing segment. `rest` can still be "" here on a malformed
|
|
257
|
+
// double-slash URL (e.g. `/docs//` splits to a trailing "" segment), so
|
|
258
|
+
// guard this in-path site the same way the root and base-case sites are.
|
|
259
|
+
if (!(node.w.w1 && rest === "")) {
|
|
260
|
+
const validatedParams = leafConstraintsPass(node.w, paramValues, rest);
|
|
261
|
+
if (validatedParams) {
|
|
262
|
+
return {
|
|
263
|
+
leaf: node.w,
|
|
264
|
+
paramValues: [...paramValues],
|
|
265
|
+
wildcardValue: rest,
|
|
266
|
+
validatedParams,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
116
270
|
}
|
|
117
271
|
|
|
118
272
|
return null;
|
|
119
273
|
}
|
|
120
274
|
|
|
275
|
+
function joinRemainingSegments(segments: string[], start: number): string {
|
|
276
|
+
if (start >= segments.length) return "";
|
|
277
|
+
return segments.slice(start).join("/");
|
|
278
|
+
}
|
|
279
|
+
|
|
121
280
|
/**
|
|
122
281
|
* Post-match: validate constraints and handle trailing slash logic.
|
|
282
|
+
*
|
|
283
|
+
* `validatedParams` is the params map walkTrie already decoded AND validated via
|
|
284
|
+
* leafConstraintsPass for a constraint-bearing winning leaf. When present (and
|
|
285
|
+
* non-empty) we reuse it verbatim and SKIP the second decode + the second
|
|
286
|
+
* constraintsSatisfied pass — both are byte-identical to the walk-time work.
|
|
287
|
+
* When absent (unconstrained leaf, or the root-path call sites that never walk)
|
|
288
|
+
* we still BUILD the params here (that is not redundant — they must be returned)
|
|
289
|
+
* and run constraintsSatisfied for safety; an unconstrained leaf's check is a
|
|
290
|
+
* cheap early `!leaf.cv` return.
|
|
123
291
|
*/
|
|
124
292
|
function validateAndBuild(
|
|
125
293
|
leaf: TrieLeaf,
|
|
126
|
-
|
|
294
|
+
paramValues: string[],
|
|
295
|
+
wildcardValue: string | undefined,
|
|
127
296
|
originalPathname: string,
|
|
128
297
|
pathnameHasTrailingSlash: boolean,
|
|
298
|
+
validatedParams?: Record<string, string>,
|
|
129
299
|
): TrieMatchResult | null {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
300
|
+
let params: Record<string, string>;
|
|
301
|
+
// EMPTY_PASS (the unconstrained sentinel) and undefined both mean "nothing was
|
|
302
|
+
// pre-validated"; only a populated map carried from a constraint-bearing leaf
|
|
303
|
+
// lets us skip the rebuild + re-check.
|
|
304
|
+
if (validatedParams && validatedParams !== EMPTY_PASS) {
|
|
305
|
+
params = validatedParams;
|
|
306
|
+
} else {
|
|
307
|
+
params = {};
|
|
308
|
+
if (leaf.pa) {
|
|
309
|
+
for (let i = 0; i < leaf.pa.length && i < paramValues.length; i++) {
|
|
310
|
+
params[leaf.pa[i]] = safeDecodeURIComponent(paramValues[i]);
|
|
136
311
|
}
|
|
137
312
|
}
|
|
138
|
-
}
|
|
139
313
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
314
|
+
if (wildcardValue !== undefined && "pn" in leaf) {
|
|
315
|
+
params[(leaf as TrieLeaf & { pn: string }).pn] =
|
|
316
|
+
safeDecodeURIComponent(wildcardValue);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (!constraintsSatisfied(leaf, params)) {
|
|
320
|
+
return null;
|
|
146
321
|
}
|
|
147
322
|
}
|
|
148
323
|
|
|
149
|
-
// Trailing slash handling
|
|
150
324
|
const tsMode = leaf.ts as "never" | "always" | "ignore" | undefined;
|
|
151
325
|
let redirectTo: string | undefined;
|
|
152
326
|
|
|
153
|
-
if (
|
|
327
|
+
if (
|
|
328
|
+
tsMode === "always" &&
|
|
329
|
+
!pathnameHasTrailingSlash &&
|
|
330
|
+
originalPathname !== "/"
|
|
331
|
+
) {
|
|
154
332
|
redirectTo = originalPathname + "/";
|
|
155
333
|
} else if (tsMode === "never" && pathnameHasTrailingSlash) {
|
|
156
334
|
redirectTo = originalPathname.slice(0, -1);
|
|
157
335
|
}
|
|
158
336
|
|
|
159
|
-
|
|
337
|
+
const result: TrieMatchResult = {
|
|
160
338
|
routeKey: leaf.n,
|
|
161
339
|
sp: leaf.sp,
|
|
162
340
|
params,
|
|
163
|
-
optionalParams: leaf.op,
|
|
164
|
-
ancestry: leaf.a,
|
|
165
|
-
...(redirectTo ? { redirectTo } : {}),
|
|
166
|
-
...(leaf.pr ? { pr: true } : {}),
|
|
167
|
-
...(leaf.pt ? { pt: true } : {}),
|
|
168
|
-
...(leaf.rt ? { responseType: leaf.rt } : {}),
|
|
169
|
-
...(leaf.nv ? { negotiateVariants: leaf.nv } : {}),
|
|
170
|
-
...(leaf.rf ? { rscFirst: true } : {}),
|
|
171
341
|
};
|
|
342
|
+
|
|
343
|
+
if (redirectTo) result.redirectTo = redirectTo;
|
|
344
|
+
if (leaf.pr) result.pr = true;
|
|
345
|
+
if (leaf.pt) result.pt = true;
|
|
346
|
+
if (leaf.rt) result.responseType = leaf.rt;
|
|
347
|
+
if (leaf.nv) result.negotiateVariants = leaf.nv;
|
|
348
|
+
if (leaf.rf) result.rscFirst = true;
|
|
349
|
+
|
|
350
|
+
return result;
|
|
172
351
|
}
|
package/src/router/types.ts
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ReactNode } from "react";
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
EntryData,
|
|
10
|
+
InterceptEntry,
|
|
11
|
+
InterceptSelectorContext,
|
|
12
|
+
} from "../server/context";
|
|
9
13
|
import type {
|
|
10
14
|
ErrorInfo,
|
|
11
15
|
ErrorPhase,
|
|
@@ -18,27 +22,11 @@ import type {
|
|
|
18
22
|
ShouldRevalidateFn,
|
|
19
23
|
} from "../types";
|
|
20
24
|
|
|
21
|
-
/**
|
|
22
|
-
* Result of resolving loaders with revalidation
|
|
23
|
-
* Contains both segments to render and all matched segment IDs
|
|
24
|
-
*/
|
|
25
|
-
export interface LoaderRevalidationResult {
|
|
26
|
-
segments: ResolvedSegment[];
|
|
27
|
-
matchedIds: string[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Result of resolving segments with revalidation
|
|
32
|
-
* Contains both segments to render and all matched segment IDs
|
|
33
|
-
*/
|
|
34
25
|
export interface SegmentRevalidationResult {
|
|
35
26
|
segments: ResolvedSegment[];
|
|
36
27
|
matchedIds: string[];
|
|
37
28
|
}
|
|
38
29
|
|
|
39
|
-
/**
|
|
40
|
-
* Action context type for revalidation
|
|
41
|
-
*/
|
|
42
30
|
export type ActionContext = {
|
|
43
31
|
actionId?: string;
|
|
44
32
|
actionUrl?: URL;
|
|
@@ -46,23 +34,6 @@ export type ActionContext = {
|
|
|
46
34
|
formData?: FormData;
|
|
47
35
|
};
|
|
48
36
|
|
|
49
|
-
/**
|
|
50
|
-
* Dependencies passed to segment resolution functions
|
|
51
|
-
* These are created within createRouter and passed to extracted utilities
|
|
52
|
-
*/
|
|
53
|
-
export interface RouterDependencies<TEnv> {
|
|
54
|
-
findNearestErrorBoundary: (
|
|
55
|
-
entry: EntryData | null
|
|
56
|
-
) => ReactNode | ErrorBoundaryHandler | null;
|
|
57
|
-
findNearestNotFoundBoundary: (
|
|
58
|
-
entry: EntryData | null
|
|
59
|
-
) => ReactNode | NotFoundBoundaryHandler | null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Dependencies injected from createRouter closure into extracted segment resolution functions.
|
|
64
|
-
* These are the closure-bound helpers that cannot be imported directly.
|
|
65
|
-
*/
|
|
66
37
|
export interface SegmentResolutionDeps<TEnv = any> {
|
|
67
38
|
wrapLoaderPromise: <T>(
|
|
68
39
|
promise: Promise<T>,
|
|
@@ -79,35 +50,31 @@ export interface SegmentResolutionDeps<TEnv = any> {
|
|
|
79
50
|
requestStartTime?: number;
|
|
80
51
|
},
|
|
81
52
|
) => Promise<LoaderDataResult<T>>;
|
|
82
|
-
trackHandler: <T>(
|
|
53
|
+
trackHandler: <T>(
|
|
54
|
+
promise: Promise<T>,
|
|
55
|
+
errorContext?: {
|
|
56
|
+
segmentId?: string;
|
|
57
|
+
segmentType?: string;
|
|
58
|
+
},
|
|
59
|
+
) => Promise<T>;
|
|
83
60
|
findNearestErrorBoundary: (
|
|
84
61
|
entry: EntryData | null,
|
|
85
62
|
) => ReactNode | ErrorBoundaryHandler | null;
|
|
86
63
|
findNearestNotFoundBoundary: (
|
|
87
64
|
entry: EntryData | null,
|
|
88
65
|
) => ReactNode | NotFoundBoundaryHandler | null;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
export interface InterceptResolutionDeps<TEnv = any> {
|
|
100
|
-
wrapLoaderPromise: SegmentResolutionDeps<TEnv>["wrapLoaderPromise"];
|
|
101
|
-
evaluateInterceptWhen: (
|
|
102
|
-
intercept: InterceptEntry,
|
|
103
|
-
selectorContext: InterceptSelectorContext | null,
|
|
104
|
-
isAction: boolean,
|
|
105
|
-
) => boolean;
|
|
66
|
+
notFoundComponent?: ReactNode | ((props: { pathname: string }) => ReactNode);
|
|
67
|
+
callOnError: (error: unknown, phase: ErrorPhase, context: any) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Router-level default for the per-segment `transition({ viewTransition })`
|
|
70
|
+
* flag, from createRouter({ viewTransition }). Resolved into each segment's
|
|
71
|
+
* transition config during resolution (only `false` is stamped) so the render
|
|
72
|
+
* gate reads the boundary decision off the segment on both server and client.
|
|
73
|
+
* Undefined is treated as "auto" (wrap).
|
|
74
|
+
*/
|
|
75
|
+
viewTransitionDefault?: "auto" | false;
|
|
106
76
|
}
|
|
107
77
|
|
|
108
|
-
/**
|
|
109
|
-
* Dependencies injected from createRouter closure into extracted match API functions.
|
|
110
|
-
*/
|
|
111
78
|
export interface MatchApiDeps<TEnv = any> {
|
|
112
79
|
findMatch: (pathname: string, ms?: any) => any;
|
|
113
80
|
getMetricsStore: () => any;
|
|
@@ -122,23 +89,13 @@ export interface MatchApiDeps<TEnv = any> {
|
|
|
122
89
|
getRouteMap: () => Record<string, string>;
|
|
123
90
|
}
|
|
124
91
|
|
|
125
|
-
/**
|
|
126
|
-
* Title descriptor types for template support
|
|
127
|
-
*/
|
|
128
92
|
export type TitleDescriptor =
|
|
129
93
|
| string
|
|
130
94
|
| { template: string; default: string } // For layouts - template applied to child titles
|
|
131
|
-
| { absolute: string };
|
|
95
|
+
| { absolute: string };
|
|
132
96
|
|
|
133
|
-
/**
|
|
134
|
-
* Unset descriptor to remove inherited meta
|
|
135
|
-
* Key format matches getMetaKey output: "title", "name:description", "property:og:image"
|
|
136
|
-
*/
|
|
137
97
|
export type UnsetDescriptor = { unset: string };
|
|
138
98
|
|
|
139
|
-
/**
|
|
140
|
-
* Base meta descriptor types (sync values)
|
|
141
|
-
*/
|
|
142
99
|
export type MetaDescriptorBase =
|
|
143
100
|
| { charSet: "utf-8" }
|
|
144
101
|
| { title: TitleDescriptor }
|
|
@@ -150,10 +107,6 @@ export type MetaDescriptorBase =
|
|
|
150
107
|
| UnsetDescriptor
|
|
151
108
|
| { [name: string]: unknown };
|
|
152
109
|
|
|
153
|
-
/**
|
|
154
|
-
* Meta descriptor that can be sync or async.
|
|
155
|
-
* Use Promise<MetaDescriptorBase> for streaming meta that resolves after initial render.
|
|
156
|
-
*/
|
|
157
110
|
export type MetaDescriptor = MetaDescriptorBase | Promise<MetaDescriptorBase>;
|
|
158
111
|
|
|
159
112
|
type LdJsonObject = { [Key in string]: LdJsonValue } & {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL param encode/decode at the route boundary.
|
|
3
|
+
*
|
|
4
|
+
* Extraction (decode): regex/trie matchers keep param values URL-encoded;
|
|
5
|
+
* `safeDecodeURIComponent` turns them back into raw strings so `ctx.params`
|
|
6
|
+
* matches the contract apps expect (Express/React Router/Fastify/Koa) and
|
|
7
|
+
* round-trips through reverse stay stable. Malformed %-encoding is
|
|
8
|
+
* preserved as-is so a broken URL doesn't crash matching.
|
|
9
|
+
*
|
|
10
|
+
* Reversal (encode): `encodePathSegment` escapes only what RFC 3986
|
|
11
|
+
* requires for a path segment — `/`, `?`, `#`, space, control chars,
|
|
12
|
+
* non-ASCII — and leaves pchar sub-delims (`@ : $ & + , ; =` and friends)
|
|
13
|
+
* readable. `encodeURIComponent` over-encodes for path segments, which
|
|
14
|
+
* makes generated URLs harder for humans to read in the address bar
|
|
15
|
+
* (e.g. mailbox IDs like `ivo@example.com` would become
|
|
16
|
+
* `ivo%40example.com` even though `@` is path-legal).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export function safeDecodeURIComponent(raw: string): string {
|
|
20
|
+
if (raw === "" || raw.indexOf("%") === -1) return raw;
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return raw;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const PATH_SAFE_ESCAPES: Record<string, string> = {
|
|
29
|
+
"%3A": ":",
|
|
30
|
+
"%40": "@",
|
|
31
|
+
"%24": "$",
|
|
32
|
+
"%26": "&",
|
|
33
|
+
"%2B": "+",
|
|
34
|
+
"%2C": ",",
|
|
35
|
+
"%3B": ";",
|
|
36
|
+
"%3D": "=",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function encodePathSegment(value: string): string {
|
|
40
|
+
return encodeURIComponent(value).replace(
|
|
41
|
+
/%(?:3A|40|24|26|2B|2C|3B|3D)/gi,
|
|
42
|
+
(match) => PATH_SAFE_ESCAPES[match.toUpperCase()] ?? match,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Encode a catch-all remainder: encode each `/`-separated segment but keep the
|
|
48
|
+
* separators, so `a/b c` -> `a/b%20c` (not `a%2Fb%20c`). Shared by the reverse
|
|
49
|
+
* helper and the build-time prerender substitution so both produce identical
|
|
50
|
+
* URLs. `encode` defaults to the path-safe `encodePathSegment`.
|
|
51
|
+
*/
|
|
52
|
+
export function encodePathRemainder(
|
|
53
|
+
value: string,
|
|
54
|
+
encode: (segment: string) => string = encodePathSegment,
|
|
55
|
+
): string {
|
|
56
|
+
return value.split("/").map(encode).join("/");
|
|
57
|
+
}
|