@rangojs/router 0.0.0-experimental.1878aa49 → 0.0.0-experimental.190fb30d
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 +303 -741
- package/dist/bin/rango.js +605 -146
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +4117 -1211
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +86 -15
- 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 +364 -0
- 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 +94 -18
- package/skills/layout/SKILL.md +62 -19
- package/skills/links/SKILL.md +247 -17
- package/skills/loader/SKILL.md +248 -10
- package/skills/middleware/SKILL.md +57 -16
- package/skills/migrate-nextjs/SKILL.md +745 -0
- package/skills/migrate-react-router/SKILL.md +153 -0
- 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 +99 -10
- package/skills/ppr/SKILL.md +618 -0
- package/skills/prerender/SKILL.md +178 -124
- package/skills/rango/SKILL.md +318 -24
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +138 -49
- package/skills/route/SKILL.md +141 -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 +1 -66
- 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 +115 -27
- package/src/browser/navigation-client.ts +163 -70
- 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 +186 -135
- package/src/browser/prefetch/cache.ts +246 -71
- package/src/browser/prefetch/fetch.ts +350 -38
- package/src/browser/prefetch/queue.ts +61 -12
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +70 -9
- 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 +23 -69
- 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 +44 -27
- package/src/browser/segment-reconciler.ts +44 -12
- 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 +205 -159
- 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 +198 -41
- 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 +9 -2
- 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 +454 -101
- 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 +2206 -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 +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +41 -21
- package/src/client.tsx +116 -290
- 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 +104 -34
- 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 +100 -13
- package/src/index.ts +143 -19
- 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 +37 -41
- package/src/prerender.ts +215 -86
- 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 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +461 -304
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +147 -72
- package/src/route-definition/index.ts +4 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +37 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +164 -17
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +47 -22
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +85 -62
- package/src/router/loader-resolution.ts +277 -54
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +97 -57
- package/src/router/match-api.ts +178 -218
- 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 +168 -277
- 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 +45 -14
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +113 -45
- 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 +133 -0
- 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 +201 -56
- package/src/router/preview-match.ts +35 -103
- package/src/router/request-classification.ts +291 -0
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +256 -0
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +125 -35
- package/src/router/router-options.ts +166 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +188 -86
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +67 -0
- package/src/router/segment-resolution/loader-snapshot.ts +308 -0
- package/src/router/segment-resolution/revalidation.ts +344 -319
- 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 +170 -72
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +678 -513
- 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 +127 -31
- 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 +134 -15
- 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 +497 -77
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +286 -114
- package/src/rsc/shell-capture.ts +1166 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/ssr-setup.ts +17 -1
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +54 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +167 -0
- package/src/segment-system.tsx +355 -204
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +247 -54
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +152 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +502 -161
- package/src/ssr/index.tsx +467 -178
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +27 -18
- 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 +120 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +40 -10
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +12 -7
- package/src/types/segments.ts +136 -15
- package/src/urls/include-helper.ts +40 -75
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -11
- package/src/urls/path-helper-types.ts +102 -23
- package/src/urls/path-helper.ts +62 -111
- package/src/urls/pattern-types.ts +72 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +98 -154
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +346 -89
- 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 +36 -38
- 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 +214 -132
- 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 +57 -4
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +15 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +261 -6
- 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 +96 -51
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
- 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 +553 -317
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +89 -27
- 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 +238 -139
- package/src/vite/router-discovery.ts +1091 -159
- 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 +98 -38
- 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,18 +101,49 @@ 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
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
+
}
|
|
135
|
+
}
|
|
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
|
+
}
|
|
108
147
|
// Track when the stream completes
|
|
109
148
|
let resolveStreamComplete: () => void;
|
|
110
149
|
const streamComplete = new Promise<void>((resolve) => {
|
|
@@ -121,21 +160,17 @@ export function createNavigationClient(
|
|
|
121
160
|
source: string,
|
|
122
161
|
): Response | Promise<Response> => {
|
|
123
162
|
// Version mismatch — server wants a full page reload
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
window.location.href = reload.url;
|
|
136
|
-
// Block further processing — page is reloading
|
|
137
|
-
return new Promise<Response>(() => {});
|
|
138
|
-
}
|
|
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;
|
|
139
174
|
|
|
140
175
|
// Server-side redirect without state: the server returned 204 with
|
|
141
176
|
// X-RSC-Redirect instead of a 3xx (which fetch would auto-follow
|
|
@@ -156,6 +191,19 @@ export function createNavigationClient(
|
|
|
156
191
|
throw new ServerRedirect(redirect.url, undefined);
|
|
157
192
|
}
|
|
158
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
|
+
|
|
159
207
|
return response;
|
|
160
208
|
};
|
|
161
209
|
|
|
@@ -168,9 +216,18 @@ export function createNavigationClient(
|
|
|
168
216
|
}
|
|
169
217
|
|
|
170
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 }),
|
|
171
224
|
headers: {
|
|
172
225
|
"X-RSC-Router-Client-Path": previousUrl,
|
|
173
|
-
|
|
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,
|
|
174
231
|
...(tx && { "X-RSC-Router-Request-Id": tx.requestId }),
|
|
175
232
|
...(interceptSourceUrl && {
|
|
176
233
|
"X-RSC-Router-Intercept-Source": interceptSourceUrl,
|
|
@@ -193,57 +250,89 @@ export function createNavigationClient(
|
|
|
193
250
|
});
|
|
194
251
|
};
|
|
195
252
|
|
|
196
|
-
|
|
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;
|
|
197
272
|
|
|
198
|
-
if (
|
|
273
|
+
if (cachedEntry) {
|
|
199
274
|
if (tx) {
|
|
200
|
-
browserDebugLog(tx, "prefetch cache hit", {
|
|
275
|
+
browserDebugLog(tx, "prefetch cache hit (warm)", {
|
|
276
|
+
key: hitKey,
|
|
277
|
+
wildcard: hitKey === wildcardKey,
|
|
278
|
+
});
|
|
201
279
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
() => {
|
|
209
|
-
if (tx) browserDebugLog(tx, "stream complete (from cache)");
|
|
210
|
-
resolveStreamComplete();
|
|
211
|
-
},
|
|
212
|
-
signal,
|
|
213
|
-
);
|
|
214
|
-
});
|
|
215
|
-
} 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) {
|
|
216
286
|
if (tx) {
|
|
217
|
-
browserDebugLog(tx, "reusing inflight prefetch", {
|
|
287
|
+
browserDebugLog(tx, "reusing inflight prefetch", {
|
|
288
|
+
key: hitKey,
|
|
289
|
+
wildcard: hitKey === wildcardKey,
|
|
290
|
+
});
|
|
218
291
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
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");
|
|
225
297
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
+
}
|
|
241
318
|
} else {
|
|
242
|
-
|
|
319
|
+
({ payload: payloadPromise, streamComplete: streamCompletePromise } =
|
|
320
|
+
freshResult());
|
|
243
321
|
}
|
|
244
322
|
|
|
245
323
|
try {
|
|
246
|
-
|
|
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
|
+
}
|
|
247
336
|
|
|
248
337
|
if (tx) {
|
|
249
338
|
browserDebugLog(tx, "response received", {
|
|
@@ -252,7 +341,11 @@ export function createNavigationClient(
|
|
|
252
341
|
diffCount: payload.metadata?.diff?.length ?? 0,
|
|
253
342
|
});
|
|
254
343
|
}
|
|
255
|
-
return {
|
|
344
|
+
return {
|
|
345
|
+
payload,
|
|
346
|
+
streamComplete: streamCompletePromise,
|
|
347
|
+
fullyPrefetched,
|
|
348
|
+
};
|
|
256
349
|
} catch (error) {
|
|
257
350
|
// Convert network-level errors to NetworkError for proper handling
|
|
258
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
|
+
}
|