@rangojs/router 0.4.0 → 0.4.1
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/README.md +19 -1
- package/dist/types/browser/event-controller.d.ts +4 -0
- package/dist/types/browser/link-interceptor.d.ts +17 -7
- package/dist/types/browser/navigation-bridge.d.ts +13 -1
- package/dist/types/browser/notify-listeners.d.ts +2 -0
- package/dist/types/browser/prefetch/cache.d.ts +1 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +12 -3
- package/dist/types/browser/prefetch/invalidation.d.ts +6 -0
- package/dist/types/browser/prefetch/loader.d.ts +3 -1
- package/dist/types/browser/prefetch/observer.d.ts +3 -6
- package/dist/types/browser/rango-state.d.ts +4 -0
- package/dist/types/browser/react/Link.d.ts +4 -9
- package/dist/types/browser/react/context.d.ts +3 -0
- package/dist/types/browser/rsc-router.d.ts +7 -2
- package/dist/types/browser/types.d.ts +1 -0
- package/dist/types/cache/cache-key-utils.d.ts +11 -3
- package/dist/types/cache/cache-scope.d.ts +82 -3
- package/dist/types/cache/cf/cf-cache-store.d.ts +2 -2
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/search-params-filter.d.ts +64 -0
- package/dist/types/cache/shell-snapshot.d.ts +4 -4
- package/dist/types/cache/types.d.ts +30 -2
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.rsc.d.ts +1 -0
- package/dist/types/router/match-middleware/cache-lookup.d.ts +13 -0
- package/dist/types/router/navigation-snapshot.d.ts +29 -0
- package/dist/types/router/router-options.d.ts +27 -3
- package/dist/types/rsc/shell-build-manifest.d.ts +7 -1
- package/dist/types/rsc/shell-serve.d.ts +7 -1
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/request-context.d.ts +57 -4
- package/dist/types/testing/render-route.d.ts +10 -1
- package/dist/types/testing/shell-status.d.ts +6 -3
- package/dist/types/vite/plugin-types.d.ts +1 -1
- package/dist/vite/index.js +5 -5
- package/package.json +23 -22
- package/skills/caching/SKILL.md +39 -0
- package/skills/comparison/references/framework-comparison.md +7 -1
- package/skills/links/SKILL.md +24 -0
- package/skills/ppr/SKILL.md +53 -4
- package/skills/router-setup/SKILL.md +7 -2
- package/skills/testing/client-components.md +15 -14
- package/skills/vercel/SKILL.md +1 -1
- package/src/browser/event-controller.ts +110 -11
- package/src/browser/link-interceptor.ts +469 -20
- package/src/browser/navigation-bridge.ts +71 -2
- package/src/browser/navigation-store.ts +24 -1
- package/src/browser/notify-listeners.ts +22 -0
- package/src/browser/prefetch/cache.ts +4 -2
- package/src/browser/prefetch/default-strategy.ts +43 -3
- package/src/browser/prefetch/invalidation.ts +30 -0
- package/src/browser/prefetch/loader.ts +19 -12
- package/src/browser/prefetch/observer.ts +50 -22
- package/src/browser/rango-state.ts +21 -0
- package/src/browser/react/Link.tsx +97 -88
- package/src/browser/react/NavigationProvider.tsx +1 -0
- package/src/browser/react/context.ts +4 -0
- package/src/browser/rsc-router.tsx +22 -9
- package/src/browser/types.ts +1 -0
- package/src/cache/cache-key-utils.ts +18 -4
- package/src/cache/cache-runtime.ts +7 -2
- package/src/cache/cache-scope.ts +152 -23
- package/src/cache/cf/cf-cache-store.ts +51 -16
- package/src/cache/document-cache.ts +7 -1
- package/src/cache/index.ts +7 -0
- package/src/cache/search-params-filter.ts +118 -0
- package/src/cache/shell-snapshot.ts +8 -4
- package/src/cache/types.ts +33 -2
- package/src/cache/vercel/vercel-cache-store.ts +17 -3
- package/src/index.rsc.ts +4 -0
- package/src/index.ts +6 -0
- package/src/router/match-middleware/cache-lookup.ts +146 -33
- package/src/router/match-middleware/cache-store.ts +70 -0
- package/src/router/navigation-snapshot.ts +46 -6
- package/src/router/router-options.ts +31 -4
- package/src/rsc/handler.ts +9 -0
- package/src/rsc/response-cache-serve.ts +1 -1
- package/src/rsc/rsc-rendering.ts +252 -27
- package/src/rsc/shell-build-manifest.ts +8 -1
- package/src/rsc/shell-capture.ts +5 -0
- package/src/rsc/shell-serve.ts +8 -2
- package/src/rsc/types.ts +17 -0
- package/src/server/request-context.ts +62 -3
- package/src/testing/dispatch.ts +21 -3
- package/src/testing/render-route.tsx +86 -17
- package/src/testing/shell-status.ts +20 -3
- package/src/vite/plugin-types.ts +1 -1
- package/src/vite/plugins/vercel-output.ts +2 -2
- package/dist/types.backup/__internal.d.ts +0 -127
- package/dist/types.backup/bin/rango.d.ts +0 -1
- package/dist/types.backup/browser/action-coordinator.d.ts +0 -57
- package/dist/types.backup/browser/action-fence.d.ts +0 -33
- package/dist/types.backup/browser/app-shell.d.ts +0 -34
- package/dist/types.backup/browser/app-version.d.ts +0 -6
- package/dist/types.backup/browser/connection-warmup.d.ts +0 -31
- package/dist/types.backup/browser/cookie-name.d.ts +0 -66
- package/dist/types.backup/browser/event-controller.d.ts +0 -221
- package/dist/types.backup/browser/history-state.d.ts +0 -26
- package/dist/types.backup/browser/index.d.ts +0 -1
- package/dist/types.backup/browser/intercept-utils.d.ts +0 -30
- package/dist/types.backup/browser/invalidate-client-cache.d.ts +0 -17
- package/dist/types.backup/browser/link-interceptor.d.ts +0 -43
- package/dist/types.backup/browser/logging.d.ts +0 -33
- package/dist/types.backup/browser/merge-segment-loaders.d.ts +0 -38
- package/dist/types.backup/browser/navigation-bridge.d.ts +0 -27
- package/dist/types.backup/browser/navigation-client.d.ts +0 -17
- package/dist/types.backup/browser/navigation-store-handle.d.ts +0 -25
- package/dist/types.backup/browser/navigation-store.d.ts +0 -95
- package/dist/types.backup/browser/navigation-transaction.d.ts +0 -75
- package/dist/types.backup/browser/network-error-handler.d.ts +0 -35
- package/dist/types.backup/browser/partial-update.d.ts +0 -61
- package/dist/types.backup/browser/prefetch/cache.d.ts +0 -183
- package/dist/types.backup/browser/prefetch/fetch.d.ts +0 -52
- package/dist/types.backup/browser/prefetch/observer.d.ts +0 -27
- package/dist/types.backup/browser/prefetch/policy.d.ts +0 -13
- package/dist/types.backup/browser/prefetch/queue.d.ts +0 -48
- package/dist/types.backup/browser/prefetch/resource-ready.d.ts +0 -28
- package/dist/types.backup/browser/rango-state.d.ts +0 -52
- package/dist/types.backup/browser/react/Link.d.ts +0 -140
- package/dist/types.backup/browser/react/NavigationProvider.d.ts +0 -88
- package/dist/types.backup/browser/react/ScrollRestoration.d.ts +0 -78
- package/dist/types.backup/browser/react/context.d.ts +0 -54
- package/dist/types.backup/browser/react/filter-segment-order.d.ts +0 -35
- package/dist/types.backup/browser/react/index.d.ts +0 -1
- package/dist/types.backup/browser/react/location-state-shared.d.ts +0 -162
- package/dist/types.backup/browser/react/location-state.d.ts +0 -29
- package/dist/types.backup/browser/react/mount-context.d.ts +0 -23
- package/dist/types.backup/browser/react/nonce-context.d.ts +0 -14
- package/dist/types.backup/browser/react/shallow-equal.d.ts +0 -5
- package/dist/types.backup/browser/react/use-action.d.ts +0 -61
- package/dist/types.backup/browser/react/use-handle.d.ts +0 -21
- package/dist/types.backup/browser/react/use-href.d.ts +0 -32
- package/dist/types.backup/browser/react/use-link-status.d.ts +0 -36
- package/dist/types.backup/browser/react/use-mount.d.ts +0 -24
- package/dist/types.backup/browser/react/use-navigation.d.ts +0 -15
- package/dist/types.backup/browser/react/use-params.d.ts +0 -21
- package/dist/types.backup/browser/react/use-pathname.d.ts +0 -13
- package/dist/types.backup/browser/react/use-reverse.d.ts +0 -40
- package/dist/types.backup/browser/react/use-router.d.ts +0 -23
- package/dist/types.backup/browser/react/use-search-params.d.ts +0 -19
- package/dist/types.backup/browser/react/use-segments.d.ts +0 -29
- package/dist/types.backup/browser/response-adapter.d.ts +0 -58
- package/dist/types.backup/browser/rsc-router.d.ts +0 -141
- package/dist/types.backup/browser/scroll-restoration.d.ts +0 -103
- package/dist/types.backup/browser/segment-reconciler.d.ts +0 -74
- package/dist/types.backup/browser/segment-structure-assert.d.ts +0 -16
- package/dist/types.backup/browser/server-action-bridge.d.ts +0 -29
- package/dist/types.backup/browser/types.d.ts +0 -530
- package/dist/types.backup/browser/validate-redirect-origin.d.ts +0 -28
- package/dist/types.backup/build/collect-fallback-refs.d.ts +0 -5
- package/dist/types.backup/build/generate-manifest.d.ts +0 -100
- package/dist/types.backup/build/generate-route-types.d.ts +0 -8
- package/dist/types.backup/build/index.d.ts +0 -21
- package/dist/types.backup/build/prefix-tree-utils.d.ts +0 -56
- package/dist/types.backup/build/route-trie.d.ts +0 -89
- package/dist/types.backup/build/route-types/ast-helpers.d.ts +0 -3
- package/dist/types.backup/build/route-types/ast-route-extraction.d.ts +0 -13
- package/dist/types.backup/build/route-types/codegen.d.ts +0 -16
- package/dist/types.backup/build/route-types/include-resolution.d.ts +0 -74
- package/dist/types.backup/build/route-types/param-extraction.d.ts +0 -13
- package/dist/types.backup/build/route-types/per-module-writer.d.ts +0 -18
- package/dist/types.backup/build/route-types/router-processing.d.ts +0 -82
- package/dist/types.backup/build/route-types/scan-filter.d.ts +0 -17
- package/dist/types.backup/build/route-types/source-scan.d.ts +0 -13
- package/dist/types.backup/build/runtime-discovery.d.ts +0 -24
- package/dist/types.backup/cache/background-task.d.ts +0 -21
- package/dist/types.backup/cache/cache-error.d.ts +0 -71
- package/dist/types.backup/cache/cache-key-utils.d.ts +0 -35
- package/dist/types.backup/cache/cache-policy.d.ts +0 -59
- package/dist/types.backup/cache/cache-runtime.d.ts +0 -51
- package/dist/types.backup/cache/cache-scope.d.ts +0 -134
- package/dist/types.backup/cache/cache-tag.d.ts +0 -79
- package/dist/types.backup/cache/cf/cf-base64.d.ts +0 -4
- package/dist/types.backup/cache/cf/cf-cache-constants.d.ts +0 -105
- package/dist/types.backup/cache/cf/cf-cache-store.d.ts +0 -481
- package/dist/types.backup/cache/cf/cf-cache-types.d.ts +0 -300
- package/dist/types.backup/cache/cf/cf-kv-utils.d.ts +0 -22
- package/dist/types.backup/cache/cf/cf-tag-marker-memo.d.ts +0 -15
- package/dist/types.backup/cache/cf/index.d.ts +0 -3
- package/dist/types.backup/cache/document-cache.d.ts +0 -69
- package/dist/types.backup/cache/handle-capture.d.ts +0 -23
- package/dist/types.backup/cache/handle-snapshot.d.ts +0 -39
- package/dist/types.backup/cache/index.d.ts +0 -7
- package/dist/types.backup/cache/memory-segment-store.d.ts +0 -163
- package/dist/types.backup/cache/profile-registry.d.ts +0 -40
- package/dist/types.backup/cache/read-through-swr.d.ts +0 -60
- package/dist/types.backup/cache/segment-codec.d.ts +0 -78
- package/dist/types.backup/cache/shell-snapshot.d.ts +0 -162
- package/dist/types.backup/cache/tag-invalidation.d.ts +0 -74
- package/dist/types.backup/cache/taint.d.ts +0 -71
- package/dist/types.backup/cache/types.d.ts +0 -407
- package/dist/types.backup/cache/vercel/index.d.ts +0 -1
- package/dist/types.backup/cache/vercel/vercel-cache-store.d.ts +0 -267
- package/dist/types.backup/client.d.ts +0 -184
- package/dist/types.backup/client.rsc.d.ts +0 -39
- package/dist/types.backup/cloudflare/index.d.ts +0 -7
- package/dist/types.backup/cloudflare/tracing.d.ts +0 -53
- package/dist/types.backup/component-utils.d.ts +0 -46
- package/dist/types.backup/components/DefaultDocument.d.ts +0 -13
- package/dist/types.backup/context-var.d.ts +0 -84
- package/dist/types.backup/debug.d.ts +0 -57
- package/dist/types.backup/decode-loader-results.d.ts +0 -5
- package/dist/types.backup/default-error-boundary.d.ts +0 -10
- package/dist/types.backup/defer.d.ts +0 -89
- package/dist/types.backup/deps/browser.d.ts +0 -1
- package/dist/types.backup/deps/html-stream-client.d.ts +0 -1
- package/dist/types.backup/deps/html-stream-server.d.ts +0 -1
- package/dist/types.backup/deps/rsc.d.ts +0 -1
- package/dist/types.backup/deps/ssr.d.ts +0 -1
- package/dist/types.backup/encode-kv.d.ts +0 -35
- package/dist/types.backup/errors.d.ts +0 -226
- package/dist/types.backup/escape-script.d.ts +0 -44
- package/dist/types.backup/handle.d.ts +0 -93
- package/dist/types.backup/handles/MetaTags.d.ts +0 -17
- package/dist/types.backup/handles/Scripts.d.ts +0 -38
- package/dist/types.backup/handles/breadcrumbs.d.ts +0 -43
- package/dist/types.backup/handles/deferred-resolution.d.ts +0 -53
- package/dist/types.backup/handles/is-thenable.d.ts +0 -12
- package/dist/types.backup/handles/meta.d.ts +0 -43
- package/dist/types.backup/handles/script.d.ts +0 -139
- package/dist/types.backup/host/cookie-handler.d.ts +0 -8
- package/dist/types.backup/host/errors.d.ts +0 -40
- package/dist/types.backup/host/index.d.ts +0 -33
- package/dist/types.backup/host/pattern-matcher.d.ts +0 -30
- package/dist/types.backup/host/router.d.ts +0 -12
- package/dist/types.backup/host/testing.d.ts +0 -41
- package/dist/types.backup/host/types.d.ts +0 -148
- package/dist/types.backup/host/utils.d.ts +0 -20
- package/dist/types.backup/href-client.d.ts +0 -214
- package/dist/types.backup/index.d.ts +0 -112
- package/dist/types.backup/index.rsc.d.ts +0 -51
- package/dist/types.backup/internal-debug.d.ts +0 -1
- package/dist/types.backup/loader-store.d.ts +0 -193
- package/dist/types.backup/loader.d.ts +0 -18
- package/dist/types.backup/loader.rsc.d.ts +0 -18
- package/dist/types.backup/missing-id-error.d.ts +0 -1
- package/dist/types.backup/outlet-context.d.ts +0 -12
- package/dist/types.backup/outlet-provider.d.ts +0 -12
- package/dist/types.backup/prerender/build-shell-capture.d.ts +0 -104
- package/dist/types.backup/prerender/param-hash.d.ts +0 -6
- package/dist/types.backup/prerender/shell-manifest-key.d.ts +0 -18
- package/dist/types.backup/prerender/store.d.ts +0 -62
- package/dist/types.backup/prerender.d.ts +0 -292
- package/dist/types.backup/redirect-origin.d.ts +0 -55
- package/dist/types.backup/regex-escape.d.ts +0 -6
- package/dist/types.backup/render-error-thrower.d.ts +0 -13
- package/dist/types.backup/response-utils.d.ts +0 -35
- package/dist/types.backup/reverse.d.ts +0 -206
- package/dist/types.backup/root-error-boundary.d.ts +0 -32
- package/dist/types.backup/route-content-wrapper.d.ts +0 -40
- package/dist/types.backup/route-definition/dsl-helpers.d.ts +0 -130
- package/dist/types.backup/route-definition/helper-factories.d.ts +0 -22
- package/dist/types.backup/route-definition/helpers-types.d.ts +0 -392
- package/dist/types.backup/route-definition/index.d.ts +0 -7
- package/dist/types.backup/route-definition/redirect.d.ts +0 -48
- package/dist/types.backup/route-definition/resolve-handler-use.d.ts +0 -19
- package/dist/types.backup/route-definition/use-item-types.d.ts +0 -1
- package/dist/types.backup/route-definition.d.ts +0 -1
- package/dist/types.backup/route-map-builder.d.ts +0 -127
- package/dist/types.backup/route-name.d.ts +0 -27
- package/dist/types.backup/route-types.d.ts +0 -172
- package/dist/types.backup/router/basename.d.ts +0 -10
- package/dist/types.backup/router/content-negotiation.d.ts +0 -91
- package/dist/types.backup/router/debug-manifest.d.ts +0 -7
- package/dist/types.backup/router/error-handling.d.ts +0 -76
- package/dist/types.backup/router/find-match.d.ts +0 -19
- package/dist/types.backup/router/handler-context.d.ts +0 -41
- package/dist/types.backup/router/instrument.d.ts +0 -161
- package/dist/types.backup/router/intercept-resolution.d.ts +0 -79
- package/dist/types.backup/router/lazy-includes.d.ts +0 -26
- package/dist/types.backup/router/loader-resolution.d.ts +0 -63
- package/dist/types.backup/router/logging.d.ts +0 -41
- package/dist/types.backup/router/manifest.d.ts +0 -8
- package/dist/types.backup/router/match-api.d.ts +0 -19
- package/dist/types.backup/router/match-context.d.ts +0 -184
- package/dist/types.backup/router/match-handlers.d.ts +0 -49
- package/dist/types.backup/router/match-middleware/background-revalidation.d.ts +0 -113
- package/dist/types.backup/router/match-middleware/cache-lookup.d.ts +0 -113
- package/dist/types.backup/router/match-middleware/cache-store.d.ts +0 -112
- package/dist/types.backup/router/match-middleware/index.d.ts +0 -80
- package/dist/types.backup/router/match-middleware/intercept-resolution.d.ts +0 -116
- package/dist/types.backup/router/match-middleware/segment-resolution.d.ts +0 -94
- package/dist/types.backup/router/match-pipelines.d.ts +0 -103
- package/dist/types.backup/router/match-result.d.ts +0 -114
- package/dist/types.backup/router/metrics.d.ts +0 -6
- package/dist/types.backup/router/middleware-types.d.ts +0 -74
- package/dist/types.backup/router/middleware.d.ts +0 -116
- package/dist/types.backup/router/navigation-snapshot.d.ts +0 -22
- package/dist/types.backup/router/params-util.d.ts +0 -8
- package/dist/types.backup/router/parse-pattern.d.ts +0 -38
- package/dist/types.backup/router/pattern-matching.d.ts +0 -169
- package/dist/types.backup/router/prefetch-cache-ttl.d.ts +0 -27
- package/dist/types.backup/router/prefetch-limits.d.ts +0 -20
- package/dist/types.backup/router/prerender-match.d.ts +0 -50
- package/dist/types.backup/router/preview-match.d.ts +0 -22
- package/dist/types.backup/router/request-classification.d.ts +0 -104
- package/dist/types.backup/router/revalidation.d.ts +0 -57
- package/dist/types.backup/router/route-snapshot.d.ts +0 -112
- package/dist/types.backup/router/router-context.d.ts +0 -137
- package/dist/types.backup/router/router-interfaces.d.ts +0 -432
- package/dist/types.backup/router/router-options.d.ts +0 -738
- package/dist/types.backup/router/router-registry.d.ts +0 -15
- package/dist/types.backup/router/segment-resolution/fresh.d.ts +0 -55
- package/dist/types.backup/router/segment-resolution/helpers.d.ts +0 -93
- package/dist/types.backup/router/segment-resolution/loader-cache.d.ts +0 -33
- package/dist/types.backup/router/segment-resolution/loader-mask.d.ts +0 -44
- package/dist/types.backup/router/segment-resolution/loader-snapshot.d.ts +0 -90
- package/dist/types.backup/router/segment-resolution/mask-nested.d.ts +0 -53
- package/dist/types.backup/router/segment-resolution/revalidation.d.ts +0 -85
- package/dist/types.backup/router/segment-resolution/static-store.d.ts +0 -17
- package/dist/types.backup/router/segment-resolution/streamed-handler-telemetry.d.ts +0 -16
- package/dist/types.backup/router/segment-resolution/view-transition-default.d.ts +0 -28
- package/dist/types.backup/router/segment-resolution.d.ts +0 -3
- package/dist/types.backup/router/segment-wrappers.d.ts +0 -53
- package/dist/types.backup/router/state-cookie-name.d.ts +0 -1
- package/dist/types.backup/router/substitute-pattern-params.d.ts +0 -23
- package/dist/types.backup/router/telemetry-otel.d.ts +0 -113
- package/dist/types.backup/router/telemetry.d.ts +0 -215
- package/dist/types.backup/router/timeout.d.ts +0 -68
- package/dist/types.backup/router/tracing.d.ts +0 -125
- package/dist/types.backup/router/trie-matching.d.ts +0 -32
- package/dist/types.backup/router/types.d.ts +0 -98
- package/dist/types.backup/router/url-params.d.ts +0 -26
- package/dist/types.backup/router.d.ts +0 -7
- package/dist/types.backup/rsc/capture-queue.d.ts +0 -6
- package/dist/types.backup/rsc/full-payload.d.ts +0 -22
- package/dist/types.backup/rsc/handler-context.d.ts +0 -31
- package/dist/types.backup/rsc/handler.d.ts +0 -9
- package/dist/types.backup/rsc/helpers.d.ts +0 -213
- package/dist/types.backup/rsc/index.d.ts +0 -17
- package/dist/types.backup/rsc/json-route-result.d.ts +0 -20
- package/dist/types.backup/rsc/loader-fetch.d.ts +0 -14
- package/dist/types.backup/rsc/manifest-init.d.ts +0 -18
- package/dist/types.backup/rsc/nonce.d.ts +0 -28
- package/dist/types.backup/rsc/origin-guard.d.ts +0 -50
- package/dist/types.backup/rsc/progressive-enhancement.d.ts +0 -19
- package/dist/types.backup/rsc/redirect-guard.d.ts +0 -35
- package/dist/types.backup/rsc/response-cache-serve.d.ts +0 -46
- package/dist/types.backup/rsc/response-error.d.ts +0 -19
- package/dist/types.backup/rsc/response-route-handler.d.ts +0 -29
- package/dist/types.backup/rsc/rsc-rendering.d.ts +0 -23
- package/dist/types.backup/rsc/runtime-warnings.d.ts +0 -22
- package/dist/types.backup/rsc/server-action.d.ts +0 -68
- package/dist/types.backup/rsc/shell-build-manifest.d.ts +0 -84
- package/dist/types.backup/rsc/shell-capture-constants.d.ts +0 -27
- package/dist/types.backup/rsc/shell-capture.d.ts +0 -374
- package/dist/types.backup/rsc/shell-serve.d.ts +0 -136
- package/dist/types.backup/rsc/ssr-setup.d.ts +0 -48
- package/dist/types.backup/rsc/transition-gate.d.ts +0 -27
- package/dist/types.backup/rsc/types.d.ts +0 -290
- package/dist/types.backup/runtime-env.d.ts +0 -1
- package/dist/types.backup/search-params.d.ts +0 -125
- package/dist/types.backup/segment-content-promise.d.ts +0 -13
- package/dist/types.backup/segment-fragments.d.ts +0 -56
- package/dist/types.backup/segment-loader-promise.d.ts +0 -22
- package/dist/types.backup/segment-system.d.ts +0 -84
- package/dist/types.backup/serialize.d.ts +0 -164
- package/dist/types.backup/server/context.d.ts +0 -494
- package/dist/types.backup/server/cookie-parse.d.ts +0 -10
- package/dist/types.backup/server/cookie-store.d.ts +0 -107
- package/dist/types.backup/server/fetchable-loader-store.d.ts +0 -20
- package/dist/types.backup/server/handle-store.d.ts +0 -100
- package/dist/types.backup/server/loader-registry.d.ts +0 -32
- package/dist/types.backup/server/request-context.d.ts +0 -596
- package/dist/types.backup/server/root-layout.d.ts +0 -3
- package/dist/types.backup/server.d.ts +0 -15
- package/dist/types.backup/ssr/index.d.ts +0 -233
- package/dist/types.backup/ssr/inject-rsc-eager.d.ts +0 -3
- package/dist/types.backup/ssr/preinit-client-references.d.ts +0 -71
- package/dist/types.backup/ssr/ssr-root.d.ts +0 -69
- package/dist/types.backup/static-handler.d.ts +0 -57
- package/dist/types.backup/testing/cache-status.d.ts +0 -63
- package/dist/types.backup/testing/collect-handle.d.ts +0 -20
- package/dist/types.backup/testing/dispatch.d.ts +0 -123
- package/dist/types.backup/testing/dom.entry.d.ts +0 -15
- package/dist/types.backup/testing/e2e/fixture.d.ts +0 -37
- package/dist/types.backup/testing/e2e/index.d.ts +0 -30
- package/dist/types.backup/testing/e2e/matchers.d.ts +0 -17
- package/dist/types.backup/testing/e2e/page-helpers.d.ts +0 -62
- package/dist/types.backup/testing/e2e/parity.d.ts +0 -111
- package/dist/types.backup/testing/e2e/server.d.ts +0 -35
- package/dist/types.backup/testing/flight-matchers.d.ts +0 -55
- package/dist/types.backup/testing/flight-normalize.d.ts +0 -1
- package/dist/types.backup/testing/flight-tree.d.ts +0 -192
- package/dist/types.backup/testing/flight.d.ts +0 -115
- package/dist/types.backup/testing/flight.entry.d.ts +0 -27
- package/dist/types.backup/testing/generated-routes.d.ts +0 -66
- package/dist/types.backup/testing/index.d.ts +0 -52
- package/dist/types.backup/testing/internal/context.d.ts +0 -225
- package/dist/types.backup/testing/internal/flight-client-globals.d.ts +0 -1
- package/dist/types.backup/testing/internal/seed-vars.d.ts +0 -30
- package/dist/types.backup/testing/render-handler.d.ts +0 -160
- package/dist/types.backup/testing/render-route.d.ts +0 -246
- package/dist/types.backup/testing/run-loader.d.ts +0 -186
- package/dist/types.backup/testing/run-middleware.d.ts +0 -132
- package/dist/types.backup/testing/run-transition-when.d.ts +0 -77
- package/dist/types.backup/testing/vitest-stubs/cloudflare-email.d.ts +0 -6
- package/dist/types.backup/testing/vitest-stubs/cloudflare-workers.d.ts +0 -13
- package/dist/types.backup/testing/vitest-stubs/plugin-rsc.d.ts +0 -7
- package/dist/types.backup/testing/vitest-stubs/version.d.ts +0 -1
- package/dist/types.backup/testing/vitest.d.ts +0 -205
- package/dist/types.backup/theme/ThemeProvider.d.ts +0 -13
- package/dist/types.backup/theme/ThemeScript.d.ts +0 -45
- package/dist/types.backup/theme/constants.d.ts +0 -39
- package/dist/types.backup/theme/index.d.ts +0 -29
- package/dist/types.backup/theme/theme-context.d.ts +0 -21
- package/dist/types.backup/theme/theme-script.d.ts +0 -26
- package/dist/types.backup/theme/types.d.ts +0 -162
- package/dist/types.backup/theme/use-theme.d.ts +0 -8
- package/dist/types.backup/types/boundaries.d.ts +0 -93
- package/dist/types.backup/types/cache-types.d.ts +0 -191
- package/dist/types.backup/types/error-types.d.ts +0 -114
- package/dist/types.backup/types/global-namespace.d.ts +0 -90
- package/dist/types.backup/types/handler-context.d.ts +0 -658
- package/dist/types.backup/types/index.d.ts +0 -11
- package/dist/types.backup/types/loader-types.d.ts +0 -182
- package/dist/types.backup/types/request-scope.d.ts +0 -93
- package/dist/types.backup/types/route-config.d.ts +0 -105
- package/dist/types.backup/types/route-entry.d.ts +0 -95
- package/dist/types.backup/types/segments.d.ts +0 -234
- package/dist/types.backup/types.d.ts +0 -1
- package/dist/types.backup/urls/include-helper.d.ts +0 -17
- package/dist/types.backup/urls/include-provider.d.ts +0 -27
- package/dist/types.backup/urls/index.d.ts +0 -6
- package/dist/types.backup/urls/path-helper-types.d.ts +0 -197
- package/dist/types.backup/urls/path-helper.d.ts +0 -12
- package/dist/types.backup/urls/pattern-types.d.ts +0 -166
- package/dist/types.backup/urls/response-types.d.ts +0 -67
- package/dist/types.backup/urls/type-extraction.d.ts +0 -157
- package/dist/types.backup/urls/urls-function.d.ts +0 -24
- package/dist/types.backup/urls.d.ts +0 -1
- package/dist/types.backup/use-loader.d.ts +0 -150
- package/dist/types.backup/vercel/index.d.ts +0 -10
- package/dist/types.backup/vercel/tracing.d.ts +0 -70
- package/dist/types.backup/vite/debug.d.ts +0 -80
- package/dist/types.backup/vite/discovery/bundle-postprocess.d.ts +0 -12
- package/dist/types.backup/vite/discovery/dev-prerender-cache.d.ts +0 -65
- package/dist/types.backup/vite/discovery/discover-routers.d.ts +0 -17
- package/dist/types.backup/vite/discovery/discovery-errors.d.ts +0 -113
- package/dist/types.backup/vite/discovery/gate-state.d.ts +0 -79
- package/dist/types.backup/vite/discovery/prerender-collection.d.ts +0 -24
- package/dist/types.backup/vite/discovery/route-types-writer.d.ts +0 -32
- package/dist/types.backup/vite/discovery/self-gen-tracking.d.ts +0 -22
- package/dist/types.backup/vite/discovery/shell-prerender-phase.d.ts +0 -40
- package/dist/types.backup/vite/discovery/state.d.ts +0 -162
- package/dist/types.backup/vite/discovery/virtual-module-codegen.d.ts +0 -15
- package/dist/types.backup/vite/index.d.ts +0 -11
- package/dist/types.backup/vite/inject-client-debug.d.ts +0 -56
- package/dist/types.backup/vite/plugin-types.d.ts +0 -298
- package/dist/types.backup/vite/plugins/cjs-to-esm.d.ts +0 -6
- package/dist/types.backup/vite/plugins/client-ref-dedup.d.ts +0 -40
- package/dist/types.backup/vite/plugins/client-ref-hashing.d.ts +0 -35
- package/dist/types.backup/vite/plugins/cloudflare-protocol-stub.d.ts +0 -64
- package/dist/types.backup/vite/plugins/expose-action-id.d.ts +0 -18
- package/dist/types.backup/vite/plugins/expose-id-utils.d.ts +0 -37
- package/dist/types.backup/vite/plugins/expose-ids/export-analysis.d.ts +0 -19
- package/dist/types.backup/vite/plugins/expose-ids/handler-transform.d.ts +0 -10
- package/dist/types.backup/vite/plugins/expose-ids/loader-transform.d.ts +0 -8
- package/dist/types.backup/vite/plugins/expose-ids/router-transform.d.ts +0 -13
- package/dist/types.backup/vite/plugins/expose-ids/types.d.ts +0 -29
- package/dist/types.backup/vite/plugins/expose-internal-ids.d.ts +0 -6
- package/dist/types.backup/vite/plugins/performance-tracks.d.ts +0 -25
- package/dist/types.backup/vite/plugins/refresh-cmd.d.ts +0 -20
- package/dist/types.backup/vite/plugins/use-cache-transform.d.ts +0 -20
- package/dist/types.backup/vite/plugins/vercel-output.d.ts +0 -85
- package/dist/types.backup/vite/plugins/version-injector.d.ts +0 -21
- package/dist/types.backup/vite/plugins/version-plugin.d.ts +0 -19
- package/dist/types.backup/vite/plugins/virtual-entries.d.ts +0 -36
- package/dist/types.backup/vite/plugins/virtual-stub-plugin.d.ts +0 -7
- package/dist/types.backup/vite/rango.d.ts +0 -29
- package/dist/types.backup/vite/router-discovery.d.ts +0 -23
- package/dist/types.backup/vite/utils/ast-handler-extract.d.ts +0 -64
- package/dist/types.backup/vite/utils/banner.d.ts +0 -2
- package/dist/types.backup/vite/utils/bundle-analysis.d.ts +0 -28
- package/dist/types.backup/vite/utils/client-chunks.d.ts +0 -55
- package/dist/types.backup/vite/utils/directive-prologue.d.ts +0 -16
- package/dist/types.backup/vite/utils/forward-user-plugins.d.ts +0 -37
- package/dist/types.backup/vite/utils/manifest-utils.d.ts +0 -7
- package/dist/types.backup/vite/utils/package-resolution.d.ts +0 -6
- package/dist/types.backup/vite/utils/prerender-utils.d.ts +0 -32
- package/dist/types.backup/vite/utils/shared-utils.d.ts +0 -55
|
@@ -68,8 +68,11 @@ export interface InitBrowserAppOptions {
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Enable global link interception for SPA navigation.
|
|
71
|
-
* When enabled, clicks on same-origin anchor elements are intercepted
|
|
72
|
-
* and handled via client-side navigation instead of full page loads.
|
|
71
|
+
* When enabled, clicks on eligible same-origin HTML anchor elements are intercepted
|
|
72
|
+
* and handled via client-side navigation instead of full page loads. Plain
|
|
73
|
+
* anchors inside the router basename also follow its default prefetch strategy
|
|
74
|
+
* after hydration. `data-prefetch="false"`/`"none"` opts out; `"true"` allows
|
|
75
|
+
* an application route with a common static-resource suffix.
|
|
73
76
|
*
|
|
74
77
|
* Links rendered with the Link component handle their own navigation
|
|
75
78
|
* regardless of this setting.
|
|
@@ -124,6 +127,8 @@ export interface BrowserAppContext {
|
|
|
124
127
|
warmupEnabled?: boolean;
|
|
125
128
|
/** Whether the hydrated tree should be wrapped in React.StrictMode */
|
|
126
129
|
strictMode?: boolean;
|
|
130
|
+
/** Whether plain-anchor click interception and delegated prefetch are enabled */
|
|
131
|
+
linkInterceptionEnabled?: boolean;
|
|
127
132
|
/** App version for prefetch version mismatch detection */
|
|
128
133
|
version?: string;
|
|
129
134
|
/**
|
|
@@ -196,6 +201,12 @@ export async function initBrowserApp(
|
|
|
196
201
|
}
|
|
197
202
|
const initialHistoryKey = generateHistoryKey(window.location.href);
|
|
198
203
|
|
|
204
|
+
// Resolve the state namespace before the store installs its BroadcastChannel
|
|
205
|
+
// listener. A streaming handle payload can delay hydration below; leaving the
|
|
206
|
+
// default name active during that wait would discard this router's messages.
|
|
207
|
+
const version = initialPayload.metadata?.version;
|
|
208
|
+
initRangoState(version ?? "0", initialPayload.metadata?.stateCookieName);
|
|
209
|
+
|
|
199
210
|
// Create navigation store with history-based caching
|
|
200
211
|
const store = createNavigationStore({
|
|
201
212
|
initialLocation: window.location,
|
|
@@ -271,7 +282,6 @@ export async function initBrowserApp(
|
|
|
271
282
|
// It is set once from the initial payload and not swapped within a session:
|
|
272
283
|
// a cross-app navigation is a full document load (X-RSC-Reload), so the
|
|
273
284
|
// target app establishes its own shell on load.
|
|
274
|
-
const version = initialPayload.metadata?.version;
|
|
275
285
|
const appShellRef = createAppShellRef({
|
|
276
286
|
routerId: initialPayload.metadata?.routerId,
|
|
277
287
|
rootLayout: initialPayload.metadata?.rootLayout,
|
|
@@ -279,11 +289,6 @@ export async function initBrowserApp(
|
|
|
279
289
|
version,
|
|
280
290
|
});
|
|
281
291
|
|
|
282
|
-
// Initialize the rango state cookie for cache invalidation. The build version
|
|
283
|
-
// busts cached prefetches on deploy; the server-resolved cookie name
|
|
284
|
-
// namespaces the cookie so sibling apps on the same origin don't collide
|
|
285
|
-
// (falls back to the bare default prefix if metadata lacks the name).
|
|
286
|
-
initRangoState(version ?? "0", initialPayload.metadata?.stateCookieName);
|
|
287
292
|
setAppVersion(version);
|
|
288
293
|
|
|
289
294
|
// Initialize the in-memory prefetch cache (TTL + max size) and the prefetch
|
|
@@ -359,6 +364,8 @@ export async function initBrowserApp(
|
|
|
359
364
|
onUpdate: (update) => store.emitUpdate(update),
|
|
360
365
|
renderSegments,
|
|
361
366
|
version: version,
|
|
367
|
+
defaultPrefetch,
|
|
368
|
+
basename: initialPayload.metadata?.basename,
|
|
362
369
|
});
|
|
363
370
|
|
|
364
371
|
// Connect action redirect → navigation bridge (now that both are initialized)
|
|
@@ -541,6 +548,7 @@ export async function initBrowserApp(
|
|
|
541
548
|
initialTheme: effectiveInitialTheme,
|
|
542
549
|
warmupEnabled: initialPayload.metadata?.warmupEnabled ?? true,
|
|
543
550
|
strictMode: initialPayload.metadata?.strictMode ?? true,
|
|
551
|
+
linkInterceptionEnabled: linkInterception,
|
|
544
552
|
version,
|
|
545
553
|
appShellRef,
|
|
546
554
|
};
|
|
@@ -614,6 +622,7 @@ export function Rango(_props: RangoProps): React.ReactElement {
|
|
|
614
622
|
warmupEnabled,
|
|
615
623
|
version,
|
|
616
624
|
appShellRef,
|
|
625
|
+
linkInterceptionEnabled,
|
|
617
626
|
} = getBrowserAppContext();
|
|
618
627
|
|
|
619
628
|
// Signal that the React tree has hydrated. useEffect only fires after
|
|
@@ -621,11 +630,15 @@ export function Rango(_props: RangoProps): React.ReactElement {
|
|
|
621
630
|
// that does not depend on React internals like __reactFiber.
|
|
622
631
|
React.useEffect(() => {
|
|
623
632
|
document.documentElement.dataset.hydrated = "";
|
|
633
|
+
const cleanupPrefetch = linkInterceptionEnabled
|
|
634
|
+
? bridge.registerDelegatedPrefetch()
|
|
635
|
+
: undefined;
|
|
624
636
|
if (IS_BROWSER_DEBUG && !hydrationCommitLogged) {
|
|
625
637
|
hydrationCommitLogged = true;
|
|
626
638
|
bootLog("hydration commit (root effect flushed)");
|
|
627
639
|
}
|
|
628
|
-
|
|
640
|
+
return cleanupPrefetch;
|
|
641
|
+
}, [bridge, linkInterceptionEnabled]);
|
|
629
642
|
|
|
630
643
|
return (
|
|
631
644
|
<NavigationProvider
|
package/src/browser/types.ts
CHANGED
|
@@ -613,6 +613,7 @@ export interface NavigationBridge {
|
|
|
613
613
|
refresh(): Promise<void>;
|
|
614
614
|
handlePopstate(): Promise<void>;
|
|
615
615
|
registerLinkInterception(): () => void;
|
|
616
|
+
registerDelegatedPrefetch(): () => void;
|
|
616
617
|
/** Current RSC version (live, reflects the latest updateVersion). */
|
|
617
618
|
getVersion(): string | undefined;
|
|
618
619
|
/** Update the RSC version (e.g. after HMR). Clears prefetch cache. */
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { encodeKV } from "../encode-kv.js";
|
|
10
|
+
import type { SearchParamsFilter } from "./search-params-filter.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Reserved URL query params that the router owns and must never key the cache
|
|
@@ -34,12 +35,22 @@ function isReservedSearchParam(key: string): boolean {
|
|
|
34
35
|
* Build a sorted, deterministic query string from URLSearchParams,
|
|
35
36
|
* excluding the router's reserved params (see isReservedSearchParam).
|
|
36
37
|
*
|
|
37
|
-
*
|
|
38
|
+
* `filter` is the compiled `cache.searchParams` config (search-params-filter.ts),
|
|
39
|
+
* applied AFTER the reserved-param exclusion and BEFORE the sort, so reserved
|
|
40
|
+
* params can never be re-included (`include: ["__no_cache"]` is a no-op) and
|
|
41
|
+
* surviving params stay order-insensitive. `undefined` means no filtering --
|
|
42
|
+
* that path must stay byte-identical to the pre-filter format (cacheKeyBase
|
|
43
|
+
* output is byte-stable by contract).
|
|
44
|
+
*
|
|
45
|
+
* Returns empty string when no user-facing params survive.
|
|
38
46
|
*/
|
|
39
|
-
export function sortedSearchString(
|
|
47
|
+
export function sortedSearchString(
|
|
48
|
+
searchParams: URLSearchParams,
|
|
49
|
+
filter?: SearchParamsFilter,
|
|
50
|
+
): string {
|
|
40
51
|
const pairs: [string, string][] = [];
|
|
41
52
|
for (const [k, v] of searchParams) {
|
|
42
|
-
if (!isReservedSearchParam(k)) {
|
|
53
|
+
if (!isReservedSearchParam(k) && (filter === undefined || filter(k))) {
|
|
43
54
|
pairs.push([k, v]);
|
|
44
55
|
}
|
|
45
56
|
}
|
|
@@ -77,9 +88,12 @@ export function cacheKeyBase(
|
|
|
77
88
|
pathname: string,
|
|
78
89
|
searchParams?: URLSearchParams,
|
|
79
90
|
params?: Record<string, string>,
|
|
91
|
+
filter?: SearchParamsFilter,
|
|
80
92
|
): string {
|
|
81
93
|
const paramStr = sortedRouteParams(params);
|
|
82
|
-
const searchStr = searchParams
|
|
94
|
+
const searchStr = searchParams
|
|
95
|
+
? sortedSearchString(searchParams, filter)
|
|
96
|
+
: "";
|
|
83
97
|
|
|
84
98
|
let key = `${host}${pathname}`;
|
|
85
99
|
if (paramStr) key += `:${paramStr}`;
|
|
@@ -302,9 +302,14 @@ export function registerCachedFunction<T extends (...args: any[]) => any>(
|
|
|
302
302
|
if (ctx._responseType) {
|
|
303
303
|
keyArgs.push(ctx._responseType);
|
|
304
304
|
}
|
|
305
|
-
// Include user-facing search params (exclude internal _rsc*/__
|
|
305
|
+
// Include user-facing search params (exclude internal _rsc*/__
|
|
306
|
+
// params, plus the request's cache.searchParams filter -- same
|
|
307
|
+
// normalization as the URL-keyed tiers).
|
|
306
308
|
if (ctx.searchParams instanceof URLSearchParams) {
|
|
307
|
-
const normalized = sortedSearchString(
|
|
309
|
+
const normalized = sortedSearchString(
|
|
310
|
+
ctx.searchParams,
|
|
311
|
+
requestCtx?._searchParamsFilter,
|
|
312
|
+
);
|
|
308
313
|
if (normalized) {
|
|
309
314
|
keyArgs.push(normalized);
|
|
310
315
|
}
|
package/src/cache/cache-scope.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { PartialCacheOptions } from "../types.js";
|
|
12
12
|
import type { ResolvedSegment } from "../types.js";
|
|
13
13
|
import type { SegmentCacheStore, CachedEntryData } from "./types.js";
|
|
14
|
+
import { CACHE_READ_ERROR } from "./types.js";
|
|
14
15
|
import { INTERNAL_RANGO_DEBUG } from "../internal-debug.js";
|
|
15
16
|
import {
|
|
16
17
|
getRequestContext,
|
|
@@ -101,7 +102,7 @@ function getDefaultRouteCacheKey(
|
|
|
101
102
|
? "intercept"
|
|
102
103
|
: (prefixOverride ?? (isPartial ? "partial" : "doc"));
|
|
103
104
|
|
|
104
|
-
return `${prefix}:${cacheKeyBase(host, pathname, searchParams, params)}`;
|
|
105
|
+
return `${prefix}:${cacheKeyBase(host, pathname, searchParams, params, ctx?._searchParamsFilter)}`;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
// ============================================================================
|
|
@@ -110,6 +111,17 @@ function getDefaultRouteCacheKey(
|
|
|
110
111
|
|
|
111
112
|
const CACHE_HIT_OBSERVERS = new WeakMap<CacheScope, () => void>();
|
|
112
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Discriminated outcome of a route cache lookup — see
|
|
116
|
+
* {@link CacheScope.lookupRouteDetailed} for what each status licenses.
|
|
117
|
+
*/
|
|
118
|
+
export type CacheRouteLookupOutcome =
|
|
119
|
+
| {
|
|
120
|
+
status: "hit";
|
|
121
|
+
result: { segments: ResolvedSegment[]; shouldRevalidate: boolean };
|
|
122
|
+
}
|
|
123
|
+
| { status: "miss" | "bypass" | "error" };
|
|
124
|
+
|
|
113
125
|
/**
|
|
114
126
|
* CacheScope represents a cache boundary in the route tree.
|
|
115
127
|
*
|
|
@@ -225,30 +237,76 @@ export class CacheScope {
|
|
|
225
237
|
return resolveCacheKey(keyFn, this.getStore(), defaultKey, "CacheScope");
|
|
226
238
|
}
|
|
227
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @internal Whether a cache read/write is allowed for the current request:
|
|
242
|
+
* the scope is enabled AND its `condition` (if any) returns true. "read"
|
|
243
|
+
* is consulted by the PPR navigation-replay gate BEFORE any shell-store
|
|
244
|
+
* read so a cache(false)/condition-false route reports `cache-disabled`
|
|
245
|
+
* without spending getShell I/O; "write" gates the capture's snapshot-only
|
|
246
|
+
* doc record (cache-store middleware) under the same semantics as the
|
|
247
|
+
* scope's own store write. Consumer opt-outs are absolute — the seeded
|
|
248
|
+
* fallback must never serve where the consumer refused cached serves.
|
|
249
|
+
*/
|
|
250
|
+
allowsCache(op: "read" | "write"): boolean {
|
|
251
|
+
return this.enabled && this.conditionAllows(op);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @internal True for scopes minted from the `_shellImplicitCache` marker
|
|
256
|
+
* (createShellImplicitDocScope) — the only construction path that passes
|
|
257
|
+
* the `doc` defaultKeyPrefix; route-derived scopes (createCacheScope) never
|
|
258
|
+
* do. withCacheLookup/withCacheStore use this to tell the implicit doc
|
|
259
|
+
* scope from a route-derived scope: the two compose on the replay serve
|
|
260
|
+
* path and only the route-derived kind gets the seeded fallback /
|
|
261
|
+
* doc-record treatment.
|
|
262
|
+
*/
|
|
263
|
+
get isShellImplicitDocScope(): boolean {
|
|
264
|
+
return this.defaultKeyPrefix === "doc";
|
|
265
|
+
}
|
|
266
|
+
|
|
228
267
|
/**
|
|
229
268
|
* Evaluate the cache `condition` predicate. Returns false (skip the cache
|
|
230
269
|
* operation) when the predicate returns false or throws; returns true when
|
|
231
270
|
* there is no condition or no request context to evaluate it against.
|
|
232
271
|
*/
|
|
272
|
+
/**
|
|
273
|
+
* One WRITE decision per (scope, request), memoized on the request context.
|
|
274
|
+
* A capture render has TWO writers consulting the same predicate — the
|
|
275
|
+
* explicit tier's cacheRoute and the snapshot-only doc record gate
|
|
276
|
+
* (recordShellCaptureDocRecord) — and a true→false flap between the two
|
|
277
|
+
* evaluations recorded a REPLAYABLE canonical snapshot for a render whose
|
|
278
|
+
* real write was refused. The first evaluation pins the answer for the
|
|
279
|
+
* whole render (the capture's derived context during captures). READ
|
|
280
|
+
* decisions stay per-lookup by design: pre-deciding a flappable predicate
|
|
281
|
+
* at the replay gate was the round-2 regression.
|
|
282
|
+
*/
|
|
283
|
+
private readonly writeConditionMemo = new WeakMap<RequestContext, boolean>();
|
|
284
|
+
|
|
233
285
|
private conditionAllows(op: "read" | "write"): boolean {
|
|
234
286
|
if (this.config === false || !this.config.condition) return true;
|
|
235
287
|
const requestCtx = getRequestContext();
|
|
236
288
|
if (!requestCtx) return true;
|
|
289
|
+
if (op === "write") {
|
|
290
|
+
const memoized = this.writeConditionMemo.get(requestCtx);
|
|
291
|
+
if (memoized !== undefined) return memoized;
|
|
292
|
+
}
|
|
293
|
+
let allowed: boolean;
|
|
237
294
|
try {
|
|
238
|
-
|
|
295
|
+
allowed = !!this.config.condition(requestCtx);
|
|
296
|
+
if (!allowed) {
|
|
239
297
|
debugCacheLog(
|
|
240
298
|
`[CacheScope] condition returned false, skipping cache ${op}`,
|
|
241
299
|
);
|
|
242
|
-
return false;
|
|
243
300
|
}
|
|
244
|
-
return true;
|
|
245
301
|
} catch (error) {
|
|
246
302
|
console.error(
|
|
247
303
|
`[CacheScope] condition function threw, skipping cache ${op}:`,
|
|
248
304
|
error,
|
|
249
305
|
);
|
|
250
|
-
|
|
306
|
+
allowed = false;
|
|
251
307
|
}
|
|
308
|
+
if (op === "write") this.writeConditionMemo.set(requestCtx, allowed);
|
|
309
|
+
return allowed;
|
|
252
310
|
}
|
|
253
311
|
|
|
254
312
|
/**
|
|
@@ -267,11 +325,42 @@ export class CacheScope {
|
|
|
267
325
|
segments: ResolvedSegment[];
|
|
268
326
|
shouldRevalidate: boolean;
|
|
269
327
|
} | null> {
|
|
270
|
-
|
|
271
|
-
|
|
328
|
+
const outcome = await this.lookupRouteDetailed(
|
|
329
|
+
pathname,
|
|
330
|
+
params,
|
|
331
|
+
isIntercept,
|
|
332
|
+
);
|
|
333
|
+
return outcome.status === "hit" ? outcome.result : null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @internal lookupRoute with a discriminated outcome. The PPR replay
|
|
338
|
+
* composition (withCacheLookup) may substitute the seeded doc record ONLY on
|
|
339
|
+
* a true `miss` — the other non-hit outcomes must not be papered over:
|
|
340
|
+
*
|
|
341
|
+
* - `bypass`: the scope refused the read — cache(false), a false
|
|
342
|
+
* `condition()`, or no resolvable store. Consumer opt-outs are absolute;
|
|
343
|
+
* a fallback here would serve cached segments to a request the consumer
|
|
344
|
+
* said must render fresh.
|
|
345
|
+
* - `error`: a throwing consumer key()/store keyGenerator/store.get. The
|
|
346
|
+
* contract on that failure is "render uncached" (see the catch below) —
|
|
347
|
+
* falling back would serve the canonical doc record across a broken key
|
|
348
|
+
* partition, exactly the collision resolveCacheKey's no-default-fallback
|
|
349
|
+
* rule exists to prevent.
|
|
350
|
+
*
|
|
351
|
+
* A corrupt entry that was evicted reads as `miss`: the store was consulted
|
|
352
|
+
* and holds nothing servable, which is the post-eviction truth.
|
|
353
|
+
*/
|
|
354
|
+
async lookupRouteDetailed(
|
|
355
|
+
pathname: string,
|
|
356
|
+
params: Record<string, string>,
|
|
357
|
+
isIntercept?: boolean,
|
|
358
|
+
): Promise<CacheRouteLookupOutcome> {
|
|
359
|
+
if (!this.enabled) return { status: "bypass" };
|
|
360
|
+
if (!this.conditionAllows("read")) return { status: "bypass" };
|
|
272
361
|
|
|
273
362
|
const store = this.getStore();
|
|
274
|
-
if (!store) return
|
|
363
|
+
if (!store) return { status: "bypass" };
|
|
275
364
|
|
|
276
365
|
// Resolve cache key INSIDE the try so a throwing consumer key() (or a
|
|
277
366
|
// store.keyGenerator) degrades to a cache miss (return null -> render
|
|
@@ -285,9 +374,17 @@ export class CacheScope {
|
|
|
285
374
|
|
|
286
375
|
const result = await store.get(key);
|
|
287
376
|
|
|
377
|
+
// Built-in stores swallow backend read failures internally and signal
|
|
378
|
+
// them with CACHE_READ_ERROR — classify as `error`, not `miss`, so the
|
|
379
|
+
// replay composition renders uncached instead of substituting the
|
|
380
|
+
// seeded doc record for a tier whose backend never answered.
|
|
381
|
+
if (result === CACHE_READ_ERROR) {
|
|
382
|
+
return { status: "error" };
|
|
383
|
+
}
|
|
384
|
+
|
|
288
385
|
if (!result) {
|
|
289
386
|
debugCacheLog(`[CacheScope] MISS: ${key}`);
|
|
290
|
-
return
|
|
387
|
+
return { status: "miss" };
|
|
291
388
|
}
|
|
292
389
|
|
|
293
390
|
const { data: cached, shouldRevalidate } = result;
|
|
@@ -320,7 +417,7 @@ export class CacheScope {
|
|
|
320
417
|
.catch((e) =>
|
|
321
418
|
reportCacheError(e, "cache-delete", `[CacheScope] ${key}: evict`),
|
|
322
419
|
);
|
|
323
|
-
return
|
|
420
|
+
return { status: "miss" };
|
|
324
421
|
}
|
|
325
422
|
|
|
326
423
|
// A hit serves content that was tagged at write time, so the document
|
|
@@ -351,16 +448,18 @@ export class CacheScope {
|
|
|
351
448
|
}
|
|
352
449
|
|
|
353
450
|
CACHE_HIT_OBSERVERS.get(this)?.();
|
|
354
|
-
return { segments, shouldRevalidate };
|
|
451
|
+
return { status: "hit", result: { segments, shouldRevalidate } };
|
|
355
452
|
} catch (error) {
|
|
356
453
|
// Covers a store.get() failure AND a throwing consumer key()/keyGenerator
|
|
357
|
-
// (resolveKey). Either way degrade to
|
|
454
|
+
// (resolveKey). Either way degrade to an uncached render — reported as
|
|
455
|
+
// `error`, not `miss`, so the replay composition cannot substitute the
|
|
456
|
+
// seeded doc record for a lookup that never resolved its key partition.
|
|
358
457
|
reportCacheError(
|
|
359
458
|
error,
|
|
360
459
|
"cache-read",
|
|
361
460
|
`[CacheScope] lookup ${key ?? "(key resolution failed)"}`,
|
|
362
461
|
);
|
|
363
|
-
return
|
|
462
|
+
return { status: "error" };
|
|
364
463
|
}
|
|
365
464
|
}
|
|
366
465
|
|
|
@@ -422,6 +521,15 @@ export class CacheScope {
|
|
|
422
521
|
// Resolve cache key early (while request context is available)
|
|
423
522
|
const key = await this.resolveKey(pathname, params, isIntercept);
|
|
424
523
|
|
|
524
|
+
// Doc-namespaced scopes (the shell implicit scope and the capture's
|
|
525
|
+
// composed doc scope) publish the canonical document segment key so
|
|
526
|
+
// captureAndStoreShell can stamp it onto the shell entry (`docKey`).
|
|
527
|
+
// Replay eligibility then requires this exact record — "any segment
|
|
528
|
+
// record" previously counted unusable explicit-tier-keyed records too.
|
|
529
|
+
if (this.defaultKeyPrefix === "doc" && requestCtx._shellImplicitCache) {
|
|
530
|
+
requestCtx._shellImplicitCache.docKey = key;
|
|
531
|
+
}
|
|
532
|
+
|
|
425
533
|
// Resolve tags early (while request context is available, before waitUntil)
|
|
426
534
|
const tags = resolveCacheTags(this.config, requestCtx);
|
|
427
535
|
recordRequestTags(tags, requestCtx);
|
|
@@ -538,6 +646,31 @@ export function createCacheScope(
|
|
|
538
646
|
return new CacheScope(config.options, parent);
|
|
539
647
|
}
|
|
540
648
|
|
|
649
|
+
type ShellImplicitCacheMarker = NonNullable<
|
|
650
|
+
RequestContext["_shellImplicitCache"]
|
|
651
|
+
>;
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Mint the implicit doc-level scope for a `_shellImplicitCache` marker: key
|
|
655
|
+
* resolution under the marker's `doc` namespace against the marker's store,
|
|
656
|
+
* with the marker's onHit wired as the hit observer. Shared by
|
|
657
|
+
* {@link resolveShellImplicitCacheScope} (routes that derived no scope) and
|
|
658
|
+
* the explicit-scope composition sites (capture doc record in the cache-store
|
|
659
|
+
* middleware, seeded replay fallback in withCacheLookup) so both ends of the
|
|
660
|
+
* shell contract resolve the SAME canonical document key.
|
|
661
|
+
*/
|
|
662
|
+
export function createShellImplicitDocScope(
|
|
663
|
+
marker: ShellImplicitCacheMarker,
|
|
664
|
+
): CacheScope {
|
|
665
|
+
const implicitScope = new CacheScope(
|
|
666
|
+
{ ttl: marker.ttl, swr: marker.swr, store: marker.store },
|
|
667
|
+
null,
|
|
668
|
+
marker.keyPrefix,
|
|
669
|
+
);
|
|
670
|
+
if (marker.onHit) CACHE_HIT_OBSERVERS.set(implicitScope, marker.onHit);
|
|
671
|
+
return implicitScope;
|
|
672
|
+
}
|
|
673
|
+
|
|
541
674
|
/**
|
|
542
675
|
* Shell fast path: when the route tree derived NO cache scope and the current
|
|
543
676
|
* request context carries the `_shellImplicitCache` marker (a shell capture,
|
|
@@ -548,9 +681,11 @@ export function createCacheScope(
|
|
|
548
681
|
* (resolveFreshLoadersAndYield).
|
|
549
682
|
*
|
|
550
683
|
* An existing scope — including an explicit cache(false) opt-out — always
|
|
551
|
-
* wins: the consumer's cache() semantics (their ttl/swr/store/condition)
|
|
552
|
-
* never overridden, and cache(false) keeps the tail on the full handler
|
|
553
|
-
* re-run path.
|
|
684
|
+
* wins HERE: the consumer's cache() semantics (their ttl/swr/store/condition)
|
|
685
|
+
* are never overridden, and cache(false) keeps the tail on the full handler
|
|
686
|
+
* re-run path. On the navigation-replay serve path the marker still composes
|
|
687
|
+
* with an explicit scope downstream (withCacheLookup's seeded fallback after
|
|
688
|
+
* an explicit-tier miss) — see `onExplicitHit` on `_shellImplicitCache`.
|
|
554
689
|
*/
|
|
555
690
|
export function resolveShellImplicitCacheScope(
|
|
556
691
|
scope: CacheScope | null,
|
|
@@ -558,11 +693,5 @@ export function resolveShellImplicitCacheScope(
|
|
|
558
693
|
if (scope) return scope;
|
|
559
694
|
const marker = getRequestContext()?._shellImplicitCache;
|
|
560
695
|
if (!marker) return null;
|
|
561
|
-
|
|
562
|
-
{ ttl: marker.ttl, swr: marker.swr, store: marker.store },
|
|
563
|
-
null,
|
|
564
|
-
marker.keyPrefix,
|
|
565
|
-
);
|
|
566
|
-
if (marker.onHit) CACHE_HIT_OBSERVERS.set(implicitScope, marker.onHit);
|
|
567
|
-
return implicitScope;
|
|
696
|
+
return createShellImplicitDocScope(marker);
|
|
568
697
|
}
|
|
@@ -35,7 +35,9 @@ import type {
|
|
|
35
35
|
CacheItemResult,
|
|
36
36
|
CacheItemOptions,
|
|
37
37
|
ShellCacheEntry,
|
|
38
|
+
CacheReadError,
|
|
38
39
|
} from "../types.js";
|
|
40
|
+
import { CACHE_READ_ERROR } from "../types.js";
|
|
39
41
|
import {
|
|
40
42
|
_getRequestContext,
|
|
41
43
|
type RequestContext,
|
|
@@ -286,6 +288,14 @@ interface KVShellEnvelope {
|
|
|
286
288
|
i?: string;
|
|
287
289
|
/** Capture data snapshot: recorded cache-store hits/writes for HIT parity */
|
|
288
290
|
sn?: import("../types.js").ShellSnapshotRecord[];
|
|
291
|
+
/**
|
|
292
|
+
* ShellCacheEntry.docKey. Must round-trip: navigation-replay eligibility
|
|
293
|
+
* requires the exact canonical doc segment record named here — dropping the
|
|
294
|
+
* field reads back as "no consumable record" and every partial navigation
|
|
295
|
+
* reports `no-segment-snapshot` after a KV round trip (the memory store
|
|
296
|
+
* passes the entry by reference, so only envelope stores can lose it).
|
|
297
|
+
*/
|
|
298
|
+
dk?: string;
|
|
289
299
|
/**
|
|
290
300
|
* ShellCacheEntry.handlerLiveHoles. Must round-trip: the serve side arms the
|
|
291
301
|
* handler-free fast path on `!entry.handlerLiveHoles`, so dropping the flag
|
|
@@ -883,7 +893,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
883
893
|
* On L1 miss, falls back to KV (L2) if configured.
|
|
884
894
|
* KV hits are promoted to L1 in the background.
|
|
885
895
|
*/
|
|
886
|
-
async get(key: string): Promise<CacheGetResult | null> {
|
|
896
|
+
async get(key: string): Promise<CacheGetResult | null | CacheReadError> {
|
|
887
897
|
if (this.isReservedSegmentKey(key, "cache-read")) return null;
|
|
888
898
|
try {
|
|
889
899
|
const cache = await this.getCache();
|
|
@@ -897,27 +907,40 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
897
907
|
const matchMs = Date.now() - matchStart;
|
|
898
908
|
|
|
899
909
|
if (!response) {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
910
|
+
if (matchError) {
|
|
911
|
+
// A match REJECTION is reported as cache-read and still degrades to
|
|
912
|
+
// L2/KV -- a real KV value (or KV's own CACHE_READ_ERROR) stands on
|
|
913
|
+
// its own. But a null KV result (unconfigured namespace, kv-miss,
|
|
914
|
+
// kv-timeout) is NOT proof of absence under a rejected L1 match:
|
|
915
|
+
// the only real signal this read produced is the failure, so
|
|
916
|
+
// surface CACHE_READ_ERROR instead of a replayable miss (the PPR
|
|
917
|
+
// seeded fallback must render uncached, not substitute the doc
|
|
918
|
+
// record for a partition the store could not actually read).
|
|
904
919
|
reportCacheError(
|
|
905
920
|
matchError,
|
|
906
921
|
"cache-read",
|
|
907
922
|
"[CFCacheStore] get L1 match",
|
|
908
923
|
);
|
|
924
|
+
if (this.debug)
|
|
925
|
+
this.emitDebug({
|
|
926
|
+
op: "get",
|
|
927
|
+
key,
|
|
928
|
+
// Distinct from a genuine absence: surface it as match-error so
|
|
929
|
+
// debug agrees with the cache-read already routed to onError,
|
|
930
|
+
// instead of masquerading as l1-miss.
|
|
931
|
+
outcome: "match-error",
|
|
932
|
+
matchMs,
|
|
933
|
+
});
|
|
934
|
+
const kvResult = await this.kvGetSegment(key);
|
|
935
|
+
return kvResult ?? CACHE_READ_ERROR;
|
|
936
|
+
}
|
|
937
|
+
// An abandoned slow match (timedOut) keeps the fail-open latency-budget
|
|
938
|
+
// policy: degrade to L2/KV, and a KV null stays a miss.
|
|
909
939
|
if (this.debug)
|
|
910
940
|
this.emitDebug({
|
|
911
941
|
op: "get",
|
|
912
942
|
key,
|
|
913
|
-
|
|
914
|
-
// surface it as match-error so debug agrees with the cache-read
|
|
915
|
-
// already routed to onError, instead of masquerading as l1-miss.
|
|
916
|
-
outcome: matchError
|
|
917
|
-
? "match-error"
|
|
918
|
-
: timedOut
|
|
919
|
-
? "match-timeout"
|
|
920
|
-
: "l1-miss",
|
|
943
|
+
outcome: timedOut ? "match-timeout" : "l1-miss",
|
|
921
944
|
matchMs,
|
|
922
945
|
});
|
|
923
946
|
return this.kvGetSegment(key);
|
|
@@ -1098,7 +1121,9 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
1098
1121
|
// emit is the separate wrangler-tail signal. Keep both observability paths.
|
|
1099
1122
|
reportCacheError(error, "cache-read", "[CFCacheStore] get");
|
|
1100
1123
|
if (this.debug) this.emitDebug({ op: "get", key, outcome: "error" });
|
|
1101
|
-
|
|
1124
|
+
// Distinct from a miss so the PPR replay composition renders uncached
|
|
1125
|
+
// instead of substituting the seeded doc record (CACHE_READ_ERROR).
|
|
1126
|
+
return CACHE_READ_ERROR;
|
|
1102
1127
|
}
|
|
1103
1128
|
}
|
|
1104
1129
|
|
|
@@ -1819,6 +1844,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
1819
1844
|
buildVersion: envelope.bv,
|
|
1820
1845
|
initialTheme: envelope.i,
|
|
1821
1846
|
snapshot: envelope.sn,
|
|
1847
|
+
docKey: envelope.dk,
|
|
1822
1848
|
handlerLiveHoles: envelope.lh,
|
|
1823
1849
|
transitionWhen: envelope.tw,
|
|
1824
1850
|
navigationOnly: envelope.no,
|
|
@@ -1908,6 +1934,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
1908
1934
|
ta: taggedAt,
|
|
1909
1935
|
i: entry.initialTheme,
|
|
1910
1936
|
sn: entry.snapshot,
|
|
1937
|
+
dk: entry.docKey,
|
|
1911
1938
|
lh: entry.handlerLiveHoles,
|
|
1912
1939
|
tw: entry.transitionWhen,
|
|
1913
1940
|
no: entry.navigationOnly,
|
|
@@ -2817,7 +2844,7 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
2817
2844
|
private async kvGetSegment(
|
|
2818
2845
|
key: string,
|
|
2819
2846
|
opts?: { suppressRevalidate?: boolean },
|
|
2820
|
-
): Promise<CacheGetResult | null> {
|
|
2847
|
+
): Promise<CacheGetResult | null | CacheReadError> {
|
|
2821
2848
|
if (!this.kv) return null;
|
|
2822
2849
|
|
|
2823
2850
|
try {
|
|
@@ -2886,7 +2913,15 @@ export class CFCacheStore<TEnv = unknown> implements SegmentCacheStore<TEnv> {
|
|
|
2886
2913
|
} catch (error) {
|
|
2887
2914
|
reportCacheError(error, "cache-read", "[CFCacheStore] kvGetSegment");
|
|
2888
2915
|
if (this.debug) this.emitDebug({ op: "get", key, outcome: "error" });
|
|
2889
|
-
|
|
2916
|
+
// A KV failure is NOT proof of absence: returning null classified it a
|
|
2917
|
+
// real miss and let the PPR seeded fallback substitute the doc record
|
|
2918
|
+
// for a key partition the store could not actually read. Same sentinel
|
|
2919
|
+
// as get()'s own catch — lookupRouteDetailed classifies it `error` and
|
|
2920
|
+
// the render stays uncached. (A kvGetOrEvict TIMEOUT above stays null
|
|
2921
|
+
// by design: it is a bounded-latency degrade of a likely-healthy read,
|
|
2922
|
+
// and serving the equivalent seeded record there is the fallback
|
|
2923
|
+
// working as intended, not a masked failure.)
|
|
2924
|
+
return CACHE_READ_ERROR;
|
|
2890
2925
|
}
|
|
2891
2926
|
}
|
|
2892
2927
|
|
|
@@ -327,7 +327,13 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
327
327
|
// existing keys and double any host they already include).
|
|
328
328
|
const cacheKey = keyGenerator
|
|
329
329
|
? keyGenerator(url) + segmentHash + typeSuffix
|
|
330
|
-
: cacheKeyBase(
|
|
330
|
+
: cacheKeyBase(
|
|
331
|
+
url.host,
|
|
332
|
+
url.pathname,
|
|
333
|
+
url.searchParams,
|
|
334
|
+
undefined,
|
|
335
|
+
requestCtx?._searchParamsFilter,
|
|
336
|
+
) +
|
|
331
337
|
segmentHash +
|
|
332
338
|
typeSuffix;
|
|
333
339
|
// 1. Check cache
|
package/src/cache/index.ts
CHANGED
|
@@ -7,7 +7,9 @@ export type {
|
|
|
7
7
|
ShellCacheEntry,
|
|
8
8
|
SerializedSegmentData,
|
|
9
9
|
SegmentHandleData,
|
|
10
|
+
CacheReadError,
|
|
10
11
|
} from "./types.js";
|
|
12
|
+
export { CACHE_READ_ERROR } from "./types.js";
|
|
11
13
|
|
|
12
14
|
export { MemorySegmentCacheStore } from "./memory-segment-store.js";
|
|
13
15
|
|
|
@@ -39,6 +41,11 @@ export {
|
|
|
39
41
|
VERCEL_MAX_TAG_BYTES,
|
|
40
42
|
} from "./vercel/index.js";
|
|
41
43
|
|
|
44
|
+
export {
|
|
45
|
+
TRACKING_SEARCH_PARAMS,
|
|
46
|
+
type CacheSearchParams,
|
|
47
|
+
} from "./search-params-filter.js";
|
|
48
|
+
|
|
42
49
|
export { CacheScope, createCacheScope } from "./cache-scope.js";
|
|
43
50
|
|
|
44
51
|
export {
|