@rangojs/router 0.0.0-experimental.79 → 0.0.0-experimental.7c7e4327
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -4
- package/README.md +301 -797
- package/dist/bin/rango.js +603 -145
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3750 -1160
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +96 -24
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +85 -6
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +228 -33
- package/skills/caching/SKILL.md +336 -19
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +110 -4
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +87 -56
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +12 -10
- package/skills/hooks/SKILL.md +73 -691
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +129 -27
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +75 -19
- package/skills/layout/SKILL.md +40 -19
- package/skills/links/SKILL.md +247 -17
- package/skills/loader/SKILL.md +248 -10
- package/skills/middleware/SKILL.md +25 -13
- package/skills/migrate-nextjs/SKILL.md +205 -20
- package/skills/migrate-react-router/SKILL.md +59 -670
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +29 -2
- package/skills/observability/SKILL.md +202 -0
- package/skills/parallel/SKILL.md +40 -10
- package/skills/ppr/SKILL.md +616 -0
- package/skills/prerender/SKILL.md +72 -60
- package/skills/rango/SKILL.md +318 -26
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +138 -49
- package/skills/route/SKILL.md +117 -9
- package/skills/router-setup/SKILL.md +44 -9
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +776 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -626
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +74 -15
- 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 +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +252 -158
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +94 -25
- package/src/browser/navigation-client.ts +144 -79
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +161 -73
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +183 -144
- package/src/browser/prefetch/cache.ts +242 -77
- package/src/browser/prefetch/fetch.ts +325 -69
- package/src/browser/prefetch/queue.ts +61 -12
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +58 -20
- package/src/browser/react/NavigationProvider.tsx +202 -120
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +145 -28
- package/src/browser/scroll-restoration.ts +37 -22
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +236 -65
- package/src/browser/types.ts +102 -9
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +203 -154
- package/src/build/generate-route-types.ts +3 -1
- package/src/build/index.ts +11 -3
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -21
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +456 -62
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +128 -51
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +13 -21
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +421 -58
- package/src/cache/cache-scope.ts +187 -96
- package/src/cache/cache-tag.ts +149 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2202 -372
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +180 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1127 -0
- package/src/client.rsc.tsx +41 -21
- package/src/client.tsx +33 -61
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- 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 +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +67 -37
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +9 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +97 -12
- package/src/index.ts +98 -14
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +78 -10
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +65 -39
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +87 -59
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +27 -42
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +82 -59
- package/src/router/loader-resolution.ts +167 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +80 -55
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +211 -165
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +69 -79
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +298 -172
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +181 -150
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +112 -67
- package/src/router/preview-match.ts +6 -2
- package/src/router/request-classification.ts +50 -69
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +115 -36
- package/src/router/router-options.ts +166 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +131 -86
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +139 -39
- package/src/router/segment-resolution/loader-mask.ts +67 -0
- package/src/router/segment-resolution/loader-snapshot.ts +251 -0
- package/src/router/segment-resolution/revalidation.ts +272 -320
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +105 -20
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -59
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +157 -71
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +291 -217
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +124 -13
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +421 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +282 -116
- package/src/rsc/shell-capture.ts +1158 -0
- package/src/rsc/shell-serve.ts +150 -0
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +53 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +350 -149
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +208 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +152 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +395 -176
- package/src/ssr/index.tsx +458 -178
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +813 -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 +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +19 -64
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -11
- package/src/urls/path-helper-types.ts +63 -17
- package/src/urls/path-helper.ts +22 -106
- package/src/urls/pattern-types.ts +72 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +98 -154
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- 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 +8 -7
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +127 -86
- 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 +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +45 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +210 -10
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +138 -27
- package/src/vite/rango.ts +236 -138
- package/src/vite/router-discovery.ts +927 -136
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- 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 +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +71 -43
- package/src/vite/utils/shared-utils.ts +142 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -8,19 +8,25 @@ import type {
|
|
|
8
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";
|
|
14
15
|
import { getRangoState } from "./rango-state.js";
|
|
16
|
+
import { isActionFenceActive } from "./action-fence.js";
|
|
15
17
|
import {
|
|
16
18
|
extractRscHeaderUrl,
|
|
17
19
|
emptyResponse,
|
|
20
|
+
handleReloadHeader,
|
|
18
21
|
teeWithCompletion,
|
|
22
|
+
isForeignRouterId,
|
|
19
23
|
} from "./response-adapter.js";
|
|
20
24
|
import {
|
|
21
25
|
buildPrefetchKey,
|
|
26
|
+
buildSourceKey,
|
|
22
27
|
consumeInflightPrefetch,
|
|
23
28
|
consumePrefetch,
|
|
29
|
+
type DecodedPrefetch,
|
|
24
30
|
} from "./prefetch/cache.js";
|
|
25
31
|
|
|
26
32
|
/**
|
|
@@ -30,8 +36,10 @@ import {
|
|
|
30
36
|
* deserializing the response using the RSC runtime.
|
|
31
37
|
*
|
|
32
38
|
* Checks the in-memory prefetch cache before making a network request.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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.
|
|
35
43
|
*
|
|
36
44
|
* @param deps - RSC browser dependencies (createFromFetch)
|
|
37
45
|
* @returns NavigationClient instance
|
|
@@ -93,38 +101,47 @@ export function createNavigationClient(
|
|
|
93
101
|
fetchUrl.searchParams.set("_rsc_rid", routerId);
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
// Check completed in-memory prefetch cache before making a network
|
|
97
|
-
//
|
|
98
|
-
//
|
|
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.
|
|
99
111
|
// Skip cache for stale revalidation (needs fresh data), HMR (needs
|
|
100
112
|
// fresh modules), and intercept contexts (source-dependent responses).
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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);
|
|
107
124
|
|
|
108
|
-
let
|
|
125
|
+
let cachedEntry: DecodedPrefetch | null = null;
|
|
109
126
|
let hitKey: string | null = null;
|
|
110
127
|
if (canUsePrefetch) {
|
|
111
|
-
|
|
112
|
-
if (
|
|
128
|
+
cachedEntry = consumePrefetch(cacheKey);
|
|
129
|
+
if (cachedEntry) {
|
|
113
130
|
hitKey = cacheKey;
|
|
114
131
|
} else {
|
|
115
|
-
|
|
116
|
-
if (
|
|
132
|
+
cachedEntry = consumePrefetch(wildcardKey);
|
|
133
|
+
if (cachedEntry) hitKey = wildcardKey;
|
|
117
134
|
}
|
|
118
135
|
}
|
|
119
136
|
|
|
120
|
-
let
|
|
121
|
-
if (canUsePrefetch && !
|
|
122
|
-
|
|
123
|
-
if (
|
|
137
|
+
let inflightEntryPromise: Promise<DecodedPrefetch | null> | null = null;
|
|
138
|
+
if (canUsePrefetch && !cachedEntry) {
|
|
139
|
+
inflightEntryPromise = consumeInflightPrefetch(cacheKey);
|
|
140
|
+
if (inflightEntryPromise) {
|
|
124
141
|
hitKey = cacheKey;
|
|
125
142
|
} else {
|
|
126
|
-
|
|
127
|
-
if (
|
|
143
|
+
inflightEntryPromise = consumeInflightPrefetch(wildcardKey);
|
|
144
|
+
if (inflightEntryPromise) hitKey = wildcardKey;
|
|
128
145
|
}
|
|
129
146
|
}
|
|
130
147
|
// Track when the stream completes
|
|
@@ -143,21 +160,17 @@ export function createNavigationClient(
|
|
|
143
160
|
source: string,
|
|
144
161
|
): Response | Promise<Response> => {
|
|
145
162
|
// Version mismatch — server wants a full page reload
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
window.location.href = reload.url;
|
|
158
|
-
// Block further processing — page is reloading
|
|
159
|
-
return new Promise<Response>(() => {});
|
|
160
|
-
}
|
|
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;
|
|
161
174
|
|
|
162
175
|
// Server-side redirect without state: the server returned 204 with
|
|
163
176
|
// X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
|
|
@@ -178,6 +191,19 @@ export function createNavigationClient(
|
|
|
178
191
|
throw new ServerRedirect(redirect.url, undefined);
|
|
179
192
|
}
|
|
180
193
|
|
|
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
|
+
}
|
|
202
|
+
resolveStreamComplete();
|
|
203
|
+
window.location.href = targetUrl;
|
|
204
|
+
return new Promise<Response>(() => {});
|
|
205
|
+
}
|
|
206
|
+
|
|
181
207
|
return response;
|
|
182
208
|
};
|
|
183
209
|
|
|
@@ -190,9 +216,18 @@ export function createNavigationClient(
|
|
|
190
216
|
}
|
|
191
217
|
|
|
192
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 }),
|
|
193
224
|
headers: {
|
|
194
225
|
"X-RSC-Router-Client-Path": previousUrl,
|
|
195
|
-
|
|
226
|
+
// Reuse the single per-operation read (see rangoState above): the
|
|
227
|
+
// cache-key lookup and this header must agree on one value, and the
|
|
228
|
+
// cookie read has side effects (external-rotation notify) we do not
|
|
229
|
+
// want to fire twice per navigation.
|
|
230
|
+
"X-Rango-State": rangoState,
|
|
196
231
|
...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
|
|
197
232
|
...(interceptSourceUrl && {
|
|
198
233
|
"X-RSC-Router-Intercept-Source": interceptSourceUrl,
|
|
@@ -215,63 +250,89 @@ export function createNavigationClient(
|
|
|
215
250
|
});
|
|
216
251
|
};
|
|
217
252
|
|
|
218
|
-
|
|
253
|
+
// A warm prefetch hit returns its eagerly-decoded payload directly: the
|
|
254
|
+
// route's chunks were imported during the prefetch, so this click runs
|
|
255
|
+
// no decode and no network. Only the fresh path runs createFromFetch and
|
|
256
|
+
// resolves the local streamComplete (via doFreshFetch's teeWithCompletion
|
|
257
|
+
// and the control-header short-circuits in validateRscHeaders).
|
|
258
|
+
const freshResult = (): {
|
|
259
|
+
payload: Promise<RscPayload>;
|
|
260
|
+
streamComplete: Promise<void>;
|
|
261
|
+
} => ({
|
|
262
|
+
payload: deps.createFromFetch<RscPayload>(doFreshFetch()),
|
|
263
|
+
streamComplete,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
let payloadPromise: Promise<RscPayload>;
|
|
267
|
+
let streamCompletePromise: Promise<void>;
|
|
268
|
+
// True only for a prefetch-cache hit whose stream had already fully drained
|
|
269
|
+
// (complete === true). A still-streaming hit and the fresh path stay false,
|
|
270
|
+
// so only a fully-warmed prefetch commits in a transition (no fallback flash).
|
|
271
|
+
let fullyPrefetched = false;
|
|
219
272
|
|
|
220
|
-
if (
|
|
273
|
+
if (cachedEntry) {
|
|
221
274
|
if (tx) {
|
|
222
|
-
browserDebugLog(tx, "prefetch cache hit", {
|
|
275
|
+
browserDebugLog(tx, "prefetch cache hit (warm)", {
|
|
223
276
|
key: hitKey,
|
|
224
277
|
wildcard: hitKey === wildcardKey,
|
|
225
278
|
});
|
|
226
279
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
() => {
|
|
234
|
-
if (tx) browserDebugLog(tx, "stream complete (from cache)");
|
|
235
|
-
resolveStreamComplete();
|
|
236
|
-
},
|
|
237
|
-
signal,
|
|
238
|
-
);
|
|
239
|
-
});
|
|
240
|
-
} else if (inflightResponsePromise) {
|
|
280
|
+
payloadPromise = cachedEntry.payload;
|
|
281
|
+
streamCompletePromise = cachedEntry.streamComplete;
|
|
282
|
+
// Only a hit whose stream already fully drained is "fully prefetched";
|
|
283
|
+
// a still-streaming hit must keep streaming its fallbacks like a cold load.
|
|
284
|
+
fullyPrefetched = cachedEntry.complete;
|
|
285
|
+
} else if (inflightEntryPromise) {
|
|
241
286
|
if (tx) {
|
|
242
287
|
browserDebugLog(tx, "reusing inflight prefetch", {
|
|
243
288
|
key: hitKey,
|
|
244
289
|
wildcard: hitKey === wildcardKey,
|
|
245
290
|
});
|
|
246
291
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return doFreshFetch();
|
|
292
|
+
const adoptedViaWildcard = hitKey === wildcardKey;
|
|
293
|
+
const entry = await inflightEntryPromise;
|
|
294
|
+
if (!entry) {
|
|
295
|
+
if (tx) {
|
|
296
|
+
browserDebugLog(tx, "inflight prefetch unavailable, refetching");
|
|
253
297
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
298
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
299
|
+
freshResult());
|
|
300
|
+
} else if (adoptedViaWildcard && entry.scope === "source") {
|
|
301
|
+
// A wildcard-adopted inflight that turned out source-scoped was
|
|
302
|
+
// built for a different source page. Discard and refetch.
|
|
303
|
+
if (tx) {
|
|
304
|
+
browserDebugLog(
|
|
305
|
+
tx,
|
|
306
|
+
"wildcard inflight turned out source-scoped, refetching",
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
310
|
+
freshResult());
|
|
311
|
+
} else {
|
|
312
|
+
payloadPromise = entry.payload;
|
|
313
|
+
streamCompletePromise = entry.streamComplete;
|
|
314
|
+
// Adopted inflight is normally still streaming (false), but read the
|
|
315
|
+
// flag in case it completed between publish and adoption.
|
|
316
|
+
fullyPrefetched = entry.complete;
|
|
317
|
+
}
|
|
269
318
|
} else {
|
|
270
|
-
|
|
319
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
320
|
+
freshResult());
|
|
271
321
|
}
|
|
272
322
|
|
|
273
323
|
try {
|
|
274
|
-
|
|
324
|
+
// [VT-DIAG] Gated behind INTERNAL_RANGO_DEBUG. Times how long the RSC
|
|
325
|
+
// payload ROOT takes to resolve: ~full-stream duration means the root
|
|
326
|
+
// model is not flushed early (server/runtime buffering, e.g. wrangler
|
|
327
|
+
// dev gzip); fast means the block, if any, is downstream in render.
|
|
328
|
+
const vtDebugStart = isBrowserDebugEnabled() ? performance.now() : 0;
|
|
329
|
+
const payload = await payloadPromise;
|
|
330
|
+
if (isBrowserDebugEnabled()) {
|
|
331
|
+
debugLog("[VT-DIAG] payloadResolved", {
|
|
332
|
+
ms: Math.round(performance.now() - vtDebugStart),
|
|
333
|
+
isPartial: payload.metadata?.isPartial,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
275
336
|
|
|
276
337
|
if (tx) {
|
|
277
338
|
browserDebugLog(tx, "response received", {
|
|
@@ -280,7 +341,11 @@ export function createNavigationClient(
|
|
|
280
341
|
diffCount: payload.metadata?.diff?.length ?? 0,
|
|
281
342
|
});
|
|
282
343
|
}
|
|
283
|
-
return {
|
|
344
|
+
return {
|
|
345
|
+
payload,
|
|
346
|
+
streamComplete: streamCompletePromise,
|
|
347
|
+
fullyPrefetched,
|
|
348
|
+
};
|
|
284
349
|
} catch (error) {
|
|
285
350
|
// Convert network-level errors to NetworkError for proper handling
|
|
286
351
|
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
|
+
}
|