vinext 1.3.1 → 1.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 +25 -22
- package/THIRD_PARTY_LICENSES.md +47 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -2
- package/dist/build/prerender.js +4 -3
- package/dist/build/report.d.ts +0 -14
- package/dist/build/report.js +1 -51
- package/dist/check.js +4 -7
- package/dist/cli.js +3 -0
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +20 -4
- package/dist/client/navigation-runtime.d.ts +13 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +2 -0
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +52 -2
- package/dist/config/next-config.d.ts +25 -0
- package/dist/config/next-config.js +82 -4
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
- package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
- package/dist/entries/app-rsc-entry.js +17 -49
- package/dist/entries/app-rsc-manifest.js +3 -4
- package/dist/entries/app-ssr-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +36 -9
- package/dist/index.js +112 -90
- package/dist/init-cloudflare.d.ts +1 -3
- package/dist/init-cloudflare.js +10 -48
- package/dist/init-platform.d.ts +2 -0
- package/dist/init-platform.js +4 -0
- package/dist/plugins/extensionless-dynamic-import.js +6 -2
- package/dist/plugins/next-intl-catalog.d.ts +12 -0
- package/dist/plugins/next-intl-catalog.js +85 -0
- package/dist/plugins/pages-node-externals.d.ts +1 -0
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/plugins/use-cache-callable.d.ts +1 -1
- package/dist/plugins/use-cache-callable.js +136 -94
- package/dist/routing/app-route-graph.d.ts +6 -0
- package/dist/routing/app-route-graph.js +9 -1
- package/dist/server/api-handler.js +21 -5
- package/dist/server/app-bfcache-identity.js +1 -1
- package/dist/server/app-browser-entry.js +86 -66
- package/dist/server/app-browser-history-controller.d.ts +5 -4
- package/dist/server/app-browser-history-controller.js +93 -15
- package/dist/server/app-browser-navigation-controller.d.ts +2 -2
- package/dist/server/app-browser-navigation-controller.js +1 -2
- package/dist/server/app-browser-rsc-redirect.js +7 -7
- package/dist/server/app-browser-server-action-client.d.ts +2 -0
- package/dist/server/app-browser-server-action-client.js +5 -4
- package/dist/server/app-browser-state.d.ts +2 -4
- package/dist/server/app-browser-state.js +9 -4
- package/dist/server/app-browser-supplemental-refresh.js +16 -1
- package/dist/server/app-browser-visible-commit.d.ts +1 -1
- package/dist/server/app-browser-visible-commit.js +4 -14
- package/dist/server/app-elements-wire.d.ts +6 -38
- package/dist/server/app-elements-wire.js +4 -41
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-history-state.d.ts +2 -2
- package/dist/server/app-history-state.js +5 -2
- package/dist/server/app-mounted-layouts.d.ts +21 -0
- package/dist/server/app-mounted-layouts.js +67 -0
- package/dist/server/app-optimistic-routing.d.ts +19 -1
- package/dist/server/app-optimistic-routing.js +43 -4
- package/dist/server/app-page-boundary-render.js +10 -14
- package/dist/server/app-page-boundary.js +2 -2
- package/dist/server/app-page-cache-finalizer.d.ts +12 -1
- package/dist/server/app-page-cache-finalizer.js +70 -29
- package/dist/server/app-page-cache.d.ts +13 -1
- package/dist/server/app-page-cache.js +31 -9
- package/dist/server/app-page-dispatch.d.ts +5 -11
- package/dist/server/app-page-dispatch.js +84 -155
- package/dist/server/app-page-element-builder.d.ts +2 -2
- package/dist/server/app-page-element-builder.js +13 -12
- package/dist/server/app-page-execution.d.ts +17 -52
- package/dist/server/app-page-execution.js +102 -95
- package/dist/server/app-page-head.d.ts +13 -0
- package/dist/server/app-page-head.js +44 -16
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
- package/dist/server/app-page-layout-gate.d.ts +35 -0
- package/dist/server/app-page-layout-gate.js +50 -0
- package/dist/server/app-page-params.d.ts +0 -1
- package/dist/server/app-page-params.js +1 -14
- package/dist/server/app-page-probe.d.ts +3 -21
- package/dist/server/app-page-probe.js +4 -37
- package/dist/server/app-page-render.d.ts +2 -13
- package/dist/server/app-page-render.js +103 -234
- package/dist/server/app-page-request.d.ts +1 -3
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +3 -3
- package/dist/server/app-page-route-wiring.d.ts +13 -6
- package/dist/server/app-page-route-wiring.js +86 -63
- package/dist/server/app-page-rsc-render-status.d.ts +27 -1
- package/dist/server/app-page-rsc-render-status.js +121 -13
- package/dist/server/app-page-stream.d.ts +12 -8
- package/dist/server/app-page-stream.js +4 -3
- package/dist/server/app-pages-bridge.d.ts +4 -0
- package/dist/server/app-pages-bridge.js +7 -3
- package/dist/server/app-render-dependency.d.ts +11 -4
- package/dist/server/app-render-dependency.js +86 -38
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-route-handler-cache.js +2 -2
- package/dist/server/app-route-handler-dispatch.js +14 -9
- package/dist/server/app-route-handler-execution.js +11 -5
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +28 -11
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +12 -12
- package/dist/server/app-rsc-cache-busting.js +31 -72
- package/dist/server/app-rsc-error-handler.d.ts +2 -1
- package/dist/server/app-rsc-error-handler.js +10 -2
- package/dist/server/app-rsc-errors.d.ts +8 -0
- package/dist/server/app-rsc-errors.js +11 -1
- package/dist/server/app-rsc-handler.d.ts +5 -5
- package/dist/server/app-rsc-handler.js +80 -83
- package/dist/server/app-rsc-request-normalization.d.ts +10 -16
- package/dist/server/app-rsc-request-normalization.js +12 -18
- package/dist/server/app-rsc-response-finalizer.js +2 -2
- package/dist/server/app-rsc-response-stage.js +9 -15
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +15 -8
- package/dist/server/app-ssr-entry.d.ts +8 -0
- package/dist/server/app-ssr-entry.js +22 -16
- package/dist/server/app-ssr-stream.js +1 -1
- package/dist/server/app-visited-response-cache.d.ts +36 -1
- package/dist/server/app-visited-response-cache.js +46 -5
- package/dist/server/app-worker-stages.d.ts +37 -6
- package/dist/server/app-worker-stages.js +81 -9
- package/dist/server/artifact-compatibility.d.ts +0 -1
- package/dist/server/artifact-compatibility.js +1 -10
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-proof.d.ts +1 -115
- package/dist/server/cache-proof.js +1 -544
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/cacheability-request.js +13 -8
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +6 -4
- package/dist/server/headers.d.ts +6 -3
- package/dist/server/headers.js +9 -5
- package/dist/server/image-optimization.d.ts +5 -0
- package/dist/server/image-optimization.js +6 -1
- package/dist/server/isr-cache.d.ts +8 -2
- package/dist/server/isr-cache.js +30 -2
- package/dist/server/metadata-route-response.js +32 -15
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +57 -12
- package/dist/server/multi-stage.js +13 -1
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/pages-api-route.js +28 -19
- package/dist/server/pages-media-type.d.ts +21 -1
- package/dist/server/pages-media-type.js +69 -5
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +54 -27
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +28 -26
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.d.ts +8 -0
- package/dist/server/pages-request-pipeline.js +2 -2
- package/dist/server/pages-request-stage-entry.js +36 -14
- package/dist/server/pages-response-stage-entry.js +9 -3
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +47 -9
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +15 -4
- package/dist/server/request-pipeline.js +43 -15
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/shared-cache-identity.d.ts +23 -0
- package/dist/server/shared-cache-identity.js +36 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-stages.d.ts +16 -3
- package/dist/server/worker-stages.js +23 -4
- package/dist/shims/cache-handler.js +2 -2
- package/dist/shims/cache-request-state.d.ts +23 -26
- package/dist/shims/cache-request-state.js +22 -57
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +94 -48
- package/dist/shims/cache.d.ts +16 -10
- package/dist/shims/cache.js +47 -36
- package/dist/shims/cacheability-classification.d.ts +2 -0
- package/dist/shims/cdn-cache.d.ts +22 -5
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/client-page-root.js +2 -2
- package/dist/shims/dynamic.js +9 -6
- package/dist/shims/error-boundary.js +2 -2
- package/dist/shims/fetch-cache-state.d.ts +5 -1
- package/dist/shims/fetch-cache-state.js +1 -3
- package/dist/shims/fetch-cache.d.ts +2 -1
- package/dist/shims/fetch-cache.js +39 -25
- package/dist/shims/form.js +2 -2
- package/dist/shims/headers.d.ts +10 -24
- package/dist/shims/headers.js +22 -70
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/link.js +8 -11
- package/dist/shims/metadata.d.ts +23 -21
- package/dist/shims/metadata.js +62 -24
- package/dist/shims/navigation-server.js +1 -1
- package/dist/shims/navigation.d.ts +74 -7
- package/dist/shims/navigation.js +184 -31
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/request-state-types.d.ts +3 -2
- package/dist/shims/slot.d.ts +16 -0
- package/dist/shims/slot.js +44 -9
- package/dist/shims/unified-request-context.d.ts +7 -1
- package/dist/shims/unified-request-context.js +3 -3
- package/dist/utils/cache-control-metadata.d.ts +5 -0
- package/dist/utils/cache-control-metadata.js +9 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/dist/utils/project.d.ts +2 -2
- package/dist/utils/project.js +3 -16
- package/dist/utils/regex.d.ts +5 -0
- package/dist/utils/regex.js +11 -1
- package/dist/utils/text-stream.d.ts +10 -5
- package/dist/utils/text-stream.js +6 -6
- package/package.json +2 -1
- package/dist/build/layout-classification-types.d.ts +0 -60
- package/dist/build/layout-classification-types.js +0 -1
- package/dist/build/layout-classification.d.ts +0 -62
- package/dist/build/layout-classification.js +0 -98
- package/dist/build/route-classification-injector.d.ts +0 -33
- package/dist/build/route-classification-injector.js +0 -59
- package/dist/build/route-classification-manifest.d.ts +0 -54
- package/dist/build/route-classification-manifest.js +0 -143
- package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
- package/dist/server/app-browser-client-reuse-manifest.js +0 -101
- package/dist/server/app-layout-param-observation.d.ts +0 -42
- package/dist/server/app-layout-param-observation.js +0 -168
- package/dist/server/client-reuse-manifest.d.ts +0 -103
- package/dist/server/client-reuse-manifest.js +0 -209
- package/dist/server/skip-cache-proof.d.ts +0 -60
- package/dist/server/skip-cache-proof.js +0 -168
- package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
- package/dist/server/static-layout-client-reuse-proof.js +0 -33
- package/dist/utils/sorted-array.d.ts +0 -8
- package/dist/utils/sorted-array.js +0 -20
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getOrCreateAls } from "./internal/als-registry.js";
|
|
2
2
|
import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
|
|
3
3
|
import { VINEXT_RSC_MARKER_HEADER } from "../server/headers.js";
|
|
4
|
+
import { isInsideWorkStoreScope } from "./internal/work-store-scope.js";
|
|
4
5
|
import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
5
6
|
import { isRouteCacheabilityProbe, recordRouteCacheabilityProbeBailout } from "./cacheability-classification.js";
|
|
6
7
|
import { shareIsolatePromise } from "../server/isolate-shared-promise.js";
|
|
@@ -11,7 +12,7 @@ import { createPprFallbackShellSuspensePromise, trackPprFallbackShellCacheTask }
|
|
|
11
12
|
import { createUseCacheAccessError, markDynamicUsage, recordInvalidDynamicUsageError } from "./internal/headers-state.js";
|
|
12
13
|
import { isDraftModeEnabled } from "./headers.js";
|
|
13
14
|
import { _registerCacheContextAccessor } from "./internal/cache-context-accessor.js";
|
|
14
|
-
import { _hasPendingRevalidatedTag, _setRequestScopedCacheLife, cacheLifeProfiles, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
15
|
+
import { _hasPendingRevalidatedTag, _isOnDemandRevalidate, _setRequestScopedCacheLife, cacheLifeProfiles, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
15
16
|
import "./fetch-cache.js";
|
|
16
17
|
import { hasUseCacheLayoutMarker, hasUseCachePageMarker, isUseCacheFunctionReference, withoutUseCacheSegmentMarker } from "./internal/app-page-props-cache-key.js";
|
|
17
18
|
import { isWellKnownProperty } from "./internal/thenable-well-known-properties.js";
|
|
@@ -189,22 +190,46 @@ async function serializeCacheResult(result, rsc) {
|
|
|
189
190
|
throw serializationError?.value ?? error;
|
|
190
191
|
}
|
|
191
192
|
}
|
|
193
|
+
const CACHE_LIFE_FIELDS = [
|
|
194
|
+
"stale",
|
|
195
|
+
"revalidate",
|
|
196
|
+
"expire"
|
|
197
|
+
];
|
|
198
|
+
/** Per field, the smallest value any config sets. */
|
|
199
|
+
function minimumCacheLife(configs) {
|
|
200
|
+
const result = {};
|
|
201
|
+
for (const config of configs) for (const field of CACHE_LIFE_FIELDS) {
|
|
202
|
+
const value = config[field];
|
|
203
|
+
const current = result[field];
|
|
204
|
+
if (value !== void 0 && (current === void 0 || value < current)) result[field] = value;
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
192
208
|
/**
|
|
193
|
-
* Resolve
|
|
194
|
-
*
|
|
195
|
-
*
|
|
209
|
+
* Resolve a cache scope's effective life, like Next.js's `collectResult`
|
|
210
|
+
* (use-cache-wrapper.ts). A field set by `cacheLife()` takes the minimum
|
|
211
|
+
* across those calls and wins over nested caches. Any other field takes the
|
|
212
|
+
* minimum of the default profile and the nested caches' lives.
|
|
196
213
|
*/
|
|
197
|
-
function resolveCacheLife(
|
|
198
|
-
|
|
199
|
-
|
|
214
|
+
function resolveCacheLife(ctx) {
|
|
215
|
+
const explicit = minimumCacheLife(ctx.lifeConfigs);
|
|
216
|
+
const collected = minimumCacheLife([cacheLifeProfiles.default, ...ctx.nestedLifeConfigs]);
|
|
200
217
|
const result = {};
|
|
201
|
-
for (const
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
if (config.expire !== void 0) result.expire = result.expire !== void 0 ? Math.min(result.expire, config.expire) : config.expire;
|
|
218
|
+
for (const field of CACHE_LIFE_FIELDS) {
|
|
219
|
+
const value = explicit[field] ?? collected[field];
|
|
220
|
+
if (value !== void 0) result[field] = value;
|
|
205
221
|
}
|
|
206
222
|
return result;
|
|
207
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Hand a finished cache scope's life to what encloses it, like Next.js's
|
|
226
|
+
* `propagateCacheEntryMetadata`: an enclosing cache collects it as a nested
|
|
227
|
+
* life, and only an outermost cache reaches the request.
|
|
228
|
+
*/
|
|
229
|
+
function propagateCacheLife(parentCtx, life) {
|
|
230
|
+
if (parentCtx) parentCtx.nestedLifeConfigs.push(life);
|
|
231
|
+
else _setRequestScopedCacheLife(life);
|
|
232
|
+
}
|
|
208
233
|
const _PRIVATE_FALLBACK_KEY = Symbol.for("vinext.cacheRuntime.privateFallback");
|
|
209
234
|
const _g = globalThis;
|
|
210
235
|
const _privateAls = getOrCreateAls("vinext.cacheRuntime.privateAls");
|
|
@@ -389,7 +414,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
389
414
|
if (knownRootParamNames && rootParams) cacheKey += computeRootParamsCacheKeySuffix(rootParams, knownRootParamNames);
|
|
390
415
|
const softTags = getCurrentFetchSoftTags();
|
|
391
416
|
let existing = null;
|
|
392
|
-
if (!_hasPendingRevalidatedTag(softTags)) try {
|
|
417
|
+
if (!_hasPendingRevalidatedTag(softTags) && !_isOnDemandRevalidate()) try {
|
|
393
418
|
existing = await handler.get(cacheKey, {
|
|
394
419
|
kind: "FETCH",
|
|
395
420
|
softTags
|
|
@@ -398,8 +423,10 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
398
423
|
console.error("[vinext] use cache: handler.get failed; treating as a cache miss:", error);
|
|
399
424
|
}
|
|
400
425
|
const redirectValue = existing?.value;
|
|
426
|
+
let staleRedirect;
|
|
401
427
|
if (isRootParamRedirect(existing) && isServableCacheState(existing?.cacheState) && rootParams && redirectValue?.kind === "FETCH" && !_hasPendingRevalidatedTag([...redirectValue.tags ?? [], ...softTags])) {
|
|
402
428
|
cacheKey = coarseCacheKey + computeRootParamsCacheKeySuffix(rootParams, addKnownRootParamNames(id, rootParamNamesFromTags(redirectValue.tags)));
|
|
429
|
+
if (existing?.cacheState) staleRedirect = existing;
|
|
403
430
|
try {
|
|
404
431
|
existing = await handler.get(cacheKey, {
|
|
405
432
|
kind: "FETCH",
|
|
@@ -410,13 +437,11 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
410
437
|
existing = null;
|
|
411
438
|
}
|
|
412
439
|
}
|
|
413
|
-
const generate = async (propagate) => {
|
|
440
|
+
const generate = async (propagate, staleEntry) => {
|
|
441
|
+
const timestamp = Date.now();
|
|
414
442
|
const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(callFn, callArgs, cacheVariant, (value) => serializeCacheResult(value, rsc));
|
|
415
443
|
const rootParamNames = ctx.readRootParamNames && ctx.readRootParamNames.size > 0 ? addKnownRootParamNames(id, ctx.readRootParamNames) : knownRootParamsByFunctionId.get(id);
|
|
416
|
-
if (propagate)
|
|
417
|
-
recordRequestScopedCacheLife(effectiveLife);
|
|
418
|
-
propagateCacheTagsToRequest(ctx.tags);
|
|
419
|
-
}
|
|
444
|
+
if (propagate) propagateCacheTagsToRequest(ctx.tags);
|
|
420
445
|
const revalidateSeconds = effectiveLife.revalidate ?? cacheLifeProfiles.default.revalidate ?? 900;
|
|
421
446
|
if (collectedResult?.cacheEntry) try {
|
|
422
447
|
let cacheFunctionInvocation;
|
|
@@ -442,6 +467,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
442
467
|
const cacheContext = {
|
|
443
468
|
fetchCache: true,
|
|
444
469
|
tags: ctx.tags,
|
|
470
|
+
timestamp,
|
|
445
471
|
...cacheFunctionInvocation ? { cacheFunctionInvocation } : {},
|
|
446
472
|
cacheControl: {
|
|
447
473
|
revalidate: revalidateSeconds,
|
|
@@ -449,25 +475,39 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
449
475
|
stale: effectiveLife.stale
|
|
450
476
|
}
|
|
451
477
|
};
|
|
478
|
+
let write;
|
|
452
479
|
if (rootParamNames && rootParamNames.size > 0 && rootParams) {
|
|
453
480
|
const specificCacheKey = coarseCacheKey + computeRootParamsCacheKeySuffix(rootParams, rootParamNames);
|
|
454
481
|
const redirectTags = [...ctx.tags, ...[...rootParamNames].map((name) => ROOT_PARAM_TAG_PREFIX + name)];
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
482
|
+
try {
|
|
483
|
+
await handler.set(coarseCacheKey, {
|
|
484
|
+
kind: "FETCH",
|
|
485
|
+
data: {
|
|
486
|
+
headers: { [ROOT_PARAM_REDIRECT_HEADER]: "1" },
|
|
487
|
+
body: "",
|
|
488
|
+
url: coarseCacheKey
|
|
489
|
+
},
|
|
490
|
+
tags: redirectTags,
|
|
491
|
+
revalidate: revalidateSeconds
|
|
492
|
+
}, {
|
|
493
|
+
...cacheContext,
|
|
494
|
+
tags: redirectTags,
|
|
495
|
+
...coarseCacheKey === cacheKey ? staleEntry && { staleEntry } : staleRedirect && { staleEntry: staleRedirect }
|
|
496
|
+
});
|
|
497
|
+
} catch {}
|
|
498
|
+
cacheValue.data.url = specificCacheKey;
|
|
499
|
+
write = handler.set(specificCacheKey, cacheValue, {
|
|
465
500
|
...cacheContext,
|
|
466
|
-
|
|
501
|
+
...staleEntry && specificCacheKey === cacheKey ? { staleEntry } : {}
|
|
467
502
|
});
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
503
|
+
} else write = handler.set(cacheKey, cacheValue, {
|
|
504
|
+
...cacheContext,
|
|
505
|
+
...staleEntry ? { staleEntry } : {}
|
|
506
|
+
});
|
|
507
|
+
const stored = write.then(() => void 0, () => {});
|
|
508
|
+
if (propagate && isInsideWorkStoreScope()) {
|
|
509
|
+
if (isInsideUnifiedScope()) getRequestContext().executionContext?.waitUntil(stored);
|
|
510
|
+
} else await stored;
|
|
471
511
|
} catch {}
|
|
472
512
|
return collectedResult ? collectedResult.result : result;
|
|
473
513
|
};
|
|
@@ -476,10 +516,13 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
476
516
|
propagateCacheTagsToRequest(existing.value.tags);
|
|
477
517
|
const result = await rsc.createFromReadableStream(uint8ToStream(base64ToUint8(existing.value.data.body)), {}, { preserveServerReferences: true });
|
|
478
518
|
recordRequestScopedCacheControl(existing.cacheControl);
|
|
479
|
-
if (existing.cacheState === "stale")
|
|
519
|
+
if (existing.cacheState === "stale") {
|
|
520
|
+
const staleEntry = existing;
|
|
521
|
+
regenerateInBackground(id, () => generate(false, staleEntry));
|
|
522
|
+
}
|
|
480
523
|
return result;
|
|
481
524
|
} catch {}
|
|
482
|
-
return generate(true);
|
|
525
|
+
return generate(true, existing?.cacheState ? existing : void 0);
|
|
483
526
|
}, cacheVariant);
|
|
484
527
|
};
|
|
485
528
|
const cachedFn = memoizeInCacheScope((...args) => invoke(args));
|
|
@@ -525,16 +568,12 @@ function recordRequestScopedCacheControl(cacheControl) {
|
|
|
525
568
|
stale: cacheControl.stale
|
|
526
569
|
};
|
|
527
570
|
const parentCtx = cacheContextStorage.getStore();
|
|
528
|
-
parentCtx
|
|
571
|
+
propagateCacheLife(parentCtx, life);
|
|
529
572
|
if (parentCtx && parentCtx.variant !== "private" && (cacheControl.revalidate === 0 || cacheControl.expire !== void 0 && cacheControl.expire < DYNAMIC_EXPIRE)) {
|
|
530
573
|
const error = new NestedDynamicUseCacheError();
|
|
531
574
|
if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(error, recordRequestScopedCacheControl);
|
|
532
575
|
parentCtx.dynamicNestedCacheError ??= error;
|
|
533
576
|
}
|
|
534
|
-
_setRequestScopedCacheLife(life);
|
|
535
|
-
}
|
|
536
|
-
function recordRequestScopedCacheLife(cacheLife) {
|
|
537
|
-
_setRequestScopedCacheLife(cacheLife);
|
|
538
577
|
}
|
|
539
578
|
/**
|
|
540
579
|
* Bubble a `"use cache"` scope's tags toward where they can drive invalidation.
|
|
@@ -561,8 +600,7 @@ function propagateCacheTagsToRequest(tags) {
|
|
|
561
600
|
addCollectedRequestTags(tags);
|
|
562
601
|
}
|
|
563
602
|
async function executeWithContext(fn, args, variant, rsc) {
|
|
564
|
-
const { result,
|
|
565
|
-
recordRequestScopedCacheLife(effectiveLife);
|
|
603
|
+
const { result, collectedResult } = await runCachedFunctionWithContext(fn, args, variant, (value) => serializeCacheResult(value, rsc));
|
|
566
604
|
return {
|
|
567
605
|
result: collectedResult ? collectedResult.result : result,
|
|
568
606
|
cacheable: collectedResult?.cacheEntry !== null,
|
|
@@ -579,6 +617,7 @@ async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
|
|
|
579
617
|
const ctx = {
|
|
580
618
|
tags: [],
|
|
581
619
|
lifeConfigs: [],
|
|
620
|
+
nestedLifeConfigs: [],
|
|
582
621
|
variant: variant || "default",
|
|
583
622
|
readRootParamNames: /* @__PURE__ */ new Set(),
|
|
584
623
|
hasExplicitRevalidate: false,
|
|
@@ -588,19 +627,26 @@ async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
|
|
|
588
627
|
};
|
|
589
628
|
let collectedResult;
|
|
590
629
|
const workUnitType = variant === "private" ? "private-cache" : "cache";
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
630
|
+
let result;
|
|
631
|
+
let effectiveLife;
|
|
632
|
+
try {
|
|
633
|
+
result = await workUnitAsyncStorage.run({ type: workUnitType }, () => cacheContextStorage.run(ctx, async () => {
|
|
634
|
+
if (!collectResult) return await fn(...args);
|
|
635
|
+
let value;
|
|
636
|
+
const lazyValue = { then: (onFulfilled, onRejected) => (value ??= new Promise((resolve) => resolve(fn(...args)))).then(onFulfilled, onRejected) };
|
|
637
|
+
collectedResult = await collectResult(lazyValue, ctx);
|
|
638
|
+
return await lazyValue;
|
|
639
|
+
}));
|
|
640
|
+
} finally {
|
|
641
|
+
effectiveLife = resolveCacheLife(ctx);
|
|
642
|
+
propagateCacheLife(parentCtx, effectiveLife);
|
|
643
|
+
if (parentCtx && eagerError && (effectiveLife.revalidate === 0 || effectiveLife.expire !== void 0 && effectiveLife.expire < DYNAMIC_EXPIRE)) parentCtx.dynamicNestedCacheError ??= eagerError;
|
|
644
|
+
}
|
|
596
645
|
if (ctx.invalidDynamicUsageError) throw ctx.invalidDynamicUsageError;
|
|
597
|
-
const effectiveLife = resolveCacheLife(ctx.lifeConfigs);
|
|
598
646
|
if (parentCtx) {
|
|
599
|
-
parentCtx.lifeConfigs.push(effectiveLife);
|
|
600
647
|
for (const tag of ctx.tags) if (!parentCtx.tags.includes(tag)) parentCtx.tags.push(tag);
|
|
601
648
|
if (parentCtx.variant !== "private") for (const name of ctx.readRootParamNames ?? []) parentCtx.readRootParamNames?.add(name);
|
|
602
649
|
}
|
|
603
|
-
if (parentCtx && eagerError && (effectiveLife.revalidate === 0 || effectiveLife.expire !== void 0 && effectiveLife.expire < DYNAMIC_EXPIRE)) parentCtx.dynamicNestedCacheError ??= eagerError;
|
|
604
650
|
if (typeof process !== "undefined" && (process.env.VINEXT_PRERENDER === "1" || process.env.NODE_ENV === "development") && ctx.dynamicNestedCacheError) {
|
|
605
651
|
if (effectiveLife.revalidate === 0 && !ctx.hasExplicitRevalidate) throw new Error(getNestedCacheZeroRevalidateErrorMessage(), { cause: ctx.dynamicNestedCacheError });
|
|
606
652
|
if (effectiveLife.expire !== void 0 && effectiveLife.expire < DYNAMIC_EXPIRE && !ctx.hasExplicitExpire) throw new Error(getNestedCacheShortExpireErrorMessage(), { cause: ctx.dynamicNestedCacheError });
|
package/dist/shims/cache.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { CacheLifeConfig } from "../utils/cache-life-profiles.js";
|
|
1
2
|
import { ExecutionContextLike, getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
|
|
2
|
-
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
3
|
-
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, PendingCdnTagInvalidation, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
4
3
|
import { CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
|
|
4
|
+
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
5
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheState, PendingCdnTagInvalidation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _isOnDemandRevalidate, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
5
6
|
//#region src/shims/cache.d.ts
|
|
6
7
|
/**
|
|
7
8
|
* Revalidate cached data associated with a specific cache tag.
|
|
@@ -61,10 +62,11 @@ export declare function updateTag(tag: string): undefined;
|
|
|
61
62
|
/**
|
|
62
63
|
* Opt out of static rendering and indicate a particular component should not be cached.
|
|
63
64
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* Without Cache Components this marks the render dynamic, so the page is not
|
|
66
|
+
* stored. With Cache Components it does nothing, as in Next.js: its prerenders
|
|
67
|
+
* ignore it, and on a request it doesn't make the page dynamic, so the page
|
|
68
|
+
* stays static and cacheable.
|
|
69
|
+
* Source: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/web/spec-extension/unstable-no-store.ts
|
|
68
70
|
*/
|
|
69
71
|
export declare function unstable_noStore(): void;
|
|
70
72
|
/**
|
|
@@ -100,12 +102,16 @@ export declare function unstable_io(): Promise<void>;
|
|
|
100
102
|
/**
|
|
101
103
|
* Set the cache lifetime for a "use cache" function.
|
|
102
104
|
*
|
|
103
|
-
* Accepts either a
|
|
104
|
-
*
|
|
105
|
+
* Accepts either a profile name (a built-in like "hours", or one configured
|
|
106
|
+
* in next.config `cacheLife`) or a custom configuration object; an unknown
|
|
107
|
+
* profile name throws, like Next.js. In Next.js, this only works inside
|
|
108
|
+
* "use cache" functions.
|
|
105
109
|
*
|
|
106
110
|
* When called inside a "use cache" function, this sets the cache TTL.
|
|
107
111
|
* The "minimum-wins" rule applies: if called multiple times, the shortest
|
|
108
|
-
* duration for each field wins.
|
|
112
|
+
* duration for each field wins. Like Next.js, only the fields a call sets are
|
|
113
|
+
* explicit: the others resolve from the default profile and any nested caches
|
|
114
|
+
* (see `resolveCacheLife` in cache-runtime.ts).
|
|
109
115
|
*
|
|
110
116
|
* When called outside a "use cache" context, this is a validated no-op.
|
|
111
117
|
*/
|
|
@@ -142,4 +148,4 @@ type UnstableCacheOptions = {
|
|
|
142
148
|
*/
|
|
143
149
|
export declare function unstable_cache<T extends (...args: any[]) => Promise<any>>(fn: T, keyParts?: string[], options?: UnstableCacheOptions): T;
|
|
144
150
|
//#endregion
|
|
145
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig,
|
|
151
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, type CacheLifeConfig, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, PendingCdnTagInvalidation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _isOnDemandRevalidate, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
|
package/dist/shims/cache.js
CHANGED
|
@@ -6,13 +6,13 @@ import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
|
6
6
|
import { isStagedCacheabilityProbeActive } from "./cacheability-classification.js";
|
|
7
7
|
import { MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
|
|
8
8
|
import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
|
|
9
|
-
import {
|
|
9
|
+
import { sha256Hex } from "../utils/hash.js";
|
|
10
10
|
import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache-state.js";
|
|
11
11
|
import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
12
12
|
import { getHeadersAccessPhase, markDynamicUsage } from "./internal/headers-state.js";
|
|
13
13
|
import { isDraftModeEnabled } from "./headers.js";
|
|
14
14
|
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
15
|
-
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife,
|
|
15
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _isOnDemandRevalidate, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
16
16
|
import { isPathKnownNotEdgeCached } from "./cdn-purge-routes.js";
|
|
17
17
|
//#region src/shims/cache.ts
|
|
18
18
|
/**
|
|
@@ -154,13 +154,15 @@ function updateTag(tag) {
|
|
|
154
154
|
/**
|
|
155
155
|
* Opt out of static rendering and indicate a particular component should not be cached.
|
|
156
156
|
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
157
|
+
* Without Cache Components this marks the render dynamic, so the page is not
|
|
158
|
+
* stored. With Cache Components it does nothing, as in Next.js: its prerenders
|
|
159
|
+
* ignore it, and on a request it doesn't make the page dynamic, so the page
|
|
160
|
+
* stays static and cacheable.
|
|
161
|
+
* Source: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/web/spec-extension/unstable-no-store.ts
|
|
161
162
|
*/
|
|
162
163
|
function unstable_noStore() {
|
|
163
164
|
if (isInsideUnstableCacheScope()) return;
|
|
165
|
+
if (String(process.env.__NEXT_CACHE_COMPONENTS) === "true") return;
|
|
164
166
|
markDynamicUsage();
|
|
165
167
|
}
|
|
166
168
|
/**
|
|
@@ -228,29 +230,34 @@ let _unstableIoWarned = false;
|
|
|
228
230
|
/**
|
|
229
231
|
* Set the cache lifetime for a "use cache" function.
|
|
230
232
|
*
|
|
231
|
-
* Accepts either a
|
|
232
|
-
*
|
|
233
|
+
* Accepts either a profile name (a built-in like "hours", or one configured
|
|
234
|
+
* in next.config `cacheLife`) or a custom configuration object; an unknown
|
|
235
|
+
* profile name throws, like Next.js. In Next.js, this only works inside
|
|
236
|
+
* "use cache" functions.
|
|
233
237
|
*
|
|
234
238
|
* When called inside a "use cache" function, this sets the cache TTL.
|
|
235
239
|
* The "minimum-wins" rule applies: if called multiple times, the shortest
|
|
236
|
-
* duration for each field wins.
|
|
240
|
+
* duration for each field wins. Like Next.js, only the fields a call sets are
|
|
241
|
+
* explicit: the others resolve from the default profile and any nested caches
|
|
242
|
+
* (see `resolveCacheLife` in cache-runtime.ts).
|
|
237
243
|
*
|
|
238
244
|
* When called outside a "use cache" context, this is a validated no-op.
|
|
239
245
|
*/
|
|
240
246
|
function cacheLife(profile) {
|
|
241
247
|
let resolvedConfig;
|
|
242
248
|
if (typeof profile === "string") {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
249
|
+
const configuredProfile = Object.hasOwn(cacheLifeProfiles, profile) ? cacheLifeProfiles[profile] : void 0;
|
|
250
|
+
if (configuredProfile === void 0) {
|
|
251
|
+
if (Object.hasOwn(cacheLifeProfiles, profile.trim())) throw new Error(`Unknown \`cacheLife()\` profile "${profile}" is not configured in next.config.js\nDid you mean "${profile.trim()}" without the spaces?`);
|
|
252
|
+
throw new Error(`Unknown \`cacheLife()\` profile "${profile}" is not configured in next.config.js\nmodule.exports = {
|
|
253
|
+
cacheLife: {
|
|
254
|
+
"${profile}": ...\n }
|
|
255
|
+
}`);
|
|
246
256
|
}
|
|
247
|
-
resolvedConfig = { ...
|
|
257
|
+
resolvedConfig = { ...configuredProfile };
|
|
248
258
|
} else if (typeof profile === "object" && profile !== null) {
|
|
249
259
|
if (profile.expire !== void 0 && profile.revalidate !== void 0 && profile.expire < profile.revalidate) console.warn("[vinext] cacheLife: expire must be >= revalidate");
|
|
250
|
-
resolvedConfig = {
|
|
251
|
-
...cacheLifeProfiles.default,
|
|
252
|
-
...profile
|
|
253
|
-
};
|
|
260
|
+
resolvedConfig = { ...profile };
|
|
254
261
|
} else return;
|
|
255
262
|
try {
|
|
256
263
|
const ctx = getRegisteredCacheContext();
|
|
@@ -258,11 +265,13 @@ function cacheLife(profile) {
|
|
|
258
265
|
ctx.lifeConfigs.push(resolvedConfig);
|
|
259
266
|
if (resolvedConfig.revalidate !== void 0) ctx.hasExplicitRevalidate = true;
|
|
260
267
|
if (resolvedConfig.expire !== void 0) ctx.hasExplicitExpire = true;
|
|
261
|
-
_setRequestScopedCacheLife(resolvedConfig);
|
|
262
268
|
return;
|
|
263
269
|
}
|
|
264
270
|
} catch {}
|
|
265
|
-
_setRequestScopedCacheLife(resolvedConfig
|
|
271
|
+
_setRequestScopedCacheLife(typeof profile === "string" ? resolvedConfig : {
|
|
272
|
+
...cacheLifeProfiles.default,
|
|
273
|
+
...profile
|
|
274
|
+
});
|
|
266
275
|
}
|
|
267
276
|
/**
|
|
268
277
|
* Tag a "use cache" function's cached result for on-demand revalidation.
|
|
@@ -325,7 +334,7 @@ function unstable_cacheTag(...tags) {
|
|
|
325
334
|
}
|
|
326
335
|
return cacheTag(...tags);
|
|
327
336
|
}
|
|
328
|
-
const UNSTABLE_CACHE_KEY_PREFIX = "unstable_cache:
|
|
337
|
+
const UNSTABLE_CACHE_KEY_PREFIX = "unstable_cache:v3";
|
|
329
338
|
/**
|
|
330
339
|
* AsyncLocalStorage to track whether we're inside an unstable_cache() callback.
|
|
331
340
|
* Stored on globalThis via Symbol so headers.ts can detect the scope without
|
|
@@ -394,7 +403,7 @@ function scheduleUnstableCacheBackgroundRevalidation(cacheKey, refresh) {
|
|
|
394
403
|
pending.set(cacheKey, trackedRevalidation);
|
|
395
404
|
waitUntilUnstableCacheRevalidation(trackedRevalidation);
|
|
396
405
|
}
|
|
397
|
-
async function refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds) {
|
|
406
|
+
async function refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds, staleEntry, deferWrite) {
|
|
398
407
|
const argsUnchanged = serializeArgsOrNull(args) === keyedArgs;
|
|
399
408
|
const result = await _unstableCacheAls.run(true, () => _unstableCacheCallbackAls.run({ useCacheContext: _useCacheContextAls.getStore() }, () => fn(...args)));
|
|
400
409
|
if (!argsUnchanged) return result;
|
|
@@ -408,11 +417,18 @@ async function refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, r
|
|
|
408
417
|
tags,
|
|
409
418
|
revalidate: typeof revalidateSeconds === "number" ? revalidateSeconds : false
|
|
410
419
|
};
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
420
|
+
const write = new Promise((resolve) => {
|
|
421
|
+
resolve(getDataCacheHandler().set(cacheKey, cacheValue, {
|
|
422
|
+
fetchCache: true,
|
|
423
|
+
tags,
|
|
424
|
+
revalidate: revalidateSeconds,
|
|
425
|
+
...staleEntry ? { staleEntry } : {}
|
|
426
|
+
}));
|
|
427
|
+
}).catch((err) => {
|
|
428
|
+
console.error("[vinext] unstable_cache write error:", err);
|
|
415
429
|
});
|
|
430
|
+
if (deferWrite) getRequestExecutionContext()?.waitUntil(write);
|
|
431
|
+
else await write;
|
|
416
432
|
return result;
|
|
417
433
|
}
|
|
418
434
|
function serializeArgsOrNull(args) {
|
|
@@ -439,16 +455,10 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
439
455
|
const keyedArgs = JSON.stringify(args);
|
|
440
456
|
const invocationKey = `${fixedKey}${keyedArgs}`;
|
|
441
457
|
addCollectedRequestTags(tags);
|
|
442
|
-
recordUnstableCacheObservation({
|
|
443
|
-
kind: "unstable_cache",
|
|
444
|
-
keyHash: fnv1a64(invocationKey),
|
|
445
|
-
revalidate: typeof revalidateSeconds === "number" ? revalidateSeconds : revalidateSeconds === false ? false : null,
|
|
446
|
-
tagCount: tags.length,
|
|
447
|
-
tagHash: tags.length > 0 ? fnv1a64(JSON.stringify(tags)) : null
|
|
448
|
-
});
|
|
449
458
|
const cacheKey = `${UNSTABLE_CACHE_KEY_PREFIX}:${await sha256Hex(invocationKey)}`;
|
|
450
459
|
const isDraftMode = isDraftModeEnabled();
|
|
451
|
-
|
|
460
|
+
let staleEntry;
|
|
461
|
+
if (!isDraftMode && !isNestedUnstableCacheCall() && !_isOnDemandRevalidate()) {
|
|
452
462
|
const softTags = getCurrentFetchSoftTags();
|
|
453
463
|
const existing = _hasPendingRevalidatedTag([...tags, ...softTags]) ? null : await getDataCacheHandler().get(cacheKey, {
|
|
454
464
|
kind: "FETCH",
|
|
@@ -457,10 +467,11 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
457
467
|
});
|
|
458
468
|
if (existing?.value && existing.value.kind === "FETCH") {
|
|
459
469
|
const cached = tryDeserializeUnstableCacheResult(existing.value.data.body);
|
|
470
|
+
if (existing.cacheState === "stale") staleEntry = existing;
|
|
460
471
|
if (cached.ok) {
|
|
461
472
|
if (existing.cacheState === "stale") {
|
|
462
473
|
if (shouldServeStaleUnstableCacheEntry()) {
|
|
463
|
-
scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds));
|
|
474
|
+
scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds, staleEntry, false));
|
|
464
475
|
return cached.value;
|
|
465
476
|
}
|
|
466
477
|
} else return cached.value;
|
|
@@ -468,9 +479,9 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
468
479
|
}
|
|
469
480
|
}
|
|
470
481
|
if (isDraftMode) return await _unstableCacheAls.run(true, () => fn(...args));
|
|
471
|
-
return await refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds);
|
|
482
|
+
return await refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds, staleEntry, !staleEntry && isInsideWorkStoreScope());
|
|
472
483
|
};
|
|
473
484
|
return cachedFn;
|
|
474
485
|
}
|
|
475
486
|
//#endregion
|
|
476
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife,
|
|
487
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _isOnDemandRevalidate, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _queuePendingCdnTagInvalidation, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _revalidateCdnTags, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
|
|
@@ -17,6 +17,8 @@ export type RouteCacheabilityOutcome = {
|
|
|
17
17
|
*/
|
|
18
18
|
status?: number;
|
|
19
19
|
headers?: Readonly<Record<string, string>>;
|
|
20
|
+
/** App pages: the client-router stale time from the completed render's cacheLife. */
|
|
21
|
+
staleTimeSeconds?: number;
|
|
20
22
|
tags?: readonly string[];
|
|
21
23
|
};
|
|
22
24
|
export type RouteCacheabilityState = {
|
|
@@ -32,6 +32,12 @@ export type CdnCacheableHeaderInput = {
|
|
|
32
32
|
*/
|
|
33
33
|
tags?: readonly string[];
|
|
34
34
|
};
|
|
35
|
+
/** A page's document, rendered from an RSC request's payload. */
|
|
36
|
+
export type CdnAppPageDocument = {
|
|
37
|
+
html: string;
|
|
38
|
+
/** The renderer's own `Link` header. */
|
|
39
|
+
linkHeader?: string;
|
|
40
|
+
};
|
|
35
41
|
export type CdnResponsePolicy = {
|
|
36
42
|
/** Whether a provider-specific response header controls shared caching. */
|
|
37
43
|
isHeader(name: string): boolean;
|
|
@@ -76,12 +82,15 @@ export type CdnCacheAdapter = {
|
|
|
76
82
|
*/
|
|
77
83
|
readonly requiresCompletedResponseAdmission?: boolean;
|
|
78
84
|
/**
|
|
79
|
-
* This adapter's response-stage transport keys shared
|
|
80
|
-
* `VinextResponseStageDispatchOptions.cacheIdentity` when core supplies
|
|
81
|
-
* Core supplies it only when completed-response admission is also
|
|
82
|
-
* because that admission is what makes a
|
|
85
|
+
* This adapter's response-stage transport keys shared dispatches by
|
|
86
|
+
* `VinextResponseStageDispatchOptions.cacheIdentity` when core supplies
|
|
87
|
+
* one. Core supplies it only when completed-response admission is also
|
|
88
|
+
* required, because that admission is what makes a host-free identity, and
|
|
89
|
+
* a page's query-free one, safe. `"query-free"` also drops the user query
|
|
90
|
+
* from App page identities; `"host-free"` keeps every dispatch's query, for
|
|
91
|
+
* a transport whose cache keys the dispatched query itself.
|
|
83
92
|
*/
|
|
84
|
-
readonly responseStageCacheIdentity?: "query-free";
|
|
93
|
+
readonly responseStageCacheIdentity?: "host-free" | "query-free";
|
|
85
94
|
/**
|
|
86
95
|
* Optionally return a foreground page response while completed-response
|
|
87
96
|
* admission continues on an independent body branch. Returning `null` keeps
|
|
@@ -90,6 +99,14 @@ export type CdnCacheAdapter = {
|
|
|
90
99
|
deferCompletedPageResponseAdmission?(response: Response, complete: (response: Response) => Promise<Response>): Response | null;
|
|
91
100
|
/** Capture the full-route RSC side stream while admitting a completed HTML response. */
|
|
92
101
|
captureAppPageRscData?(rscData: Promise<ArrayBuffer>): void;
|
|
102
|
+
/**
|
|
103
|
+
* Store the page's document beside an RSC request's completed response, as
|
|
104
|
+
* Next.js keeps a page's document and RSC payload in one entry. Returns the
|
|
105
|
+
* callback admission calls with the document the render rendered from its
|
|
106
|
+
* payload, or with `null` when the page has no document to store, or
|
|
107
|
+
* `undefined` when this render's response stores no document.
|
|
108
|
+
*/
|
|
109
|
+
captureAppPageDocument?(): ((document: CdnAppPageDocument | null) => void) | undefined;
|
|
93
110
|
/**
|
|
94
111
|
* Whether this adapter sends the 304 for a Pages render whose If-None-Match
|
|
95
112
|
* matches. When it does, the render returns the page, so an adapter that
|
|
@@ -9,4 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function buildClientHookErrorMessage(hookName: string): string;
|
|
11
11
|
export declare function throwClientHookError(hookName: string): never;
|
|
12
|
+
/** Rewrites that TypeError into the actionable message, like Next.js's formatServerError. */
|
|
13
|
+
export declare function rewriteClientHookError(error: Error): void;
|
|
12
14
|
//#endregion
|
|
@@ -13,5 +13,20 @@ function buildClientHookErrorMessage(hookName) {
|
|
|
13
13
|
function throwClientHookError(hookName) {
|
|
14
14
|
throw new Error(buildClientHookErrorMessage(hookName));
|
|
15
15
|
}
|
|
16
|
+
const clientHookPattern = /\b(useState|useEffect|useReducer|useRef|useContext|useLayoutEffect|useInsertionEffect|useSyncExternalStore|useTransition|useImperativeHandle|useDeferredValue|useActionState|useOptimistic|useEffectEvent)\b.*is not a function/;
|
|
17
|
+
/** Rewrites that TypeError into the actionable message, like Next.js's formatServerError. */
|
|
18
|
+
function rewriteClientHookError(error) {
|
|
19
|
+
const match = error.message.match(clientHookPattern);
|
|
20
|
+
if (!match) return;
|
|
21
|
+
const message = buildClientHookErrorMessage(match[1]);
|
|
22
|
+
try {
|
|
23
|
+
if (error.stack) {
|
|
24
|
+
const lines = error.stack.split("\n");
|
|
25
|
+
lines[0] = message;
|
|
26
|
+
error.stack = lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
error.message = message;
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
16
31
|
//#endregion
|
|
17
|
-
export { buildClientHookErrorMessage, throwClientHookError };
|
|
32
|
+
export { buildClientHookErrorMessage, rewriteClientHookError, throwClientHookError };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { searchParamsToRecord } from "../utils/query.js";
|
|
3
3
|
import { getNavigationContext } from "./navigation-context-state.js";
|
|
4
|
+
import { getClientNavigationRenderContext, useSearchParams } from "./navigation.js";
|
|
4
5
|
import "./navigation-server.js";
|
|
5
|
-
import { isOwnPropertyCheck, isWellKnownProperty } from "./internal/thenable-well-known-properties.js";
|
|
6
6
|
import { RenderedSearchContext } from "./slot.js";
|
|
7
|
-
import {
|
|
7
|
+
import { isOwnPropertyCheck, isWellKnownProperty } from "./internal/thenable-well-known-properties.js";
|
|
8
8
|
import { createElement, use, useMemo } from "react";
|
|
9
9
|
//#region src/shims/client-page-root.tsx
|
|
10
10
|
/**
|