@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
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Negotiation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Pure functions for HTTP Accept header parsing and response type matching.
|
|
5
|
+
* Used by previewMatch and classifyRequest for content negotiation between
|
|
6
|
+
* RSC routes and response routes (JSON, text, image, stream, etc.).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { EntryData } from "../server/context.js";
|
|
10
|
+
import type { NegotiateVariant } from "../build/route-trie.js";
|
|
11
|
+
import type { CollectedMiddleware } from "./middleware-types.js";
|
|
12
|
+
import { collectRouteMiddleware } from "./middleware.js";
|
|
13
|
+
import { loadManifest } from "./manifest.js";
|
|
14
|
+
import { traverseBack } from "./pattern-matching.js";
|
|
15
|
+
import type { RouteMatchResult } from "./pattern-matching.js";
|
|
16
|
+
import type { RouteSnapshot } from "./route-snapshot.js";
|
|
17
|
+
|
|
18
|
+
export const RESPONSE_TYPE_MIME: Record<string, string> = {
|
|
19
|
+
json: "application/json",
|
|
20
|
+
text: "text/plain",
|
|
21
|
+
xml: "application/xml",
|
|
22
|
+
html: "text/html",
|
|
23
|
+
md: "text/markdown",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const MIME_RESPONSE_TYPE: Record<string, string> = Object.fromEntries(
|
|
27
|
+
Object.entries(RESPONSE_TYPE_MIME).map(([tag, mime]) => [mime, tag]),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export type NamedRouteEntry =
|
|
31
|
+
| string
|
|
32
|
+
| { path: string; search?: Record<string, string> };
|
|
33
|
+
|
|
34
|
+
export function flattenNamedRoutes(
|
|
35
|
+
routeNames?: Record<string, NamedRouteEntry>,
|
|
36
|
+
): Record<string, string> {
|
|
37
|
+
if (!routeNames) return {};
|
|
38
|
+
const flattened: Record<string, string> = {};
|
|
39
|
+
for (const [name, entry] of Object.entries(routeNames)) {
|
|
40
|
+
flattened[name] = typeof entry === "string" ? entry : entry.path;
|
|
41
|
+
}
|
|
42
|
+
return flattened;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AcceptEntry {
|
|
46
|
+
mime: string;
|
|
47
|
+
q: number;
|
|
48
|
+
order: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Parse an Accept header into a sorted array of MIME entries.
|
|
53
|
+
* Respects q-values (default 1.0) and uses client order as tiebreaker
|
|
54
|
+
* when q-values are equal (matching Express/Hono behavior).
|
|
55
|
+
*/
|
|
56
|
+
export function parseAcceptTypes(accept: string): AcceptEntry[] {
|
|
57
|
+
const entries: AcceptEntry[] = [];
|
|
58
|
+
const parts = accept.split(",");
|
|
59
|
+
for (let i = 0; i < parts.length; i++) {
|
|
60
|
+
const part = parts[i]!;
|
|
61
|
+
const segments = part.split(";");
|
|
62
|
+
const mime = segments[0]!.trim().toLowerCase();
|
|
63
|
+
if (!mime) continue;
|
|
64
|
+
let q = 1.0;
|
|
65
|
+
for (let j = 1; j < segments.length; j++) {
|
|
66
|
+
const param = segments[j]!.trim();
|
|
67
|
+
if (param.startsWith("q=")) {
|
|
68
|
+
q = Math.max(0, Math.min(1, Number(param.slice(2)) || 0));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
entries.push({ mime, q, order: i });
|
|
72
|
+
}
|
|
73
|
+
entries.sort((a, b) => b.q - a.q || a.order - b.order);
|
|
74
|
+
return entries;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const RSC_RESPONSE_TYPE = "__rsc__";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Pick the best negotiate variant by walking the client's sorted Accept list.
|
|
81
|
+
* For each accepted MIME type (in q-value/order priority), check if any
|
|
82
|
+
* candidate serves that type. Wildcards match the first candidate.
|
|
83
|
+
* Falls back to the first candidate if nothing matches.
|
|
84
|
+
*/
|
|
85
|
+
export function pickNegotiateVariant<
|
|
86
|
+
T extends { routeKey: string; responseType: string },
|
|
87
|
+
>(acceptEntries: AcceptEntry[], candidates: T[]): T {
|
|
88
|
+
const byCandidateMime = new Map<string, T>();
|
|
89
|
+
for (const c of candidates) {
|
|
90
|
+
const mime =
|
|
91
|
+
c.responseType === RSC_RESPONSE_TYPE
|
|
92
|
+
? "text/html"
|
|
93
|
+
: RESPONSE_TYPE_MIME[c.responseType];
|
|
94
|
+
if (mime && !byCandidateMime.has(mime)) {
|
|
95
|
+
byCandidateMime.set(mime, c);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const entry of acceptEntries) {
|
|
100
|
+
if (entry.q === 0) continue;
|
|
101
|
+
if (entry.mime === "*/*") return candidates[0]!;
|
|
102
|
+
if (entry.mime.endsWith("/*")) {
|
|
103
|
+
const typePrefix = entry.mime.slice(0, entry.mime.indexOf("/"));
|
|
104
|
+
for (const [mime, candidate] of byCandidateMime) {
|
|
105
|
+
if (mime.startsWith(typePrefix + "/")) return candidate;
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const match = byCandidateMime.get(entry.mime);
|
|
110
|
+
if (match) return match;
|
|
111
|
+
}
|
|
112
|
+
return candidates[0]!;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Re-key params from the primary leaf's names to a winning variant's names.
|
|
117
|
+
*
|
|
118
|
+
* The trie match builds `params` positionally under the primary leaf's pa, so
|
|
119
|
+
* `/widgets/:id` matched as the primary yields `{ id }` even when the winning
|
|
120
|
+
* `/widgets/:file` response variant expects `{ file }`. Both share the same trie
|
|
121
|
+
* terminal, so they bind the same number of positional named params; we zip the
|
|
122
|
+
* variant's pa against the named values in insertion order (which is the
|
|
123
|
+
* primary's pa order). The wildcard key (`*`) is positional-independent and left
|
|
124
|
+
* untouched.
|
|
125
|
+
*
|
|
126
|
+
* Mutates `params` in place. No-op when `variantPa` is absent, when names already
|
|
127
|
+
* match (the common case), or when the positional count diverges (defensive:
|
|
128
|
+
* never corrupt params by zipping mismatched lengths).
|
|
129
|
+
*/
|
|
130
|
+
export function rekeyParamsForVariant(
|
|
131
|
+
params: Record<string, string>,
|
|
132
|
+
variantPa: string[] | undefined,
|
|
133
|
+
): void {
|
|
134
|
+
if (!variantPa || variantPa.length === 0) return;
|
|
135
|
+
|
|
136
|
+
const namedKeys: string[] = [];
|
|
137
|
+
for (const key in params) {
|
|
138
|
+
if (key !== "*") namedKeys.push(key);
|
|
139
|
+
}
|
|
140
|
+
if (namedKeys.length !== variantPa.length) return;
|
|
141
|
+
|
|
142
|
+
let identical = true;
|
|
143
|
+
for (let i = 0; i < variantPa.length; i++) {
|
|
144
|
+
if (namedKeys[i] !== variantPa[i]) {
|
|
145
|
+
identical = false;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (identical) return;
|
|
150
|
+
|
|
151
|
+
const values = namedKeys.map((k) => params[k]!);
|
|
152
|
+
for (const key of namedKeys) delete params[key];
|
|
153
|
+
for (let i = 0; i < variantPa.length; i++) {
|
|
154
|
+
params[variantPa[i]!] = values[i]!;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Result of content negotiation for a route with negotiate variants.
|
|
160
|
+
*/
|
|
161
|
+
export interface NegotiationResult {
|
|
162
|
+
/** The winning response type */
|
|
163
|
+
responseType: string;
|
|
164
|
+
/** Handler function for the winning variant */
|
|
165
|
+
handler: Function;
|
|
166
|
+
/** Manifest entry for the winning variant (may differ from primary) */
|
|
167
|
+
manifestEntry: EntryData;
|
|
168
|
+
/** Route middleware for the winning variant */
|
|
169
|
+
routeMiddleware: CollectedMiddleware[];
|
|
170
|
+
/** True when negotiation selected a variant; false for a plain response route. */
|
|
171
|
+
negotiated: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Perform content negotiation for a route with negotiate variants.
|
|
176
|
+
*
|
|
177
|
+
* Returns a NegotiationResult when a response route wins negotiation.
|
|
178
|
+
* Returns null when RSC wins or no negotiation is needed.
|
|
179
|
+
*
|
|
180
|
+
* Shared by previewMatch and classifyRequest to avoid duplicating
|
|
181
|
+
* the candidate-building and variant-loading logic.
|
|
182
|
+
*/
|
|
183
|
+
export async function negotiateRoute(
|
|
184
|
+
request: Request,
|
|
185
|
+
pathname: string,
|
|
186
|
+
snapshot: RouteSnapshot,
|
|
187
|
+
): Promise<NegotiationResult | null> {
|
|
188
|
+
const { matched, manifestEntry, routeMiddleware, responseType } = snapshot;
|
|
189
|
+
if (!matched.negotiateVariants || matched.negotiateVariants.length === 0) {
|
|
190
|
+
// No variants: a plain response route still yields a result (negotiated:false)
|
|
191
|
+
// so callers don't re-derive it; RSC routes (no responseType/handler) -> null.
|
|
192
|
+
const handler =
|
|
193
|
+
manifestEntry.type === "route" ? manifestEntry.handler : undefined;
|
|
194
|
+
if (responseType && handler) {
|
|
195
|
+
return {
|
|
196
|
+
responseType,
|
|
197
|
+
handler: handler as Function,
|
|
198
|
+
manifestEntry,
|
|
199
|
+
routeMiddleware,
|
|
200
|
+
negotiated: false,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const acceptEntries = parseAcceptTypes(request.headers.get("accept") || "");
|
|
207
|
+
|
|
208
|
+
// Variants carry the variant's own pa (positional param names); the synthetic
|
|
209
|
+
// primary/RSC candidates have none (their params are already keyed correctly).
|
|
210
|
+
const variants = matched.negotiateVariants as NegotiateVariant[];
|
|
211
|
+
let candidates: NegotiateVariant[];
|
|
212
|
+
if (responseType) {
|
|
213
|
+
candidates = [...variants, { routeKey: matched.routeKey, responseType }];
|
|
214
|
+
} else {
|
|
215
|
+
const rscCandidate = {
|
|
216
|
+
routeKey: matched.routeKey,
|
|
217
|
+
responseType: RSC_RESPONSE_TYPE,
|
|
218
|
+
};
|
|
219
|
+
candidates = matched.rscFirst
|
|
220
|
+
? [rscCandidate, ...variants]
|
|
221
|
+
: [...variants, rscCandidate];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const variant = pickNegotiateVariant(acceptEntries, candidates);
|
|
225
|
+
|
|
226
|
+
if (variant.responseType === RSC_RESPONSE_TYPE) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (responseType && variant.routeKey === matched.routeKey) {
|
|
231
|
+
return {
|
|
232
|
+
responseType,
|
|
233
|
+
handler: manifestEntry.handler as Function,
|
|
234
|
+
manifestEntry,
|
|
235
|
+
routeMiddleware,
|
|
236
|
+
negotiated: true,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
// The trie extracted params under the PRIMARY leaf's pa, but the winning
|
|
240
|
+
// variant's handler is keyed by the variant's own param names. Re-key in place
|
|
241
|
+
// so plan.route.params (and the variant middleware collected just below) see
|
|
242
|
+
// the variant's names. No-op when the variant has no pa or shares the primary's
|
|
243
|
+
// names (the common case).
|
|
244
|
+
rekeyParamsForVariant(matched.params, variant.pa);
|
|
245
|
+
const negotiateEntry = await loadManifest(
|
|
246
|
+
matched.entry,
|
|
247
|
+
variant.routeKey,
|
|
248
|
+
pathname,
|
|
249
|
+
undefined,
|
|
250
|
+
false,
|
|
251
|
+
);
|
|
252
|
+
const variantMiddleware = collectRouteMiddleware(
|
|
253
|
+
traverseBack(negotiateEntry),
|
|
254
|
+
matched.params,
|
|
255
|
+
);
|
|
256
|
+
return {
|
|
257
|
+
responseType: variant.responseType,
|
|
258
|
+
handler: negotiateEntry.handler as Function,
|
|
259
|
+
manifestEntry: negotiateEntry,
|
|
260
|
+
routeMiddleware: variantMiddleware,
|
|
261
|
+
negotiated: true,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type EntryData, getContext } from "../server/context";
|
|
2
|
+
import { serializeManifest, type SerializedManifest } from "../debug.js";
|
|
3
|
+
import { createRouteHelpers } from "../route-definition.js";
|
|
4
|
+
import MapRootLayout from "../server/root-layout.js";
|
|
5
|
+
import type { RouteEntry, TrailingSlashMode } from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build a serialized manifest from all route entries for debug inspection.
|
|
9
|
+
* Used by the `debugManifest()` method on the router instance.
|
|
10
|
+
*/
|
|
11
|
+
export async function buildDebugManifest<TEnv = any>(
|
|
12
|
+
routesEntries: RouteEntry<TEnv>[],
|
|
13
|
+
): Promise<SerializedManifest> {
|
|
14
|
+
const manifest = new Map<string, EntryData>();
|
|
15
|
+
|
|
16
|
+
for (const entry of routesEntries) {
|
|
17
|
+
const Store = {
|
|
18
|
+
manifest,
|
|
19
|
+
namespace: `debug.M${entry.mountIndex}`,
|
|
20
|
+
parent: null as EntryData | null,
|
|
21
|
+
counters: {} as Record<string, number>,
|
|
22
|
+
mountIndex: entry.mountIndex,
|
|
23
|
+
patterns: new Map<string, string>(),
|
|
24
|
+
trailingSlash: new Map<string, TrailingSlashMode>(),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
await getContext().runWithStore(
|
|
28
|
+
Store,
|
|
29
|
+
`debug.M${entry.mountIndex}`,
|
|
30
|
+
null,
|
|
31
|
+
async () => {
|
|
32
|
+
const helpers = createRouteHelpers();
|
|
33
|
+
|
|
34
|
+
// Wrap handler execution in root layout (same as loadManifest)
|
|
35
|
+
let promiseResult: Promise<any> | null = null;
|
|
36
|
+
helpers.layout(MapRootLayout, () => {
|
|
37
|
+
const result = entry.handler();
|
|
38
|
+
if (result instanceof Promise) {
|
|
39
|
+
promiseResult = result;
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (promiseResult !== null) {
|
|
46
|
+
const load = await (promiseResult as Promise<any>);
|
|
47
|
+
if (load && typeof load === "object" && "default" in load) {
|
|
48
|
+
// Promise<{ default: fn }> — e.g. dynamic import
|
|
49
|
+
if (typeof load.default !== "function") {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`[@rangojs/router] Unsupported async handler: { default } must be a function, ` +
|
|
52
|
+
`got ${typeof load.default}. Use () => import('./urls') for lazy loading.`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
load.default(helpers);
|
|
56
|
+
} else if (typeof load === "function") {
|
|
57
|
+
// Promise<fn>
|
|
58
|
+
load(helpers);
|
|
59
|
+
} else {
|
|
60
|
+
// Reject unsupported async handler results (same policy as manifest.ts)
|
|
61
|
+
throw new Error(
|
|
62
|
+
`[@rangojs/router] Unsupported async handler result (${typeof load}). ` +
|
|
63
|
+
`Lazy route handlers must resolve to a function or { default: fn }.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return serializeManifest(manifest);
|
|
72
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Router Error Handling Utilities
|
|
3
3
|
*
|
|
4
|
-
* Error boundary and not-found boundary handling for
|
|
4
|
+
* Error boundary and not-found boundary handling for Rango.
|
|
5
5
|
* Also includes the shared invokeOnError utility for error callback invocation.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -60,7 +60,7 @@ export function invokeOnError<TEnv = any>(
|
|
|
60
60
|
error: unknown,
|
|
61
61
|
phase: ErrorPhase,
|
|
62
62
|
context: InvokeOnErrorContext<TEnv>,
|
|
63
|
-
logPrefix: string = "Router"
|
|
63
|
+
logPrefix: string = "Router",
|
|
64
64
|
): void {
|
|
65
65
|
if (!onError) return;
|
|
66
66
|
|
|
@@ -74,8 +74,8 @@ export function invokeOnError<TEnv = any>(
|
|
|
74
74
|
phase,
|
|
75
75
|
request: context.request,
|
|
76
76
|
url: context.url,
|
|
77
|
-
pathname: context.url
|
|
78
|
-
method: context.request
|
|
77
|
+
pathname: context.url?.pathname,
|
|
78
|
+
method: context.request?.method,
|
|
79
79
|
routeKey: context.routeKey,
|
|
80
80
|
params: context.params,
|
|
81
81
|
segmentId: context.segmentId,
|
|
@@ -112,21 +112,15 @@ export function invokeOnError<TEnv = any>(
|
|
|
112
112
|
*/
|
|
113
113
|
export function findNearestErrorBoundary(
|
|
114
114
|
entry: EntryData | null,
|
|
115
|
-
defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler
|
|
115
|
+
defaultErrorBoundary?: ReactNode | ErrorBoundaryHandler,
|
|
116
116
|
): ReactNode | ErrorBoundaryHandler | null {
|
|
117
117
|
let current: EntryData | null = entry;
|
|
118
118
|
|
|
119
119
|
while (current) {
|
|
120
|
-
// Check if this entry has error boundaries defined
|
|
121
120
|
if (current.errorBoundary && current.errorBoundary.length > 0) {
|
|
122
|
-
// Return the last error boundary (most recently defined takes precedence)
|
|
123
121
|
return current.errorBoundary[current.errorBoundary.length - 1];
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
// Check orphan layouts for error boundaries
|
|
127
|
-
// Orphan layouts are siblings that render alongside the main route chain
|
|
128
|
-
// They can define error boundaries that catch errors from routes in the same route group
|
|
129
|
-
// Check from first to last (first sibling takes precedence as the "outer" wrapper)
|
|
130
124
|
if (current.layout && current.layout.length > 0) {
|
|
131
125
|
for (const orphan of current.layout) {
|
|
132
126
|
if (orphan.errorBoundary && orphan.errorBoundary.length > 0) {
|
|
@@ -148,16 +142,26 @@ export function findNearestErrorBoundary(
|
|
|
148
142
|
*/
|
|
149
143
|
export function findNearestNotFoundBoundary(
|
|
150
144
|
entry: EntryData | null,
|
|
151
|
-
defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler
|
|
145
|
+
defaultNotFoundBoundary?: ReactNode | NotFoundBoundaryHandler,
|
|
152
146
|
): ReactNode | NotFoundBoundaryHandler | null {
|
|
153
147
|
let current: EntryData | null = entry;
|
|
154
148
|
|
|
155
149
|
while (current) {
|
|
156
|
-
// Check if this entry has notFound boundaries defined
|
|
157
150
|
if (current.notFoundBoundary && current.notFoundBoundary.length > 0) {
|
|
158
|
-
// Return the last notFound boundary (most recently defined takes precedence)
|
|
159
151
|
return current.notFoundBoundary[current.notFoundBoundary.length - 1];
|
|
160
152
|
}
|
|
153
|
+
|
|
154
|
+
// Check orphan layouts mirroring findNearestErrorBoundary: notFoundBoundary
|
|
155
|
+
// attaches identically (onto parent.notFoundBoundary), and an orphan layout
|
|
156
|
+
// (parent=null) is reachable only via this scan. First sibling is "outer".
|
|
157
|
+
if (current.layout && current.layout.length > 0) {
|
|
158
|
+
for (const orphan of current.layout) {
|
|
159
|
+
if (orphan.notFoundBoundary && orphan.notFoundBoundary.length > 0) {
|
|
160
|
+
return orphan.notFoundBoundary[orphan.notFoundBoundary.length - 1];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
161
165
|
current = current.parent;
|
|
162
166
|
}
|
|
163
167
|
|
|
@@ -165,6 +169,37 @@ export function findNearestNotFoundBoundary(
|
|
|
165
169
|
return defaultNotFoundBoundary || null;
|
|
166
170
|
}
|
|
167
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Normalize an error's cause into a Flight-serializable shape.
|
|
174
|
+
* ErrorInfo.cause crosses the RSC serialization boundary (via
|
|
175
|
+
* LoaderDataResult.error + error-segment fallback props); a non-serializable
|
|
176
|
+
* cause (function, class instance, circular object) would make Flight
|
|
177
|
+
* serialization throw and mask the original loader error.
|
|
178
|
+
*/
|
|
179
|
+
function normalizeCause(cause: unknown): unknown {
|
|
180
|
+
if (cause == null) return undefined;
|
|
181
|
+
const t = typeof cause;
|
|
182
|
+
if (t === "string" || t === "number" || t === "boolean") return cause;
|
|
183
|
+
// The whole body is guarded: even `instanceof`/clone can run user code (a
|
|
184
|
+
// Proxy trap, a throwing getter), and this helper must never throw —
|
|
185
|
+
// throwing here would mask the original loader error it exists to protect.
|
|
186
|
+
try {
|
|
187
|
+
if (cause instanceof Error) {
|
|
188
|
+
return { name: cause.name, message: cause.message, stack: cause.stack };
|
|
189
|
+
}
|
|
190
|
+
// Prefer preserving a serializable object/array intact (Flight uses
|
|
191
|
+
// structured-clone-like semantics); fall back to a string when the value
|
|
192
|
+
// is circular, host-bound, or otherwise non-serializable.
|
|
193
|
+
return structuredClone(cause);
|
|
194
|
+
} catch {
|
|
195
|
+
try {
|
|
196
|
+
return String(cause);
|
|
197
|
+
} catch {
|
|
198
|
+
return "[unstringifiable cause]";
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
168
203
|
/**
|
|
169
204
|
* Create ErrorInfo from an error object
|
|
170
205
|
* Sanitizes error details in production
|
|
@@ -172,7 +207,7 @@ export function findNearestNotFoundBoundary(
|
|
|
172
207
|
export function createErrorInfo(
|
|
173
208
|
error: unknown,
|
|
174
209
|
segmentId: string,
|
|
175
|
-
segmentType: ErrorInfo["segmentType"]
|
|
210
|
+
segmentType: ErrorInfo["segmentType"],
|
|
176
211
|
): ErrorInfo {
|
|
177
212
|
const isDev = process.env.NODE_ENV !== "production";
|
|
178
213
|
|
|
@@ -182,7 +217,7 @@ export function createErrorInfo(
|
|
|
182
217
|
name: error.name,
|
|
183
218
|
code: (error as any).code,
|
|
184
219
|
stack: isDev ? error.stack : undefined,
|
|
185
|
-
cause: isDev ? error.cause : undefined,
|
|
220
|
+
cause: isDev ? normalizeCause(error.cause) : undefined,
|
|
186
221
|
segmentId,
|
|
187
222
|
segmentType,
|
|
188
223
|
};
|
|
@@ -205,24 +240,19 @@ export function createErrorSegment(
|
|
|
205
240
|
errorInfo: ErrorInfo,
|
|
206
241
|
fallback: ReactNode | ErrorBoundaryHandler,
|
|
207
242
|
entry: EntryData,
|
|
208
|
-
params: Record<string, string
|
|
243
|
+
params: Record<string, string>,
|
|
209
244
|
): ResolvedSegment {
|
|
210
|
-
// Determine the component to render
|
|
211
245
|
let component: ReactNode;
|
|
212
246
|
|
|
213
247
|
if (typeof fallback === "function") {
|
|
214
|
-
// ErrorBoundaryHandler - call with error info
|
|
215
248
|
const props: ErrorBoundaryFallbackProps = {
|
|
216
249
|
error: errorInfo,
|
|
217
250
|
};
|
|
218
251
|
component = fallback(props);
|
|
219
252
|
} else {
|
|
220
|
-
// Static ReactNode fallback
|
|
221
253
|
component = fallback;
|
|
222
254
|
}
|
|
223
255
|
|
|
224
|
-
// Error segment uses the same ID as the layout that has the error boundary
|
|
225
|
-
// The error boundary content replaces the layout's outlet content
|
|
226
256
|
return {
|
|
227
257
|
id: entry.shortCode,
|
|
228
258
|
namespace: entry.id,
|
|
@@ -241,7 +271,7 @@ export function createNotFoundInfo(
|
|
|
241
271
|
error: { message: string },
|
|
242
272
|
segmentId: string,
|
|
243
273
|
segmentType: NotFoundInfo["segmentType"],
|
|
244
|
-
pathname?: string
|
|
274
|
+
pathname?: string,
|
|
245
275
|
): NotFoundInfo {
|
|
246
276
|
return {
|
|
247
277
|
message: error.message,
|
|
@@ -259,19 +289,16 @@ export function createNotFoundSegment(
|
|
|
259
289
|
notFoundInfo: NotFoundInfo,
|
|
260
290
|
fallback: ReactNode | NotFoundBoundaryHandler,
|
|
261
291
|
entry: EntryData,
|
|
262
|
-
params: Record<string, string
|
|
292
|
+
params: Record<string, string>,
|
|
263
293
|
): ResolvedSegment {
|
|
264
|
-
// Determine the component to render
|
|
265
294
|
let component: ReactNode;
|
|
266
295
|
|
|
267
296
|
if (typeof fallback === "function") {
|
|
268
|
-
// NotFoundBoundaryHandler - call with props
|
|
269
297
|
const props: NotFoundBoundaryFallbackProps = {
|
|
270
298
|
notFound: notFoundInfo,
|
|
271
299
|
};
|
|
272
300
|
component = fallback(props);
|
|
273
301
|
} else {
|
|
274
|
-
// Static ReactNode fallback
|
|
275
302
|
component = fallback;
|
|
276
303
|
}
|
|
277
304
|
|