@rangojs/router 0.0.0-experimental.9c9afef3 → 0.0.0-experimental.a014d2b7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -0
- package/README.md +245 -49
- package/dist/bin/rango.js +440 -133
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3373 -1176
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +68 -14
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +64 -2
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +224 -32
- package/skills/caching/SKILL.md +279 -17
- package/skills/composability/SKILL.md +27 -3
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +250 -30
- package/skills/host-router/SKILL.md +83 -23
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +87 -18
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +235 -9
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +771 -0
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +77 -7
- package/skills/prerender/SKILL.md +172 -125
- package/skills/rango/SKILL.md +251 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +123 -48
- package/skills/route/SKILL.md +70 -5
- package/skills/router-setup/SKILL.md +65 -8
- package/skills/scripts/SKILL.md +179 -0
- 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 +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/typesafety/SKILL.md +322 -29
- package/skills/use-cache/SKILL.md +57 -14
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +1 -66
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +192 -150
- 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/navigation-bridge.ts +131 -30
- package/src/browser/navigation-client.ts +186 -100
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +157 -74
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +165 -112
- package/src/browser/prefetch/cache.ts +205 -62
- package/src/browser/prefetch/fetch.ts +347 -39
- package/src/browser/prefetch/queue.ts +42 -8
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +102 -15
- package/src/browser/react/NavigationProvider.tsx +295 -119
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/deferred-handle-resolution.ts +75 -0
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +23 -69
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +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 +99 -8
- package/src/browser/rsc-router.tsx +114 -24
- package/src/browser/scroll-restoration.ts +37 -22
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +222 -72
- package/src/browser/types.ts +102 -12
- 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 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +165 -36
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +125 -24
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +260 -94
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +224 -41
- package/src/cache/cache-scope.ts +188 -82
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +1989 -378
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +89 -21
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +10 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +44 -21
- package/src/client.tsx +119 -290
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +62 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +37 -8
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +99 -13
- package/src/index.ts +139 -19
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +37 -41
- package/src/prerender.ts +198 -82
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +461 -304
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +143 -69
- package/src/route-definition/index.ts +4 -2
- package/src/route-definition/redirect.ts +51 -10
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +37 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +164 -17
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +52 -31
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +48 -24
- package/src/router/lazy-includes.ts +15 -52
- package/src/router/loader-resolution.ts +268 -56
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +40 -42
- package/src/router/match-api.ts +124 -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 +40 -24
- package/src/router/match-middleware/cache-lookup.ts +170 -276
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +45 -14
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +87 -39
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -140
- package/src/router/middleware.ts +266 -169
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +132 -90
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +195 -56
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +3 -28
- package/src/router/router-interfaces.ts +115 -35
- package/src/router/router-options.ts +172 -15
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +162 -84
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +76 -39
- package/src/router/segment-resolution/revalidation.ts +351 -321
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +163 -59
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +157 -54
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +655 -529
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +122 -31
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +131 -14
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +109 -74
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +287 -115
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +29 -9
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +236 -202
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +224 -52
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +38 -46
- package/src/server/request-context.ts +401 -173
- package/src/ssr/index.tsx +24 -16
- 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 +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +581 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +125 -71
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +40 -11
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +12 -7
- package/src/types/segments.ts +136 -15
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +68 -18
- 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 -19
- 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 +214 -132
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +57 -4
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +6 -0
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +178 -5
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +96 -51
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +553 -317
- package/src/vite/plugins/performance-tracks.ts +64 -170
- package/src/vite/plugins/refresh-cmd.ts +89 -27
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +39 -25
- package/src/vite/rango.ts +118 -114
- package/src/vite/router-discovery.ts +941 -142
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +81 -34
- package/src/vite/utils/shared-utils.ts +92 -42
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/debug-channel.ts +0 -93
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Cache key resolution (3-tier, matching CacheScope.resolveKey):
|
|
9
9
|
* 1. options.key(requestCtx) — full override
|
|
10
10
|
* 2. store.keyGenerator(requestCtx, defaultKey) — store-level modification
|
|
11
|
-
* 3. loader:{loaderId}:{pathname}:{sortedParams} — default
|
|
11
|
+
* 3. loader:{loaderId}:{host}{pathname}:{sortedParams} — default
|
|
12
12
|
*
|
|
13
13
|
* Values are serialized via RSC Flight (serializeResult/deserializeResult),
|
|
14
14
|
* supporting ReactNode, Promises, null, and all RSC-serializable types.
|
|
@@ -19,18 +19,23 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { LoaderEntry } from "../../server/context.js";
|
|
22
|
-
import type { HandlerContext } from "../../types.js";
|
|
22
|
+
import type { HandlerContext, InternalHandlerContext } from "../../types.js";
|
|
23
23
|
import { INTERNAL_RANGO_DEBUG } from "../../internal-debug.js";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
getRequestContext,
|
|
26
|
+
runWithRequestContext,
|
|
27
|
+
} from "../../server/request-context.js";
|
|
25
28
|
import { sortedRouteParams } from "../../cache/cache-key-utils.js";
|
|
26
29
|
import {
|
|
27
30
|
resolveTtl,
|
|
28
31
|
resolveSwrWindow,
|
|
29
32
|
resolveCacheKey,
|
|
30
33
|
resolveCacheStore,
|
|
34
|
+
resolveTagsOption,
|
|
31
35
|
DEFAULT_ROUTE_TTL,
|
|
32
36
|
} from "../../cache/cache-policy.js";
|
|
33
37
|
import { readThroughItem } from "../../cache/read-through-swr.js";
|
|
38
|
+
import { recordRequestTags } from "../../cache/cache-tag.js";
|
|
34
39
|
// Lazy-loaded to avoid pulling @vitejs/plugin-rsc/rsc into modules that
|
|
35
40
|
// import segment-resolution but never use loader caching.
|
|
36
41
|
let _serializeResult: typeof import("../../cache/segment-codec.js").serializeResult;
|
|
@@ -55,12 +60,13 @@ function debugLoaderCacheLog(message: string): void {
|
|
|
55
60
|
|
|
56
61
|
function getDefaultLoaderCacheKey(
|
|
57
62
|
loaderId: string,
|
|
63
|
+
host: string,
|
|
58
64
|
pathname: string,
|
|
59
65
|
params: Record<string, string>,
|
|
60
66
|
): string {
|
|
61
67
|
const paramStr = sortedRouteParams(params);
|
|
62
68
|
const base = paramStr ? `${pathname}:${paramStr}` : pathname;
|
|
63
|
-
return `loader:${loaderId}:${base}`;
|
|
69
|
+
return `loader:${loaderId}:${host}${base}`;
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
/**
|
|
@@ -74,7 +80,13 @@ async function resolveLoaderKey(
|
|
|
74
80
|
params: Record<string, string>,
|
|
75
81
|
): Promise<string> {
|
|
76
82
|
const options = loaderEntry.cache!.options;
|
|
77
|
-
|
|
83
|
+
// The host is part of the loader cache identity, matching the route-level
|
|
84
|
+
// cache (cache-scope getCacheKeyBase: `${host}${pathname}`) and "use cache"
|
|
85
|
+
// (cache-runtime pushes ctx.url.host). Without it, a multi-tenant host router
|
|
86
|
+
// serving the same pathname for different hosts would leak one host's cached
|
|
87
|
+
// loader data to another.
|
|
88
|
+
const host = getRequestContext()?.url?.host ?? "localhost";
|
|
89
|
+
const defaultKey = getDefaultLoaderCacheKey(loaderId, host, pathname, params);
|
|
78
90
|
if (options === false) return defaultKey;
|
|
79
91
|
return resolveCacheKey(options.key, store, defaultKey, "LoaderCache");
|
|
80
92
|
}
|
|
@@ -87,23 +99,8 @@ async function resolveLoaderKey(
|
|
|
87
99
|
*/
|
|
88
100
|
function resolveTags(loaderEntry: LoaderEntry): string[] | undefined {
|
|
89
101
|
const options = loaderEntry.cache?.options;
|
|
90
|
-
if (!options
|
|
91
|
-
|
|
92
|
-
if (typeof options.tags === "function") {
|
|
93
|
-
const requestCtx = getRequestContext();
|
|
94
|
-
if (!requestCtx) return undefined;
|
|
95
|
-
try {
|
|
96
|
-
return options.tags(requestCtx);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error(
|
|
99
|
-
`[LoaderCache] Tags function failed, caching without tags:`,
|
|
100
|
-
error,
|
|
101
|
-
);
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return options.tags;
|
|
102
|
+
if (!options) return undefined;
|
|
103
|
+
return resolveTagsOption(options.tags, getRequestContext(), "LoaderCache");
|
|
107
104
|
}
|
|
108
105
|
|
|
109
106
|
function getLoaderStore(
|
|
@@ -119,6 +116,11 @@ function getLoaderStore(
|
|
|
119
116
|
*
|
|
120
117
|
* When the LoaderEntry has no cache config, delegates directly to ctx.use(loader).
|
|
121
118
|
* When cached, checks store first and stores on miss via waitUntil.
|
|
119
|
+
*
|
|
120
|
+
* Loader metering is NOT done here — it lives at the ctx.use execution funnel
|
|
121
|
+
* (observePhase; see instrument.ts). A cache HIT returns without calling ctx.use,
|
|
122
|
+
* so it emits no loader phase (the loader did not execute; the hit is only a
|
|
123
|
+
* LoaderCache debug log).
|
|
122
124
|
*/
|
|
123
125
|
export function resolveLoaderData<TEnv>(
|
|
124
126
|
loaderEntry: LoaderEntry,
|
|
@@ -148,15 +150,51 @@ export function resolveLoaderData<TEnv>(
|
|
|
148
150
|
|
|
149
151
|
const loaderId = loaderEntry.loader.$$id;
|
|
150
152
|
|
|
153
|
+
// A handler that later awaits this same loader via ctx.use(loader) must get
|
|
154
|
+
// THIS memoized promise, not a fresh execution. Rather than rebind ctx.use
|
|
155
|
+
// once per cached loader (O(N) chained wrappers + a synchronous
|
|
156
|
+
// capture-before-overwrite invariant), install a single stable interceptor on
|
|
157
|
+
// the first cached loader that consults a per-ctx override table, then just
|
|
158
|
+
// prime the table for each subsequent cached loader. The captured pre-
|
|
159
|
+
// interceptor `originalUse` (whatever setup mode installed it) runs the
|
|
160
|
+
// cache-miss execute, so a loader never awaits its own in-flight promise.
|
|
161
|
+
const internal = ctx as InternalHandlerContext<any, TEnv>;
|
|
162
|
+
let overrides = internal._loaderCacheOverrides;
|
|
163
|
+
if (!overrides) {
|
|
164
|
+
overrides = internal._loaderCacheOverrides = new Map();
|
|
165
|
+
const originalUse = ctx.use;
|
|
166
|
+
internal._loaderCacheOriginalUse = originalUse;
|
|
167
|
+
ctx.use = ((item: any) => {
|
|
168
|
+
const cached = overrides!.get(item?.$$id);
|
|
169
|
+
if (cached) return cached;
|
|
170
|
+
return originalUse(item);
|
|
171
|
+
}) as typeof ctx.use;
|
|
172
|
+
}
|
|
173
|
+
const runMiss = internal._loaderCacheOriginalUse!;
|
|
174
|
+
|
|
175
|
+
// Dedup the cache read-through across repeated resolutions of the SAME
|
|
176
|
+
// loaderId in one request. An orphan layout with parallel slots inherits its
|
|
177
|
+
// parent route's loaders, so resolveOrphanLayout (fresh.ts) re-resolves the
|
|
178
|
+
// parent's loaders under a different shortCode — calling resolveLoaderData
|
|
179
|
+
// again for the same loaderId. The cache key (loader:{loaderId}:{host}
|
|
180
|
+
// {pathname}:{sortedParams}) does not include the shortCode and ctx/params
|
|
181
|
+
// are identical, so both resolutions produce the same data. Reuse the already
|
|
182
|
+
// in-flight dataPromise instead of issuing a second getItem/setItem (e.g. a
|
|
183
|
+
// second KV round-trip) for one logical cached loader. The shortCode only
|
|
184
|
+
// affects the emitted segmentId in resolveLoaders, not the cached value.
|
|
185
|
+
const existing = overrides.get(loaderId);
|
|
186
|
+
if (existing) return existing;
|
|
187
|
+
|
|
188
|
+
// Compute ttl/swr/tags only AFTER the dedup short-circuit: a deduped second
|
|
189
|
+
// resolution of the same loaderId (the orphan-layout inheritance path) must
|
|
190
|
+
// not re-run the user tags() callback. These values are only consumed inside
|
|
191
|
+
// the read-through below, so they belong here, past the dedup gate.
|
|
151
192
|
const ttl = resolveTtl(options.ttl, store.defaults, DEFAULT_ROUTE_TTL);
|
|
152
193
|
const swrWindow = resolveSwrWindow(options.swr, store.defaults);
|
|
153
194
|
const swr = swrWindow || undefined;
|
|
154
195
|
const tags = resolveTags(loaderEntry);
|
|
196
|
+
recordRequestTags(tags);
|
|
155
197
|
|
|
156
|
-
// Wrap ctx.use() so cache HIT primes the handler's memoization map.
|
|
157
|
-
// ctx.use() closes over the match context's loaderPromises (not request context's).
|
|
158
|
-
// By intercepting ctx.use(), we inject cached data into the correct map.
|
|
159
|
-
const originalUse = ctx.use;
|
|
160
198
|
const dataPromise = (async () => {
|
|
161
199
|
const codec = await getCodec();
|
|
162
200
|
const key = await resolveLoaderKey(
|
|
@@ -167,11 +205,20 @@ export function resolveLoaderData<TEnv>(
|
|
|
167
205
|
ctx.params,
|
|
168
206
|
);
|
|
169
207
|
|
|
208
|
+
// Capture the request context up front (foreground, ALS present) so the
|
|
209
|
+
// background stale revalidation can re-establish it. On workerd a waitUntil
|
|
210
|
+
// task runs detached from the request's I/O context, so a loader body that
|
|
211
|
+
// reads the ambient getRequestContext() would otherwise throw "called
|
|
212
|
+
// outside of a request context" and the revalidation would fail silently.
|
|
213
|
+
// The wrap is applied via wrapBackground (background path only); the
|
|
214
|
+
// foreground miss runs execute() directly since its context is present.
|
|
215
|
+
const requestCtxForExecute = getRequestContext();
|
|
170
216
|
return readThroughItem({
|
|
171
217
|
getItem: (k) => store.getItem!(k),
|
|
172
218
|
setItem: (k, v, o) => store.setItem!(k, v, o),
|
|
173
219
|
key,
|
|
174
|
-
execute: () =>
|
|
220
|
+
execute: () => runMiss(loaderEntry.loader),
|
|
221
|
+
wrapBackground: (run) => runWithRequestContext(requestCtxForExecute, run),
|
|
175
222
|
serialize: (d) => codec.serializeResult(d),
|
|
176
223
|
deserialize: (v) => codec.deserializeResult(v),
|
|
177
224
|
storeOptions: { ttl, swr, tags },
|
|
@@ -179,21 +226,11 @@ export function resolveLoaderData<TEnv>(
|
|
|
179
226
|
onStale: () => debugLoaderCacheLog(`[LoaderCache] STALE: ${key}`),
|
|
180
227
|
onMiss: () => debugLoaderCacheLog(`[LoaderCache] MISS: ${key}`),
|
|
181
228
|
onCached: () => debugLoaderCacheLog(`[LoaderCache] Cached: ${key}`),
|
|
182
|
-
host:
|
|
229
|
+
host: requestCtxForExecute,
|
|
183
230
|
});
|
|
184
231
|
})();
|
|
185
232
|
|
|
186
|
-
|
|
187
|
-
// This is needed because ctx.use() closes over the match context's loaderPromises
|
|
188
|
-
// map which is separate from the request context. By wrapping use(), we intercept
|
|
189
|
-
// the handler's call and return the shared dataPromise.
|
|
190
|
-
const wrappedUse = ((item: any) => {
|
|
191
|
-
if (item === loaderEntry.loader || item?.$$id === loaderId) {
|
|
192
|
-
return dataPromise;
|
|
193
|
-
}
|
|
194
|
-
return originalUse(item);
|
|
195
|
-
}) as typeof ctx.use;
|
|
196
|
-
ctx.use = wrappedUse;
|
|
233
|
+
overrides.set(loaderId, dataPromise);
|
|
197
234
|
|
|
198
235
|
return dataPromise;
|
|
199
236
|
}
|