@rangojs/router 0.0.0-experimental.32 → 0.0.0-experimental.3232cd17
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 +4 -0
- package/README.md +198 -44
- package/dist/bin/rango.js +287 -105
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3248 -1117
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +73 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +107 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +245 -21
- package/skills/caching/SKILL.md +302 -6
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +270 -30
- package/skills/host-router/SKILL.md +82 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +49 -5
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +294 -30
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +203 -7
- package/skills/prerender/SKILL.md +123 -100
- package/skills/rango/SKILL.md +250 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +122 -47
- package/skills/route/SKILL.md +97 -5
- package/skills/router-setup/SKILL.md +90 -5
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +329 -27
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +67 -40
- 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/app-version.ts +14 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +86 -147
- 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/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +148 -19
- package/src/browser/navigation-client.ts +187 -67
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +76 -67
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/partial-update.ts +123 -94
- package/src/browser/prefetch/cache.ts +214 -36
- package/src/browser/prefetch/fetch.ts +260 -38
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +126 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +93 -11
- package/src/browser/react/NavigationProvider.tsx +115 -34
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +49 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -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-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +22 -5
- 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 +46 -11
- 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 +52 -1
- package/src/browser/rsc-router.tsx +215 -76
- package/src/browser/scroll-restoration.ts +46 -39
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +176 -50
- package/src/browser/types.ts +95 -11
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +137 -32
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +9 -2
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +278 -96
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +149 -43
- package/src/cache/cache-scope.ts +148 -81
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2550 -93
- package/src/cache/cf/index.ts +11 -17
- package/src/cache/document-cache.ts +78 -27
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +108 -290
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- 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 +52 -26
- package/src/index.ts +100 -38
- package/src/internal-debug.ts +2 -4
- 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/network-error-thrower.tsx +1 -6
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +37 -41
- package/src/prerender.ts +198 -82
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +437 -274
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +113 -37
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +52 -10
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -17
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +108 -9
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +45 -22
- package/src/router/handler-context.ts +83 -41
- package/src/router/intercept-resolution.ts +25 -23
- package/src/router/lazy-includes.ts +19 -53
- package/src/router/loader-resolution.ts +213 -30
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +49 -45
- package/src/router/match-api.ts +120 -204
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +27 -6
- package/src/router/match-middleware/cache-lookup.ts +205 -249
- package/src/router/match-middleware/cache-store.ts +45 -32
- package/src/router/match-middleware/intercept-resolution.ts +8 -28
- package/src/router/match-middleware/segment-resolution.ts +52 -18
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +104 -40
- package/src/router/metrics.ts +5 -34
- package/src/router/middleware-types.ts +13 -142
- package/src/router/middleware.ts +173 -143
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +109 -63
- package/src/router/prerender-match.ts +190 -54
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +63 -55
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +6 -28
- package/src/router/router-interfaces.ts +100 -35
- package/src/router/router-options.ts +91 -11
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +242 -75
- package/src/router/segment-resolution/helpers.ts +63 -24
- package/src/router/segment-resolution/loader-cache.ts +41 -37
- package/src/router/segment-resolution/revalidation.ts +456 -372
- 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 +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +2 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +91 -46
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +134 -43
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +492 -383
- package/src/rsc/helpers.ts +162 -46
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +30 -3
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +90 -63
- package/src/rsc/rsc-rendering.ts +56 -54
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +74 -67
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/types.ts +25 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +134 -0
- package/src/segment-system.tsx +272 -129
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +309 -61
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +26 -24
- package/src/server/loader-registry.ts +10 -28
- package/src/server/request-context.ts +338 -126
- package/src/ssr/index.tsx +23 -15
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -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 +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -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 +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -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 +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +233 -81
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +107 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +37 -14
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +58 -11
- package/src/urls/path-helper.ts +57 -111
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +346 -89
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +36 -38
- package/src/vite/discovery/discover-routers.ts +130 -85
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +192 -99
- 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 +51 -6
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin-types.ts +187 -69
- package/src/vite/plugins/cjs-to-esm.ts +8 -18
- 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 +49 -98
- package/src/vite/plugins/expose-id-utils.ts +11 -50
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
- package/src/vite/plugins/expose-internal-ids.ts +554 -317
- package/src/vite/plugins/performance-tracks.ts +89 -0
- 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 +258 -0
- package/src/vite/plugins/version-injector.ts +21 -25
- package/src/vite/plugins/version-plugin.ts +41 -20
- package/src/vite/plugins/virtual-entries.ts +2 -17
- package/src/vite/rango.ts +257 -289
- package/src/vite/router-discovery.ts +930 -140
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -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 +27 -29
- package/src/vite/utils/shared-utils.ts +92 -42
- 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/router/middleware-cookies.ts +0 -55
package/src/cache/cf/index.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* - CACHE_STALE_AT_HEADER - Header containing staleness timestamp
|
|
9
|
-
* - CACHE_STATUS_HEADER - Header containing HIT/REVALIDATING status
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
// Public API
|
|
13
|
-
export { CFCacheStore, type CFCacheStoreOptions } from "./cf-cache-store.js";
|
|
1
|
+
export {
|
|
2
|
+
CFCacheStore,
|
|
3
|
+
type CFCacheStoreOptions,
|
|
4
|
+
type CFCacheDebug,
|
|
5
|
+
type CFCacheReadDebugEvent,
|
|
6
|
+
type KVNamespace,
|
|
7
|
+
} from "./cf-cache-store.js";
|
|
14
8
|
|
|
15
|
-
// Header constants for debugging and inspection
|
|
16
9
|
export {
|
|
17
10
|
CACHE_STALE_AT_HEADER,
|
|
18
11
|
CACHE_STATUS_HEADER,
|
|
12
|
+
CACHE_REVALIDATING_AT_HEADER,
|
|
19
13
|
} from "./cf-cache-store.js";
|
|
20
14
|
|
|
21
|
-
// Internal exports (re-exported for backwards compatibility, marked @internal in source)
|
|
22
15
|
export {
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
EDGE_LOOKUP_TIMEOUT_MS,
|
|
17
|
+
EDGE_READ_TIMEOUT_MS,
|
|
18
|
+
KV_READ_TIMEOUT_MS,
|
|
25
19
|
} from "./cf-cache-store.js";
|
|
@@ -12,22 +12,25 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type { MiddlewareFn, MiddlewareContext } from "../router/middleware.js";
|
|
15
|
-
import {
|
|
15
|
+
import { hasPerClientSignal } from "../browser/cookie-name.js";
|
|
16
|
+
import {
|
|
17
|
+
getRequestContext,
|
|
18
|
+
type RequestContext,
|
|
19
|
+
} from "../server/request-context.js";
|
|
20
|
+
import { mayNeedSSR } from "../rsc/ssr-setup.js";
|
|
16
21
|
import { sortedSearchString } from "./cache-key-utils.js";
|
|
17
22
|
import { runBackground } from "./background-task.js";
|
|
23
|
+
import { reportCacheError } from "./cache-error.js";
|
|
18
24
|
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// Constants
|
|
21
|
-
// ============================================================================
|
|
22
|
-
|
|
23
|
-
/** Header indicating cache status for debugging */
|
|
24
25
|
const CACHE_STATUS_HEADER = "x-document-cache-status";
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
function collectRequestTags(
|
|
28
|
+
requestCtx: RequestContext | undefined,
|
|
29
|
+
): string[] | undefined {
|
|
30
|
+
const tags = requestCtx?._requestTags;
|
|
31
|
+
return tags && tags.size > 0 ? [...tags] : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
31
34
|
function hashSegmentIds(segmentIds: string): string {
|
|
32
35
|
if (!segmentIds) return "";
|
|
33
36
|
|
|
@@ -36,12 +39,9 @@ function hashSegmentIds(segmentIds: string): string {
|
|
|
36
39
|
const char = segmentIds.charCodeAt(i);
|
|
37
40
|
hash = ((hash << 5) - hash + char) | 0;
|
|
38
41
|
}
|
|
39
|
-
// Convert to base36 for shorter string, take absolute value
|
|
40
42
|
return Math.abs(hash).toString(36);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
// ============================================================================
|
|
44
|
-
// Cache Control Parsing
|
|
45
45
|
// ============================================================================
|
|
46
46
|
|
|
47
47
|
interface CacheDirectives {
|
|
@@ -55,6 +55,16 @@ interface CacheDirectives {
|
|
|
55
55
|
function parseCacheControl(header: string | null): CacheDirectives | null {
|
|
56
56
|
if (!header) return null;
|
|
57
57
|
|
|
58
|
+
// RFC 7234: in a SHARED cache, `private` and `no-store` forbid storage and
|
|
59
|
+
// MUST win over `s-maxage` even though `private, s-maxage` is contradictory.
|
|
60
|
+
// The document cache is a shared edge store, so refuse both regardless of any
|
|
61
|
+
// s-maxage / stale-while-revalidate also present. Match standalone directive
|
|
62
|
+
// tokens (start/end, whitespace, comma, semicolon, or `=` bounded), not a
|
|
63
|
+
// substring, so a value containing "private" cannot false-veto.
|
|
64
|
+
if (/(^|[\s,;])(private|no-store)(?=$|[\s,;=])/i.test(header)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
58
68
|
const directives: CacheDirectives = {};
|
|
59
69
|
|
|
60
70
|
// Parse s-maxage
|
|
@@ -86,6 +96,16 @@ function shouldCacheResponse(response: Response): CacheDirectives | null {
|
|
|
86
96
|
return null;
|
|
87
97
|
}
|
|
88
98
|
|
|
99
|
+
// Never cache a per-client signal into a SHARED response store. A Set-Cookie
|
|
100
|
+
// (e.g. a rango state rotation from invalidateClientCache(), or any cookie a
|
|
101
|
+
// loader set) would be replayed to every client on a hit — pinning them to
|
|
102
|
+
// one value and even rolling a rotated client back to a prior one. The
|
|
103
|
+
// x-rango-keep-cache directive header is the mirror image: a replayed "keep"
|
|
104
|
+
// would suppress invalidation for every replayed client. Refuse both.
|
|
105
|
+
if (hasPerClientSignal(response.headers)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
89
109
|
const cacheControl = response.headers.get("Cache-Control");
|
|
90
110
|
return parseCacheControl(cacheControl);
|
|
91
111
|
}
|
|
@@ -204,18 +224,24 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
204
224
|
): Promise<Response> {
|
|
205
225
|
const url = ctx.url;
|
|
206
226
|
|
|
227
|
+
// Use the original request URL for _rsc* param detection and cache key
|
|
228
|
+
// differentiation. ctx.url is stripped of _rsc* params by the middleware
|
|
229
|
+
// pipeline (stripInternalParams), so _rsc_partial, _rsc_segments, etc.
|
|
230
|
+
// are not visible on ctx.url in production.
|
|
231
|
+
const rawUrl = new URL(ctx.request.url);
|
|
232
|
+
|
|
207
233
|
// Only cache GET requests — mutations and other methods must not be cached
|
|
208
234
|
if (ctx.request.method !== "GET") {
|
|
209
235
|
return next();
|
|
210
236
|
}
|
|
211
237
|
|
|
212
238
|
// Skip RSC action requests (mutations shouldn't be cached)
|
|
213
|
-
if (
|
|
239
|
+
if (rawUrl.searchParams.has("_rsc_action")) {
|
|
214
240
|
return next();
|
|
215
241
|
}
|
|
216
242
|
|
|
217
243
|
// Skip loader requests (have their own caching)
|
|
218
|
-
if (
|
|
244
|
+
if (rawUrl.searchParams.has("_rsc_loader")) {
|
|
219
245
|
return next();
|
|
220
246
|
}
|
|
221
247
|
|
|
@@ -241,9 +267,12 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
241
267
|
return next();
|
|
242
268
|
}
|
|
243
269
|
|
|
244
|
-
// Determine request type for cache key differentiation
|
|
245
|
-
|
|
246
|
-
|
|
270
|
+
// Determine request type for cache key differentiation.
|
|
271
|
+
// Uses rawUrl for _rsc* param checks and mayNeedSSR for Accept-based
|
|
272
|
+
// detection. Full-document RSC fetches must not share the HTML cache slot.
|
|
273
|
+
const isPartial = rawUrl.searchParams.has("_rsc_partial");
|
|
274
|
+
const isRscRequest = !mayNeedSSR(ctx.request, rawUrl);
|
|
275
|
+
const typeLabel = isRscRequest ? "RSC" : "HTML";
|
|
247
276
|
|
|
248
277
|
// Track whether next() has been called so the catch block knows
|
|
249
278
|
// whether it is safe to fall through to the handler.
|
|
@@ -254,10 +283,10 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
254
283
|
// gracefully to the origin handler instead of rejecting the request.
|
|
255
284
|
// This is a deliberate fail-open-to-origin policy: the fallback is
|
|
256
285
|
// "serve uncached from origin", not "use a different cache key".
|
|
257
|
-
const clientSegments =
|
|
286
|
+
const clientSegments = rawUrl.searchParams.get("_rsc_segments") || "";
|
|
258
287
|
const segmentHash =
|
|
259
288
|
isPartial && clientSegments ? `:${hashSegmentIds(clientSegments)}` : "";
|
|
260
|
-
const typeSuffix =
|
|
289
|
+
const typeSuffix = isRscRequest ? ":rsc" : ":html";
|
|
261
290
|
|
|
262
291
|
let searchSuffix = "";
|
|
263
292
|
if (!keyGenerator) {
|
|
@@ -293,17 +322,26 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
293
322
|
const fresh = await next();
|
|
294
323
|
const directives = shouldCacheResponse(fresh);
|
|
295
324
|
|
|
296
|
-
if (directives) {
|
|
325
|
+
if (directives && fresh.body) {
|
|
326
|
+
// Background revalidation: nothing streams to a client, so drain
|
|
327
|
+
// the fresh render fully before snapshotting tags (same
|
|
328
|
+
// render-complete barrier as the miss path).
|
|
329
|
+
const body = await new Response(fresh.body).arrayBuffer();
|
|
297
330
|
await store.putResponse!(
|
|
298
331
|
cacheKey,
|
|
299
|
-
fresh,
|
|
332
|
+
new Response(body, fresh),
|
|
300
333
|
directives.sMaxAge!,
|
|
301
334
|
directives.staleWhileRevalidate,
|
|
335
|
+
collectRequestTags(requestCtx),
|
|
302
336
|
);
|
|
303
337
|
log(`[DocumentCache] REVALIDATED ${typeLabel}: ${url.pathname}`);
|
|
304
338
|
}
|
|
305
339
|
} catch (error) {
|
|
306
|
-
|
|
340
|
+
reportCacheError(
|
|
341
|
+
error,
|
|
342
|
+
"cache-write",
|
|
343
|
+
"[DocumentCache] revalidation",
|
|
344
|
+
);
|
|
307
345
|
}
|
|
308
346
|
});
|
|
309
347
|
|
|
@@ -336,14 +374,27 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
336
374
|
// Clone response for caching (non-blocking)
|
|
337
375
|
runBackground(requestCtx, async () => {
|
|
338
376
|
try {
|
|
377
|
+
// Drain the cache copy fully BEFORE snapshotting tags. Tags from
|
|
378
|
+
// Suspense-streamed "use cache"/cacheTag and loaders are recorded as
|
|
379
|
+
// each value resolves during the RSC/HTML render, which completes
|
|
380
|
+
// only when the stream ends - the handler-settlement barrier is too
|
|
381
|
+
// early. Buffering the body (the client streams the other tee branch,
|
|
382
|
+
// unaffected) is the render-complete barrier that keeps the cached
|
|
383
|
+
// body and its tag set consistent.
|
|
384
|
+
const body = await new Response(cacheStream).arrayBuffer();
|
|
339
385
|
await store.putResponse!(
|
|
340
386
|
cacheKey,
|
|
341
|
-
new Response(
|
|
387
|
+
new Response(body, originalResponse),
|
|
342
388
|
directives.sMaxAge!,
|
|
343
389
|
directives.staleWhileRevalidate,
|
|
390
|
+
collectRequestTags(requestCtx),
|
|
344
391
|
);
|
|
345
392
|
} catch (error) {
|
|
346
|
-
|
|
393
|
+
reportCacheError(
|
|
394
|
+
error,
|
|
395
|
+
"cache-write",
|
|
396
|
+
"[DocumentCache] cache write",
|
|
397
|
+
);
|
|
347
398
|
}
|
|
348
399
|
});
|
|
349
400
|
|
|
@@ -356,7 +407,7 @@ export function createDocumentCacheMiddleware<TEnv = any>(
|
|
|
356
407
|
// No cache headers - pass through
|
|
357
408
|
return originalResponse;
|
|
358
409
|
} catch (error) {
|
|
359
|
-
|
|
410
|
+
reportCacheError(error, "cache-read", "[DocumentCache] middleware");
|
|
360
411
|
if (handlerCalled) {
|
|
361
412
|
// Post-handler failure (e.g. body.tee()): do not call next() again
|
|
362
413
|
// as that would re-run handler side effects.
|
|
@@ -9,6 +9,69 @@
|
|
|
9
9
|
import type { ResolvedSegment } from "../types.js";
|
|
10
10
|
import type { HandleStore } from "../server/handle-store.js";
|
|
11
11
|
import type { SegmentHandleData } from "./types.js";
|
|
12
|
+
import { serializeResult, deserializeResult } from "./segment-codec.js";
|
|
13
|
+
|
|
14
|
+
const HANDLE_ENCODE_TIMEOUT_MS = 5000;
|
|
15
|
+
|
|
16
|
+
type HandleRecord = Record<string, SegmentHandleData>;
|
|
17
|
+
|
|
18
|
+
function hasHandleData(handles: HandleRecord): boolean {
|
|
19
|
+
for (const segId in handles) {
|
|
20
|
+
for (const _ in handles[segId]) return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function withTimeout<T>(p: Promise<T>, ms: number, onTimeout: T): Promise<T> {
|
|
26
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
27
|
+
const timeout = new Promise<T>((resolve) => {
|
|
28
|
+
timer = setTimeout(() => resolve(onTimeout), ms);
|
|
29
|
+
});
|
|
30
|
+
return Promise.race([
|
|
31
|
+
p.then(
|
|
32
|
+
(v) => {
|
|
33
|
+
clearTimeout(timer);
|
|
34
|
+
return v;
|
|
35
|
+
},
|
|
36
|
+
(e) => {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
throw e;
|
|
39
|
+
},
|
|
40
|
+
),
|
|
41
|
+
timeout,
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function encodeHandles(handles: HandleRecord): Promise<string> {
|
|
46
|
+
if (!hasHandleData(handles)) return "";
|
|
47
|
+
return encodeHandleValue(handles);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function decodeHandles(encoded: string): Promise<HandleRecord | null> {
|
|
51
|
+
return decodeHandleValue<HandleRecord>(encoded);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function encodeHandleValue(value: unknown): Promise<string> {
|
|
55
|
+
const encoded = await withTimeout(
|
|
56
|
+
serializeResult(value),
|
|
57
|
+
HANDLE_ENCODE_TIMEOUT_MS,
|
|
58
|
+
null,
|
|
59
|
+
);
|
|
60
|
+
return encoded ?? "";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Decode a Flight-encoded handle-data string. Returns null on any decode
|
|
65
|
+
* failure so the caller can skip handle restore without discarding valid
|
|
66
|
+
* cached/prerendered segments.
|
|
67
|
+
*/
|
|
68
|
+
export async function decodeHandleValue<T>(encoded: string): Promise<T | null> {
|
|
69
|
+
try {
|
|
70
|
+
return await deserializeResult<T>(encoded);
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
12
75
|
|
|
13
76
|
/**
|
|
14
77
|
* Capture handle data for a set of segments from the handle store.
|
package/src/cache/index.ts
CHANGED
|
@@ -1,43 +1,46 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache Store
|
|
3
|
-
*
|
|
4
|
-
* Server-side caching for RSC segments and loader data.
|
|
5
|
-
*
|
|
6
|
-
* Main exports for users:
|
|
7
|
-
* - SegmentCacheStore - Interface for implementing custom cache stores
|
|
8
|
-
* - MemorySegmentCacheStore - In-memory cache for development/testing
|
|
9
|
-
* - CFCacheStore - Cloudflare edge cache store for production
|
|
10
|
-
* - CacheScope / createCacheScope - Request-scoped cache provider
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Segment cache store types and implementations
|
|
14
1
|
export type {
|
|
15
2
|
SegmentCacheStore,
|
|
16
|
-
SegmentCacheProvider,
|
|
17
3
|
CachedEntryData,
|
|
18
|
-
CachedEntryResult,
|
|
19
4
|
CacheGetResult,
|
|
5
|
+
CacheItemResult,
|
|
6
|
+
CacheItemOptions,
|
|
20
7
|
SerializedSegmentData,
|
|
21
8
|
SegmentHandleData,
|
|
22
|
-
CacheConfig,
|
|
23
|
-
CacheConfigOrFactory,
|
|
24
9
|
} from "./types.js";
|
|
25
10
|
|
|
26
11
|
export { MemorySegmentCacheStore } from "./memory-segment-store.js";
|
|
27
12
|
|
|
28
|
-
// Cloudflare cache store
|
|
29
13
|
export {
|
|
30
14
|
CFCacheStore,
|
|
31
15
|
type CFCacheStoreOptions,
|
|
16
|
+
type CFCacheDebug,
|
|
17
|
+
type CFCacheReadDebugEvent,
|
|
18
|
+
type KVNamespace,
|
|
32
19
|
CACHE_STALE_AT_HEADER,
|
|
33
20
|
CACHE_STATUS_HEADER,
|
|
21
|
+
CACHE_REVALIDATING_AT_HEADER,
|
|
22
|
+
EDGE_LOOKUP_TIMEOUT_MS,
|
|
23
|
+
EDGE_READ_TIMEOUT_MS,
|
|
24
|
+
KV_READ_TIMEOUT_MS,
|
|
34
25
|
} from "./cf/index.js";
|
|
35
26
|
|
|
36
|
-
|
|
27
|
+
export {
|
|
28
|
+
VercelCacheStore,
|
|
29
|
+
type VercelCacheStoreOptions,
|
|
30
|
+
type VercelRuntimeCache,
|
|
31
|
+
type VercelCacheDebug,
|
|
32
|
+
type VercelCacheReadDebugEvent,
|
|
33
|
+
type VercelCacheReadOutcome,
|
|
34
|
+
VERCEL_MAX_ITEM_BYTES,
|
|
35
|
+
VERCEL_MAX_TAGS_PER_ITEM,
|
|
36
|
+
VERCEL_MAX_TAG_BYTES,
|
|
37
|
+
} from "./vercel/index.js";
|
|
38
|
+
|
|
37
39
|
export { CacheScope, createCacheScope } from "./cache-scope.js";
|
|
38
40
|
|
|
39
|
-
// Document-level cache middleware
|
|
40
41
|
export {
|
|
41
42
|
createDocumentCacheMiddleware,
|
|
42
43
|
type DocumentCacheOptions,
|
|
43
44
|
} from "./document-cache.js";
|
|
45
|
+
|
|
46
|
+
export type { CacheErrorCategory } from "./cache-error.js";
|