@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,12 +5,29 @@ import type {
|
|
|
5
5
|
RscPayload,
|
|
6
6
|
RscBrowserDependencies,
|
|
7
7
|
} from "./types.js";
|
|
8
|
-
import { NetworkError, isNetworkError } from "../errors.js";
|
|
8
|
+
import { NetworkError, ServerRedirect, isNetworkError } from "../errors.js";
|
|
9
9
|
import {
|
|
10
10
|
browserDebugLog,
|
|
11
|
+
debugLog,
|
|
11
12
|
isBrowserDebugEnabled,
|
|
12
13
|
startBrowserTransaction,
|
|
13
14
|
} from "./logging.js";
|
|
15
|
+
import { getRangoState } from "./rango-state.js";
|
|
16
|
+
import { isActionFenceActive } from "./action-fence.js";
|
|
17
|
+
import {
|
|
18
|
+
extractRscHeaderUrl,
|
|
19
|
+
emptyResponse,
|
|
20
|
+
handleReloadHeader,
|
|
21
|
+
teeWithCompletion,
|
|
22
|
+
isForeignRouterId,
|
|
23
|
+
} from "./response-adapter.js";
|
|
24
|
+
import {
|
|
25
|
+
buildPrefetchKey,
|
|
26
|
+
buildSourceKey,
|
|
27
|
+
consumeInflightPrefetch,
|
|
28
|
+
consumePrefetch,
|
|
29
|
+
type DecodedPrefetch,
|
|
30
|
+
} from "./prefetch/cache.js";
|
|
14
31
|
|
|
15
32
|
/**
|
|
16
33
|
* Create a navigation client for fetching RSC payloads
|
|
@@ -18,32 +35,25 @@ import {
|
|
|
18
35
|
* The client handles building URLs with RSC parameters and
|
|
19
36
|
* deserializing the response using the RSC runtime.
|
|
20
37
|
*
|
|
38
|
+
* Checks the in-memory prefetch cache before making a network request.
|
|
39
|
+
* Tries the source-scoped key first (populated when the server tagged
|
|
40
|
+
* the response as source-sensitive via `X-RSC-Prefetch-Scope: source`)
|
|
41
|
+
* and falls back to the Rango-state-keyed wildcard slot used for the
|
|
42
|
+
* common source-agnostic case.
|
|
43
|
+
*
|
|
21
44
|
* @param deps - RSC browser dependencies (createFromFetch)
|
|
22
45
|
* @returns NavigationClient instance
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```typescript
|
|
26
|
-
* import { createFromFetch } from "@vitejs/plugin-rsc/browser";
|
|
27
|
-
*
|
|
28
|
-
* const client = createNavigationClient({ createFromFetch });
|
|
29
|
-
*
|
|
30
|
-
* const payload = await client.fetchPartial({
|
|
31
|
-
* targetUrl: "/shop/products",
|
|
32
|
-
* segmentIds: ["root", "shop"],
|
|
33
|
-
* previousUrl: "/",
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
46
|
*/
|
|
37
47
|
export function createNavigationClient(
|
|
38
48
|
deps: Pick<RscBrowserDependencies, "createFromFetch">,
|
|
39
49
|
): NavigationClient {
|
|
40
|
-
|
|
41
50
|
return {
|
|
42
51
|
/**
|
|
43
52
|
* Fetch a partial RSC payload for navigation
|
|
44
53
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
54
|
+
* First checks the in-memory prefetch cache for a matching entry.
|
|
55
|
+
* If found, uses the cached response instantly. Otherwise sends
|
|
56
|
+
* current segment IDs to the server for diff-based rendering.
|
|
47
57
|
*
|
|
48
58
|
* @param options - Fetch options
|
|
49
59
|
* @returns RSC payload with segments and metadata, plus stream completion promise
|
|
@@ -59,6 +69,7 @@ export function createNavigationClient(
|
|
|
59
69
|
staleRevalidation,
|
|
60
70
|
interceptSourceUrl,
|
|
61
71
|
version,
|
|
72
|
+
routerId,
|
|
62
73
|
hmr,
|
|
63
74
|
} = options;
|
|
64
75
|
|
|
@@ -75,7 +86,8 @@ export function createNavigationClient(
|
|
|
75
86
|
});
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
// Build fetch URL with partial rendering params
|
|
89
|
+
// Build fetch URL with partial rendering params (used for both
|
|
90
|
+
// cache key lookup and actual fetch if cache misses)
|
|
79
91
|
const fetchUrl = new URL(targetUrl, window.location.origin);
|
|
80
92
|
fetchUrl.searchParams.set("_rsc_partial", "true");
|
|
81
93
|
fetchUrl.searchParams.set("_rsc_segments", segmentIds.join(","));
|
|
@@ -85,85 +97,239 @@ export function createNavigationClient(
|
|
|
85
97
|
if (version) {
|
|
86
98
|
fetchUrl.searchParams.set("_rsc_v", version);
|
|
87
99
|
}
|
|
100
|
+
if (routerId) {
|
|
101
|
+
fetchUrl.searchParams.set("_rsc_rid", routerId);
|
|
102
|
+
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
// Check completed in-memory prefetch cache before making a network
|
|
105
|
+
// request. Try the source-scoped key first (populated when the server
|
|
106
|
+
// tagged the prefetch response as source-sensitive, e.g. intercepts,
|
|
107
|
+
// or when a Link opted in with `prefetchKey=":source"`), then fall
|
|
108
|
+
// back to the wildcard slot shared across source pages.
|
|
109
|
+
// Both keys embed the Rango state, so state rotation (deploy or
|
|
110
|
+
// server-action invalidation) auto-invalidates both scopes.
|
|
111
|
+
// Skip cache for stale revalidation (needs fresh data), HMR (needs
|
|
112
|
+
// fresh modules), and intercept contexts (source-dependent responses).
|
|
113
|
+
// Suspend prefetch consumption while an action is in flight: a queued
|
|
114
|
+
// prefetch holds pre-mutation data and must not be served until the
|
|
115
|
+
// action's response decides whether anything changed.
|
|
116
|
+
const canUsePrefetch =
|
|
117
|
+
!staleRevalidation &&
|
|
118
|
+
!hmr &&
|
|
119
|
+
!interceptSourceUrl &&
|
|
120
|
+
!isActionFenceActive();
|
|
121
|
+
const rangoState = getRangoState();
|
|
122
|
+
const wildcardKey = buildPrefetchKey(rangoState, fetchUrl);
|
|
123
|
+
const cacheKey = buildSourceKey(rangoState, previousUrl, fetchUrl);
|
|
124
|
+
|
|
125
|
+
let cachedEntry: DecodedPrefetch | null = null;
|
|
126
|
+
let hitKey: string | null = null;
|
|
127
|
+
if (canUsePrefetch) {
|
|
128
|
+
cachedEntry = consumePrefetch(cacheKey);
|
|
129
|
+
if (cachedEntry) {
|
|
130
|
+
hitKey = cacheKey;
|
|
131
|
+
} else {
|
|
132
|
+
cachedEntry = consumePrefetch(wildcardKey);
|
|
133
|
+
if (cachedEntry) hitKey = wildcardKey;
|
|
134
|
+
}
|
|
93
135
|
}
|
|
94
136
|
|
|
137
|
+
let inflightEntryPromise: Promise<DecodedPrefetch | null> | null = null;
|
|
138
|
+
if (canUsePrefetch && !cachedEntry) {
|
|
139
|
+
inflightEntryPromise = consumeInflightPrefetch(cacheKey);
|
|
140
|
+
if (inflightEntryPromise) {
|
|
141
|
+
hitKey = cacheKey;
|
|
142
|
+
} else {
|
|
143
|
+
inflightEntryPromise = consumeInflightPrefetch(wildcardKey);
|
|
144
|
+
if (inflightEntryPromise) hitKey = wildcardKey;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
95
147
|
// Track when the stream completes
|
|
96
148
|
let resolveStreamComplete: () => void;
|
|
97
149
|
const streamComplete = new Promise<void>((resolve) => {
|
|
98
150
|
resolveStreamComplete = resolve;
|
|
99
151
|
});
|
|
100
152
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Validate RSC control headers on any response (fresh, cached, or
|
|
155
|
+
* in-flight). Handles version-mismatch reloads and server redirects.
|
|
156
|
+
* Returns the response unchanged when no control header is present.
|
|
157
|
+
*/
|
|
158
|
+
const validateRscHeaders = (
|
|
159
|
+
response: Response,
|
|
160
|
+
source: string,
|
|
161
|
+
): Response | Promise<Response> => {
|
|
162
|
+
// Version mismatch — server wants a full page reload
|
|
163
|
+
const reloadResult = handleReloadHeader(response, {
|
|
164
|
+
onBlocked: resolveStreamComplete,
|
|
165
|
+
onReload: (url) => {
|
|
166
|
+
if (tx) {
|
|
167
|
+
browserDebugLog(tx, `version mismatch, reloading (${source})`, {
|
|
168
|
+
reloadUrl: url,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
if (reloadResult) return reloadResult;
|
|
174
|
+
|
|
175
|
+
// Server-side redirect without state: the server returned 204 with
|
|
176
|
+
// X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
|
|
177
|
+
// to a URL rendering full HTML). Throw ServerRedirect so the
|
|
178
|
+
// navigation bridge catches it and re-navigates with _skipCache.
|
|
179
|
+
const redirect = extractRscHeaderUrl(response, "X-RSC-Redirect");
|
|
180
|
+
if (redirect === "blocked") {
|
|
181
|
+
resolveStreamComplete();
|
|
182
|
+
return emptyResponse();
|
|
183
|
+
}
|
|
184
|
+
if (redirect) {
|
|
116
185
|
if (tx) {
|
|
117
|
-
browserDebugLog(tx,
|
|
186
|
+
browserDebugLog(tx, `server redirect (${source})`, {
|
|
187
|
+
redirectUrl: redirect.url,
|
|
188
|
+
});
|
|
118
189
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return new Promise<Response>(() => {});
|
|
190
|
+
resolveStreamComplete();
|
|
191
|
+
throw new ServerRedirect(redirect.url, undefined);
|
|
122
192
|
}
|
|
123
193
|
|
|
124
|
-
|
|
125
|
-
|
|
194
|
+
// Integrity check (pre-decode): refuse a foreign app's content response
|
|
195
|
+
// before createFromFetch imports its chunks. Ordered AFTER the reload
|
|
196
|
+
// and redirect handlers — control responses are never stamped with
|
|
197
|
+
// X-RSC-Router-Id, so they are steered first and never reach here.
|
|
198
|
+
if (isForeignRouterId(response, routerId)) {
|
|
199
|
+
if (tx) {
|
|
200
|
+
browserDebugLog(tx, `router id mismatch, reloading (${source})`);
|
|
201
|
+
}
|
|
126
202
|
resolveStreamComplete();
|
|
127
|
-
|
|
203
|
+
window.location.href = targetUrl;
|
|
204
|
+
return new Promise<Response>(() => {});
|
|
128
205
|
}
|
|
129
206
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// Consume the tracking stream to detect when it closes
|
|
134
|
-
(async () => {
|
|
135
|
-
const reader = trackingStream.getReader();
|
|
207
|
+
return response;
|
|
208
|
+
};
|
|
136
209
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
210
|
+
/** Start a fresh navigation fetch (no cache / inflight hit). */
|
|
211
|
+
const doFreshFetch = (): Promise<Response> => {
|
|
212
|
+
if (tx) {
|
|
213
|
+
browserDebugLog(tx, "fetching", {
|
|
214
|
+
path: `${fetchUrl.pathname}${fetchUrl.search}`,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
140
217
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
218
|
+
return fetch(fetchUrl, {
|
|
219
|
+
// During an action's flight the state is not rotated, so the old
|
|
220
|
+
// X-Rango-State still matches the Vary-keyed HTTP-cache entry; bypass
|
|
221
|
+
// it so a genuine mid-action navigation fetches fresh instead of being
|
|
222
|
+
// served the stale prefetched bytes.
|
|
223
|
+
...(isActionFenceActive() && { cache: "no-store" as RequestCache }),
|
|
224
|
+
headers: {
|
|
225
|
+
"X-RSC-Router-Client-Path": previousUrl,
|
|
226
|
+
"X-Rango-State": getRangoState(),
|
|
227
|
+
...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
|
|
228
|
+
...(interceptSourceUrl && {
|
|
229
|
+
"X-RSC-Router-Intercept-Source": interceptSourceUrl,
|
|
230
|
+
}),
|
|
231
|
+
...(hmr && { "X-RSC-HMR": "1" }),
|
|
232
|
+
},
|
|
233
|
+
signal,
|
|
234
|
+
}).then((response) => {
|
|
235
|
+
const validated = validateRscHeaders(response, "fetch");
|
|
236
|
+
if (validated instanceof Promise) return validated;
|
|
155
237
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
238
|
+
return teeWithCompletion(
|
|
239
|
+
validated,
|
|
240
|
+
() => {
|
|
241
|
+
if (tx) browserDebugLog(tx, "stream complete");
|
|
242
|
+
resolveStreamComplete();
|
|
243
|
+
},
|
|
244
|
+
signal,
|
|
245
|
+
);
|
|
161
246
|
});
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// A warm prefetch hit returns its eagerly-decoded payload directly: the
|
|
250
|
+
// route's chunks were imported during the prefetch, so this click runs
|
|
251
|
+
// no decode and no network. Only the fresh path runs createFromFetch and
|
|
252
|
+
// resolves the local streamComplete (via doFreshFetch's teeWithCompletion
|
|
253
|
+
// and the control-header short-circuits in validateRscHeaders).
|
|
254
|
+
const freshResult = (): {
|
|
255
|
+
payload: Promise<RscPayload>;
|
|
256
|
+
streamComplete: Promise<void>;
|
|
257
|
+
} => ({
|
|
258
|
+
payload: deps.createFromFetch<RscPayload>(doFreshFetch()),
|
|
259
|
+
streamComplete,
|
|
162
260
|
});
|
|
163
261
|
|
|
262
|
+
let payloadPromise: Promise<RscPayload>;
|
|
263
|
+
let streamCompletePromise: Promise<void>;
|
|
264
|
+
// True only for a prefetch-cache hit whose stream had already fully drained
|
|
265
|
+
// (complete === true). A still-streaming hit and the fresh path stay false,
|
|
266
|
+
// so only a fully-warmed prefetch commits in a transition (no fallback flash).
|
|
267
|
+
let fullyPrefetched = false;
|
|
268
|
+
|
|
269
|
+
if (cachedEntry) {
|
|
270
|
+
if (tx) {
|
|
271
|
+
browserDebugLog(tx, "prefetch cache hit (warm)", {
|
|
272
|
+
key: hitKey,
|
|
273
|
+
wildcard: hitKey === wildcardKey,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
payloadPromise = cachedEntry.payload;
|
|
277
|
+
streamCompletePromise = cachedEntry.streamComplete;
|
|
278
|
+
// Only a hit whose stream already fully drained is "fully prefetched";
|
|
279
|
+
// a still-streaming hit must keep streaming its fallbacks like a cold load.
|
|
280
|
+
fullyPrefetched = cachedEntry.complete;
|
|
281
|
+
} else if (inflightEntryPromise) {
|
|
282
|
+
if (tx) {
|
|
283
|
+
browserDebugLog(tx, "reusing inflight prefetch", {
|
|
284
|
+
key: hitKey,
|
|
285
|
+
wildcard: hitKey === wildcardKey,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
const adoptedViaWildcard = hitKey === wildcardKey;
|
|
289
|
+
const entry = await inflightEntryPromise;
|
|
290
|
+
if (!entry) {
|
|
291
|
+
if (tx) {
|
|
292
|
+
browserDebugLog(tx, "inflight prefetch unavailable, refetching");
|
|
293
|
+
}
|
|
294
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
295
|
+
freshResult());
|
|
296
|
+
} else if (adoptedViaWildcard && entry.scope === "source") {
|
|
297
|
+
// A wildcard-adopted inflight that turned out source-scoped was
|
|
298
|
+
// built for a different source page. Discard and refetch.
|
|
299
|
+
if (tx) {
|
|
300
|
+
browserDebugLog(
|
|
301
|
+
tx,
|
|
302
|
+
"wildcard inflight turned out source-scoped, refetching",
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
306
|
+
freshResult());
|
|
307
|
+
} else {
|
|
308
|
+
payloadPromise = entry.payload;
|
|
309
|
+
streamCompletePromise = entry.streamComplete;
|
|
310
|
+
// Adopted inflight is normally still streaming (false), but read the
|
|
311
|
+
// flag in case it completed between publish and adoption.
|
|
312
|
+
fullyPrefetched = entry.complete;
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
316
|
+
freshResult());
|
|
317
|
+
}
|
|
318
|
+
|
|
164
319
|
try {
|
|
165
|
-
//
|
|
166
|
-
|
|
320
|
+
// [VT-DIAG] Gated behind INTERNAL_RANGO_DEBUG. Times how long the RSC
|
|
321
|
+
// payload ROOT takes to resolve: ~full-stream duration means the root
|
|
322
|
+
// model is not flushed early (server/runtime buffering, e.g. wrangler
|
|
323
|
+
// dev gzip); fast means the block, if any, is downstream in render.
|
|
324
|
+
const vtDebugStart = isBrowserDebugEnabled() ? performance.now() : 0;
|
|
325
|
+
const payload = await payloadPromise;
|
|
326
|
+
if (isBrowserDebugEnabled()) {
|
|
327
|
+
debugLog("[VT-DIAG] payloadResolved", {
|
|
328
|
+
ms: Math.round(performance.now() - vtDebugStart),
|
|
329
|
+
isPartial: payload.metadata?.isPartial,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
167
333
|
if (tx) {
|
|
168
334
|
browserDebugLog(tx, "response received", {
|
|
169
335
|
isPartial: payload.metadata?.isPartial,
|
|
@@ -171,7 +337,11 @@ export function createNavigationClient(
|
|
|
171
337
|
diffCount: payload.metadata?.diff?.length ?? 0,
|
|
172
338
|
});
|
|
173
339
|
}
|
|
174
|
-
return {
|
|
340
|
+
return {
|
|
341
|
+
payload,
|
|
342
|
+
streamComplete: streamCompletePromise,
|
|
343
|
+
fullyPrefetched,
|
|
344
|
+
};
|
|
175
345
|
} catch (error) {
|
|
176
346
|
// Convert network-level errors to NetworkError for proper handling
|
|
177
347
|
if (isNetworkError(error)) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A module-level handle to the active navigation store.
|
|
3
|
+
*
|
|
4
|
+
* The boot path (`rsc-router.tsx`) calls `createNavigationStore()` directly;
|
|
5
|
+
* there is no global store singleton. This handle is the live reference for
|
|
6
|
+
* code that needs the store but does not
|
|
7
|
+
* receive it by argument: the jar-divergence observer (below) and the client
|
|
8
|
+
* seat of `invalidateClientCache()` (added later).
|
|
9
|
+
*
|
|
10
|
+
* Dependency-light on purpose: it imports only `setRangoStateObserver` and the
|
|
11
|
+
* store type, so pulling it into the default root entry does not drag the
|
|
12
|
+
* navigation store into bundles that previously lacked it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { setRangoStateObserver } from "./rango-state.js";
|
|
16
|
+
import type { NavigationStore } from "./types.js";
|
|
17
|
+
|
|
18
|
+
let registeredStore: NavigationStore | null = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register the active navigation store at boot, and wire the jar-divergence
|
|
22
|
+
* observer: when a per-request cookie read detects an EXTERNAL rotation (a
|
|
23
|
+
* sibling tab, a server `Set-Cookie`, or a cookie clear), mark this tab's
|
|
24
|
+
* history cache stale. The history cache is not state-keyed, so the value
|
|
25
|
+
* rotation alone does not reach it. No broadcast, no prefetch clear, no
|
|
26
|
+
* re-rotation — the value already changed externally.
|
|
27
|
+
*/
|
|
28
|
+
export function registerNavigationStore(store: NavigationStore): void {
|
|
29
|
+
registeredStore = store;
|
|
30
|
+
setRangoStateObserver(() => {
|
|
31
|
+
registeredStore?.markHistoryCacheStale();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The active navigation store, or null before boot has registered it. */
|
|
36
|
+
export function getRegisteredStore(): NavigationStore | null {
|
|
37
|
+
return registeredStore;
|
|
38
|
+
}
|