vinext 1.0.1 → 1.1.0
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 +72 -1
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/prerender-paths.js +3 -78
- package/dist/build/prerender.js +33 -8
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +3 -1
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -43
- package/dist/index.d.ts +4 -1
- package/dist/index.js +59 -30
- package/dist/plugins/cache-flight-codec.d.ts +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.js +17 -7
- package/dist/server/app-browser-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +93 -10
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +5 -0
- package/dist/server/app-page-cache.js +27 -7
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +47 -30
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +2 -2
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +1 -2
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +55 -33
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +4 -4
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-router-entry.js +3 -3
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +212 -96
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +6 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +6 -4
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +2 -2
- package/dist/server/app-worker-stages.js +3 -3
- package/dist/server/cacheability-request.js +9 -5
- package/dist/server/config-headers.js +2 -0
- package/dist/server/dev-server.js +12 -2
- package/dist/server/headers.d.ts +14 -0
- package/dist/server/headers.js +15 -1
- package/dist/server/image-optimization.d.ts +16 -0
- package/dist/server/image-optimization.js +26 -6
- package/dist/server/isr-cache.js +2 -2
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-response-headers.js +2 -0
- package/dist/server/multi-stage.d.ts +8 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- package/dist/server/pages-page-handler.js +21 -4
- package/dist/server/pages-request-stage-entry.js +8 -4
- package/dist/server/prod-server.d.ts +8 -7
- package/dist/server/prod-server.js +153 -69
- package/dist/server/request-pipeline.d.ts +20 -8
- package/dist/server/request-pipeline.js +21 -7
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- package/dist/server/seed-cache.js +10 -7
- package/dist/server/socket-error-backstop.d.ts +14 -0
- package/dist/server/socket-error-backstop.js +27 -4
- package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +2 -40
- package/dist/shims/cache-callable-runtime.js +50 -168
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +6 -19
- package/dist/shims/cache-runtime.js +165 -225
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +5 -4
- package/dist/shims/cacheability-classification.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- package/dist/shims/fetch-cache.d.ts +6 -0
- package/dist/shims/fetch-cache.js +19 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -1
- package/dist/shims/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +14 -4
- package/dist/shims/request-context.d.ts +9 -0
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -1
- package/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +3 -3
|
@@ -9,11 +9,13 @@ import { createPprFallbackShellSuspensePromise, trackPprFallbackShellCacheTask }
|
|
|
9
9
|
import { markDynamicUsage, throwIfInsideCacheScope } from "./internal/headers-state.js";
|
|
10
10
|
import { isDraftModeEnabled } from "./headers.js";
|
|
11
11
|
import { _registerCacheContextAccessor } from "./internal/cache-context-accessor.js";
|
|
12
|
-
import { _hasPendingRevalidatedTag, _setRequestScopedCacheLife, cacheLifeProfiles } from "./cache-request-state.js";
|
|
13
|
-
import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { _hasPendingRevalidatedTag, _setRequestScopedCacheLife, cacheLifeProfiles, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
13
|
+
import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache.js";
|
|
14
|
+
import { hasUseCacheLayoutMarker, hasUseCachePageMarker, isUseCacheFunctionReference, withoutUseCacheSegmentMarker } from "./internal/app-page-props-cache-key.js";
|
|
15
|
+
import { getFallbackParamsSnapshot, makeThenableParams, restoreThenableParams } from "./thenable-params.js";
|
|
16
16
|
import { getCurrentRootParams } from "./root-params.js";
|
|
17
|
+
import { flightArgumentsKey, restoreFlightReply, snapshotFlightReply } from "./cache-flight-arguments.js";
|
|
18
|
+
import { cache } from "react";
|
|
17
19
|
//#region src/shims/cache-runtime.ts
|
|
18
20
|
/**
|
|
19
21
|
* "use cache" runtime
|
|
@@ -36,14 +38,17 @@ import { getCurrentRootParams } from "./root-params.js";
|
|
|
36
38
|
* and all RSC-serializable types — unlike JSON.stringify which silently
|
|
37
39
|
* drops $$typeof Symbols and function values.
|
|
38
40
|
*
|
|
39
|
-
* When RSC APIs are unavailable (e.g. in unit tests), falls back to
|
|
40
|
-
* JSON.stringify/parse with the same stableStringify cache key generation.
|
|
41
|
-
*
|
|
42
41
|
* Cache variants:
|
|
43
42
|
* - "use cache" — shared cache (default profile)
|
|
44
43
|
* - "use cache: remote" — shared cache (explicit)
|
|
45
44
|
* - "use cache: private" — per-request cache (not shared across requests)
|
|
46
45
|
*/
|
|
46
|
+
const replayableFunctions = /* @__PURE__ */ new WeakMap();
|
|
47
|
+
function replayCachedFunction(fn, args) {
|
|
48
|
+
const replay = replayableFunctions.get(fn);
|
|
49
|
+
if (!replay || args.version !== 1) throw new Error("Invalid cache function arguments");
|
|
50
|
+
return replay(args);
|
|
51
|
+
}
|
|
47
52
|
/** Threshold below which expire is considered "dynamic" (5 minutes in seconds). */
|
|
48
53
|
const DYNAMIC_EXPIRE = 300;
|
|
49
54
|
/**
|
|
@@ -124,16 +129,9 @@ function buildUseCacheKey(id, keySeed, argsKey) {
|
|
|
124
129
|
const scopedId = keySeed ? `build:${encodeURIComponent(keySeed)}:${id}` : id;
|
|
125
130
|
return argsKey === void 0 ? `use-cache:${scopedId}` : `use-cache:${scopedId}:${argsKey}`;
|
|
126
131
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (_rscModule !== NOT_LOADED) return _rscModule;
|
|
131
|
-
try {
|
|
132
|
-
_rscModule = await import("@vitejs/plugin-rsc/react/rsc");
|
|
133
|
-
} catch {
|
|
134
|
-
_rscModule = null;
|
|
135
|
-
}
|
|
136
|
-
return _rscModule;
|
|
132
|
+
let _rscModule;
|
|
133
|
+
function getRscModule() {
|
|
134
|
+
return _rscModule ??= import("@vitejs/plugin-rsc/react/rsc");
|
|
137
135
|
}
|
|
138
136
|
/** Collect a ReadableStream<Uint8Array> into a single Uint8Array. */
|
|
139
137
|
async function collectStream(stream) {
|
|
@@ -171,55 +169,22 @@ function uint8ToStream(bytes) {
|
|
|
171
169
|
} });
|
|
172
170
|
}
|
|
173
171
|
async function serializeCacheResult(result, rsc) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
throw serializationError?.value ?? error;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
const body = JSON.stringify(result);
|
|
193
|
-
return body === void 0 ? null : {
|
|
194
|
-
result,
|
|
195
|
-
cacheEntry: {
|
|
196
|
-
body,
|
|
197
|
-
headers: {}
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Convert an encodeReply result (string | FormData) to a cache key string.
|
|
203
|
-
* For FormData (binary args), produces a deterministic SHA-256 hash over
|
|
204
|
-
* the sorted entries. We can't hash `new Response(formData).arrayBuffer()`
|
|
205
|
-
* because multipart boundaries are non-deterministic across serializations.
|
|
206
|
-
*
|
|
207
|
-
* Exported for testing.
|
|
208
|
-
*/
|
|
209
|
-
async function replyToCacheKey(reply) {
|
|
210
|
-
if (typeof reply === "string") return reply;
|
|
211
|
-
const entries = [...reply.entries()];
|
|
212
|
-
const valStr = (v) => typeof v === "string" ? v : v.name;
|
|
213
|
-
entries.sort((a, b) => a[0].localeCompare(b[0]) || valStr(a[1]).localeCompare(valStr(b[1])));
|
|
214
|
-
const parts = [];
|
|
215
|
-
for (const [name, value] of entries) if (typeof value === "string") parts.push(`${name}=s:${value}`);
|
|
216
|
-
else {
|
|
217
|
-
const bytes = new Uint8Array(await value.arrayBuffer());
|
|
218
|
-
parts.push(`${name}=b:${value.type}:${value.size}:${Buffer.from(bytes).toString("base64")}`);
|
|
172
|
+
let serializationError;
|
|
173
|
+
const [returnStream, savedStream] = rsc.renderToReadableStream(result, { onError(error) {
|
|
174
|
+
serializationError ??= { value: error };
|
|
175
|
+
} }).tee();
|
|
176
|
+
try {
|
|
177
|
+
const [deserializedResult, bytes] = await Promise.all([rsc.createFromReadableStream(returnStream, {}, { preserveServerReferences: true }), collectStream(savedStream)]);
|
|
178
|
+
return {
|
|
179
|
+
result: deserializedResult,
|
|
180
|
+
cacheEntry: serializationError ? null : {
|
|
181
|
+
body: uint8ToBase64(bytes),
|
|
182
|
+
headers: { [VINEXT_RSC_MARKER_HEADER]: "1" }
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
} catch (error) {
|
|
186
|
+
throw serializationError?.value ?? error;
|
|
219
187
|
}
|
|
220
|
-
const payload = new TextEncoder().encode(parts.join("\0"));
|
|
221
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", payload);
|
|
222
|
-
return Buffer.from(new Uint8Array(hashBuffer)).toString("base64url");
|
|
223
188
|
}
|
|
224
189
|
/**
|
|
225
190
|
* Resolve collected cacheLife configs into a single effective config.
|
|
@@ -301,6 +266,17 @@ function propagateRootParamNamesToParent(names) {
|
|
|
301
266
|
if (!parent || parent.variant === "private") return;
|
|
302
267
|
for (const name of names) parent.readRootParamNames?.add(name);
|
|
303
268
|
}
|
|
269
|
+
function isServableCacheState(cacheState) {
|
|
270
|
+
if (cacheState === "expired") return false;
|
|
271
|
+
if (cacheState !== "stale") return true;
|
|
272
|
+
return shouldServeStaleUnstableCacheEntry() && process.env.VINEXT_PRERENDER !== "1" && !isRouteCacheabilityProbe();
|
|
273
|
+
}
|
|
274
|
+
function regenerateInBackground(id, regenerate) {
|
|
275
|
+
const regeneration = runWithDetachedCacheObservations(() => runWithDetachedFetchObservations(() => cacheContextStorage.exit(regenerate))).then(() => void 0, (error) => {
|
|
276
|
+
console.error(`[vinext] use cache: background regeneration failed for ${id}:`, error);
|
|
277
|
+
});
|
|
278
|
+
if (isInsideUnifiedScope()) getRequestContext().executionContext?.waitUntil(regeneration);
|
|
279
|
+
}
|
|
304
280
|
/**
|
|
305
281
|
* Register a function as a cached function. This is called by the Vite
|
|
306
282
|
* transform for each "use cache" function.
|
|
@@ -315,7 +291,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
315
291
|
const omitAppPageSearchParams = cacheVariant !== "private";
|
|
316
292
|
const cacheFunctionId = options.serverReferenceId ? JSON.stringify([id, options.serverReferenceId]) : id;
|
|
317
293
|
const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
|
|
318
|
-
const
|
|
294
|
+
const invoke = (args, replay) => {
|
|
319
295
|
if (cacheVariant === "private") {
|
|
320
296
|
const parentCtx = cacheContextStorage.getStore();
|
|
321
297
|
if (parentCtx && parentCtx.variant !== "private") throwPrivateUseCacheInsidePublicUseCacheError();
|
|
@@ -346,40 +322,60 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
346
322
|
}
|
|
347
323
|
}
|
|
348
324
|
return trackPprFallbackShellCacheTask(async () => {
|
|
349
|
-
const
|
|
325
|
+
const codec = await getRscModule();
|
|
326
|
+
const clientReferences = codec.createClientTemporaryReferenceSet();
|
|
327
|
+
const serverReferences = codec.createTemporaryReferenceSet();
|
|
328
|
+
const rsc = {
|
|
329
|
+
...codec,
|
|
330
|
+
renderToReadableStream: (value, options) => codec.renderToReadableStream(value, {
|
|
331
|
+
...options,
|
|
332
|
+
temporaryReferences: serverReferences
|
|
333
|
+
}),
|
|
334
|
+
createFromReadableStream: (stream, options, context) => codec.createFromReadableStream(stream, {
|
|
335
|
+
...options,
|
|
336
|
+
temporaryReferences: clientReferences
|
|
337
|
+
}, context)
|
|
338
|
+
};
|
|
350
339
|
const keySeed = getUseCacheKeySeed();
|
|
351
|
-
const captures = options.decryptCaptures ? await options.decryptCaptures(args[0]) : void 0;
|
|
340
|
+
const captures = !replay && options.decryptCaptures ? await options.decryptCaptures(args[0]) : void 0;
|
|
352
341
|
const hasCaptureEnvelope = captures !== void 0;
|
|
353
|
-
const
|
|
342
|
+
const limitedArgs = options.argumentCount === void 0 ? args : hasCaptureEnvelope ? [args[0], ...args.slice(1, 1 + options.argumentCount)] : args.slice(0, options.argumentCount);
|
|
343
|
+
const pagePropsArgIndex = replay?.pagePropsIndex ?? limitedArgs.findIndex(hasUseCachePageMarker);
|
|
344
|
+
const layoutPropsArgIndex = replay?.layoutPropsIndex ?? limitedArgs.findIndex(hasUseCacheLayoutMarker);
|
|
354
345
|
const isPageInvocation = pagePropsArgIndex !== -1;
|
|
355
|
-
const
|
|
356
|
-
const admittedArgs =
|
|
346
|
+
const segmentPropsIndex = isPageInvocation ? pagePropsArgIndex : layoutPropsArgIndex;
|
|
347
|
+
const admittedArgs = segmentPropsIndex !== -1 && !replay ? replaceArgument(limitedArgs, segmentPropsIndex, withoutUseCacheSegmentMarker(limitedArgs[segmentPropsIndex], isPageInvocation)) : limitedArgs;
|
|
357
348
|
const executionArgs = hasCaptureEnvelope ? [captures, ...admittedArgs.slice(1)] : admittedArgs;
|
|
349
|
+
const outerParams = !replay && segmentPropsIndex !== -1 ? executionArgs[segmentPropsIndex].params : void 0;
|
|
350
|
+
const fallbackParams = getFallbackParamsSnapshot(outerParams);
|
|
351
|
+
const serializationArgs = fallbackParams ? replaceArgument(executionArgs, segmentPropsIndex, {
|
|
352
|
+
...executionArgs[segmentPropsIndex],
|
|
353
|
+
params: fallbackParams
|
|
354
|
+
}) : executionArgs;
|
|
358
355
|
const pagePropsIndex = omitAppPageSearchParams && isPageInvocation ? pagePropsArgIndex : void 0;
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const argsKey = processedArgs.length > 0 ? stableStringify(processedArgs) : void 0;
|
|
372
|
-
cacheKey = buildUseCacheKey(cacheFunctionId, keySeed, argsKey);
|
|
373
|
-
}
|
|
374
|
-
} catch {
|
|
375
|
-
return (await executeWithContext(fn, callArgs, cacheVariant)).result;
|
|
356
|
+
const keyArgs = pagePropsIndex === void 0 ? serializationArgs : toReplayablePageArgs(serializationArgs, pagePropsIndex);
|
|
357
|
+
const flightArguments = replay ?? await snapshotFlightReply(await rsc.encodeReply(keyArgs, { temporaryReferences: clientReferences }), isPageInvocation ? pagePropsArgIndex : void 0);
|
|
358
|
+
if (!replay && layoutPropsArgIndex !== -1) flightArguments.layoutPropsIndex = layoutPropsArgIndex;
|
|
359
|
+
let cacheKey = buildUseCacheKey(cacheFunctionId, keySeed, flightArgumentsKey(flightArguments));
|
|
360
|
+
let callArgs = await rsc.decodeReply(restoreFlightReply(flightArguments), { temporaryReferences: serverReferences });
|
|
361
|
+
if (segmentPropsIndex !== -1) {
|
|
362
|
+
const props = callArgs[segmentPropsIndex];
|
|
363
|
+
callArgs = replaceArgument(callArgs, segmentPropsIndex, {
|
|
364
|
+
...props,
|
|
365
|
+
params: restoreThenableParams(await props.params, outerParams)
|
|
366
|
+
});
|
|
367
|
+
if (pagePropsIndex !== void 0) callArgs = withErroringPageSearchParams(callArgs, pagePropsIndex);
|
|
376
368
|
}
|
|
369
|
+
if (fallbackParams) return (await executeWithContext(fn, callArgs, cacheVariant, rsc)).result;
|
|
377
370
|
if (cacheVariant === "private") {
|
|
378
371
|
const privateCache = _getPrivateState()._privateCache;
|
|
379
372
|
const privateHit = privateCache.get(cacheKey);
|
|
380
|
-
if (privateHit !== void 0)
|
|
373
|
+
if (privateHit !== void 0) {
|
|
374
|
+
if (privateHit.serialized) return rsc.createFromReadableStream(uint8ToStream(base64ToUint8(privateHit.serialized.body)), {}, { preserveServerReferences: true });
|
|
375
|
+
return privateHit.result;
|
|
376
|
+
}
|
|
381
377
|
const execution = await executeWithContext(fn, callArgs, cacheVariant, rsc);
|
|
382
|
-
if (execution.cacheable) privateCache.set(cacheKey, execution
|
|
378
|
+
if (execution.cacheable) privateCache.set(cacheKey, execution);
|
|
383
379
|
return execution.result;
|
|
384
380
|
}
|
|
385
381
|
if (isDev || isDraftModeEnabled()) return (await executeWithContext(fn, callArgs, cacheVariant, rsc)).result;
|
|
@@ -399,7 +395,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
399
395
|
console.error("[vinext] use cache: handler.get failed; treating as a cache miss:", error);
|
|
400
396
|
}
|
|
401
397
|
const redirectValue = existing?.value;
|
|
402
|
-
if (isRootParamRedirect(existing) && existing?.cacheState
|
|
398
|
+
if (isRootParamRedirect(existing) && isServableCacheState(existing?.cacheState) && rootParams && redirectValue?.kind === "FETCH" && !_hasPendingRevalidatedTag([...redirectValue.tags ?? [], ...softTags])) {
|
|
403
399
|
cacheKey = coarseCacheKey + computeRootParamsCacheKeySuffix(rootParams, addKnownRootParamNames(id, rootParamNamesFromTags(redirectValue.tags)));
|
|
404
400
|
try {
|
|
405
401
|
existing = await handler.get(cacheKey, {
|
|
@@ -411,78 +407,80 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
411
407
|
existing = null;
|
|
412
408
|
}
|
|
413
409
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
recordRequestScopedCacheControl(existing.cacheControl);
|
|
421
|
-
return result;
|
|
410
|
+
const generate = async (propagate) => {
|
|
411
|
+
const { result, ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(fn, callArgs, cacheVariant, (value) => serializeCacheResult(value, rsc));
|
|
412
|
+
const rootParamNames = ctx.readRootParamNames && ctx.readRootParamNames.size > 0 ? addKnownRootParamNames(id, ctx.readRootParamNames) : knownRootParamsByFunctionId.get(id);
|
|
413
|
+
if (propagate) {
|
|
414
|
+
recordRequestScopedCacheLife(effectiveLife);
|
|
415
|
+
propagateCacheTagsToRequest(ctx.tags);
|
|
422
416
|
}
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
encryptedArgs: await options.encodeInvocationArgs(pagePropsIndex === void 0 ? admittedArgs : toReplayablePageArgs(admittedArgs, pagePropsIndex)),
|
|
437
|
-
referenceId: options.serverReferenceId,
|
|
438
|
-
rootParams: Object.fromEntries(Object.entries(rootParams ?? {}).filter((entry) => entry[1] !== void 0)),
|
|
439
|
-
softTags
|
|
440
|
-
};
|
|
441
|
-
} catch {}
|
|
442
|
-
const serialized = collectedResult.cacheEntry;
|
|
443
|
-
const cacheValue = {
|
|
444
|
-
kind: "FETCH",
|
|
445
|
-
data: {
|
|
446
|
-
headers: serialized.headers,
|
|
447
|
-
body: serialized.body,
|
|
448
|
-
url: cacheKey
|
|
449
|
-
},
|
|
450
|
-
tags: ctx.tags,
|
|
451
|
-
revalidate: revalidateSeconds
|
|
452
|
-
};
|
|
453
|
-
const cacheContext = {
|
|
454
|
-
fetchCache: true,
|
|
455
|
-
tags: ctx.tags,
|
|
456
|
-
...cacheFunctionInvocation ? { cacheFunctionInvocation } : {},
|
|
457
|
-
cacheControl: {
|
|
458
|
-
revalidate: revalidateSeconds,
|
|
459
|
-
expire: effectiveLife.expire,
|
|
460
|
-
stale: effectiveLife.stale
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
if (rootParamNames && rootParamNames.size > 0 && rootParams) {
|
|
464
|
-
const specificCacheKey = coarseCacheKey + computeRootParamsCacheKeySuffix(rootParams, rootParamNames);
|
|
465
|
-
const redirectTags = [...ctx.tags, ...[...rootParamNames].map((name) => ROOT_PARAM_TAG_PREFIX + name)];
|
|
466
|
-
await handler.set(coarseCacheKey, {
|
|
417
|
+
const revalidateSeconds = effectiveLife.revalidate ?? cacheLifeProfiles.default.revalidate ?? 900;
|
|
418
|
+
if (collectedResult?.cacheEntry) try {
|
|
419
|
+
let cacheFunctionInvocation;
|
|
420
|
+
if (options.serverReferenceId && options.encodeInvocation) try {
|
|
421
|
+
cacheFunctionInvocation = {
|
|
422
|
+
encryptedArgs: await options.encodeInvocation(flightArguments),
|
|
423
|
+
referenceId: options.serverReferenceId,
|
|
424
|
+
rootParams: Object.fromEntries(Object.entries(rootParams ?? {}).filter((entry) => entry[1] !== void 0)),
|
|
425
|
+
softTags
|
|
426
|
+
};
|
|
427
|
+
} catch {}
|
|
428
|
+
const serialized = collectedResult.cacheEntry;
|
|
429
|
+
const cacheValue = {
|
|
467
430
|
kind: "FETCH",
|
|
468
431
|
data: {
|
|
469
|
-
headers:
|
|
470
|
-
body:
|
|
471
|
-
url:
|
|
432
|
+
headers: serialized.headers,
|
|
433
|
+
body: serialized.body,
|
|
434
|
+
url: cacheKey
|
|
472
435
|
},
|
|
473
|
-
tags:
|
|
436
|
+
tags: ctx.tags,
|
|
474
437
|
revalidate: revalidateSeconds
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
438
|
+
};
|
|
439
|
+
const cacheContext = {
|
|
440
|
+
fetchCache: true,
|
|
441
|
+
tags: ctx.tags,
|
|
442
|
+
...cacheFunctionInvocation ? { cacheFunctionInvocation } : {},
|
|
443
|
+
cacheControl: {
|
|
444
|
+
revalidate: revalidateSeconds,
|
|
445
|
+
expire: effectiveLife.expire,
|
|
446
|
+
stale: effectiveLife.stale
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
if (rootParamNames && rootParamNames.size > 0 && rootParams) {
|
|
450
|
+
const specificCacheKey = coarseCacheKey + computeRootParamsCacheKeySuffix(rootParams, rootParamNames);
|
|
451
|
+
const redirectTags = [...ctx.tags, ...[...rootParamNames].map((name) => ROOT_PARAM_TAG_PREFIX + name)];
|
|
452
|
+
await handler.set(coarseCacheKey, {
|
|
453
|
+
kind: "FETCH",
|
|
454
|
+
data: {
|
|
455
|
+
headers: { [ROOT_PARAM_REDIRECT_HEADER]: "1" },
|
|
456
|
+
body: "",
|
|
457
|
+
url: coarseCacheKey
|
|
458
|
+
},
|
|
459
|
+
tags: redirectTags,
|
|
460
|
+
revalidate: revalidateSeconds
|
|
461
|
+
}, {
|
|
462
|
+
...cacheContext,
|
|
463
|
+
tags: redirectTags
|
|
464
|
+
});
|
|
465
|
+
cacheValue.data.url = specificCacheKey;
|
|
466
|
+
await handler.set(specificCacheKey, cacheValue, cacheContext);
|
|
467
|
+
} else await handler.set(cacheKey, cacheValue, cacheContext);
|
|
468
|
+
} catch {}
|
|
469
|
+
return collectedResult ? collectedResult.result : result;
|
|
470
|
+
};
|
|
471
|
+
if (existing?.value && existing.value.kind === "FETCH" && existing.value.data.headers["x-vinext-rsc"] === "1" && isServableCacheState(existing.cacheState) && !_hasPendingRevalidatedTag([...existing.value.tags ?? [], ...softTags])) try {
|
|
472
|
+
propagateRootParamNamesToParent(knownRootParamsByFunctionId.get(id));
|
|
473
|
+
propagateCacheTagsToRequest(existing.value.tags);
|
|
474
|
+
const result = await rsc.createFromReadableStream(uint8ToStream(base64ToUint8(existing.value.data.body)), {}, { preserveServerReferences: true });
|
|
475
|
+
recordRequestScopedCacheControl(existing.cacheControl);
|
|
476
|
+
if (existing.cacheState === "stale") regenerateInBackground(id, () => generate(false));
|
|
477
|
+
return result;
|
|
482
478
|
} catch {}
|
|
483
|
-
return
|
|
479
|
+
return generate(true);
|
|
484
480
|
}, cacheVariant);
|
|
485
481
|
};
|
|
482
|
+
const cachedFn = memoizeInCacheScope((...args) => invoke(args));
|
|
483
|
+
replayableFunctions.set(cachedFn, (data) => invoke([], data));
|
|
486
484
|
Object.defineProperty(cachedFn, "length", {
|
|
487
485
|
value: fn.length,
|
|
488
486
|
configurable: true
|
|
@@ -491,6 +489,11 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
491
489
|
if (options.acceptsSecondArgument !== void 0) Reflect.set(cachedFn, USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL, options.acceptsSecondArgument);
|
|
492
490
|
return cachedFn;
|
|
493
491
|
}
|
|
492
|
+
/** Memoize in one React render without skipping cache guards or scoped serialization. */
|
|
493
|
+
function memoizeInCacheScope(fn) {
|
|
494
|
+
const memoized = cache((_parent, _workUnit, _unstable, ...args) => fn(...args));
|
|
495
|
+
return (...args) => memoized(cacheContextStorage.getStore(), workUnitAsyncStorage.getStore(), unstableCacheContextStorage.getStore() === true, ...args);
|
|
496
|
+
}
|
|
494
497
|
/** @internal Symbol used to identify "use cache" wrapper functions. */
|
|
495
498
|
const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
|
|
496
499
|
/** @internal Symbol carrying transform-derived cached function argument metadata. */
|
|
@@ -555,11 +558,12 @@ function propagateCacheTagsToRequest(tags) {
|
|
|
555
558
|
addCollectedRequestTags(tags);
|
|
556
559
|
}
|
|
557
560
|
async function executeWithContext(fn, args, variant, rsc) {
|
|
558
|
-
const { result, ctx: _ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(fn, args, variant,
|
|
561
|
+
const { result, ctx: _ctx, effectiveLife, collectedResult } = await runCachedFunctionWithContext(fn, args, variant, (value) => serializeCacheResult(value, rsc));
|
|
559
562
|
recordRequestScopedCacheLife(effectiveLife);
|
|
560
563
|
return {
|
|
561
564
|
result: collectedResult ? collectedResult.result : result,
|
|
562
|
-
cacheable: collectedResult?.cacheEntry !== null
|
|
565
|
+
cacheable: collectedResult?.cacheEntry !== null,
|
|
566
|
+
serialized: collectedResult?.cacheEntry
|
|
563
567
|
};
|
|
564
568
|
}
|
|
565
569
|
async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
|
|
@@ -605,31 +609,6 @@ async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
|
|
|
605
609
|
collectedResult
|
|
606
610
|
};
|
|
607
611
|
}
|
|
608
|
-
function unwrapThenableObjects(value, options) {
|
|
609
|
-
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
610
|
-
const childOptions = { omitMarkedAppPageSearchParams: options.omitMarkedAppPageSearchParams };
|
|
611
|
-
if (Array.isArray(value)) return value.map((item) => unwrapThenableObjects(item, childOptions));
|
|
612
|
-
if (isThenableObject(value)) {
|
|
613
|
-
const plain = {};
|
|
614
|
-
for (const key of Object.keys(value)) plain[key] = unwrapThenableObjects(value[key], childOptions);
|
|
615
|
-
return plain;
|
|
616
|
-
}
|
|
617
|
-
if (typeof value.then === "function") return value;
|
|
618
|
-
const result = {};
|
|
619
|
-
for (const key of Object.keys(value)) {
|
|
620
|
-
if (key === "searchParams" && (options.omitAppPageSearchParamsAtRoot || options.omitMarkedAppPageSearchParams && isMarkedAppPagePropsObject(value))) continue;
|
|
621
|
-
result[key] = unwrapThenableObjects(value[key], childOptions);
|
|
622
|
-
}
|
|
623
|
-
return result;
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* A thenable (not an array) with own enumerable properties — the
|
|
627
|
-
* `Object.assign(Promise.resolve(obj), obj)` pattern Next.js params use. The
|
|
628
|
-
* cache key is built from its fields instead of the promise.
|
|
629
|
-
*/
|
|
630
|
-
function isThenableObject(value) {
|
|
631
|
-
return !Array.isArray(value) && "then" in value && typeof value.then === "function" && Object.keys(value).length > 0;
|
|
632
|
-
}
|
|
633
612
|
function isPagePropsObject(value) {
|
|
634
613
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
635
614
|
}
|
|
@@ -638,26 +617,17 @@ function replaceArgument(args, index, value) {
|
|
|
638
617
|
result[index] = value;
|
|
639
618
|
return result;
|
|
640
619
|
}
|
|
641
|
-
/** Remove the `$$isPage` invocation marker before props reach the key or user code. */
|
|
642
|
-
function withoutUseCachePageMarker(props) {
|
|
643
|
-
const { [APP_PAGE_USE_CACHE_MARKER]: _marker, ...pageProps } = props;
|
|
644
|
-
return isMarkedAppPagePropsObject(props) ? markAppPagePropsForUseCache(pageProps) : pageProps;
|
|
645
|
-
}
|
|
646
620
|
/**
|
|
647
621
|
* Response Store replay args for a public page cache: drop `searchParams` from
|
|
648
622
|
* the page props at `index` (after a capture envelope, if any), as Next.js does
|
|
649
|
-
* for the serialized arguments (use-cache-wrapper.ts, `isPageSegmentFunction`)
|
|
650
|
-
*
|
|
651
|
-
* the erroring searchParams fallback.
|
|
623
|
+
* for the serialized arguments (use-cache-wrapper.ts, `isPageSegmentFunction`).
|
|
624
|
+
* The replay regains page semantics from `CacheFlightArguments.pagePropsIndex`.
|
|
652
625
|
*/
|
|
653
626
|
function toReplayablePageArgs(args, index) {
|
|
654
627
|
const props = args[index];
|
|
655
628
|
if (!isPagePropsObject(props)) return [...args];
|
|
656
629
|
const { searchParams: _searchParams, ...pageProps } = props;
|
|
657
|
-
return replaceArgument(args, index,
|
|
658
|
-
...pageProps,
|
|
659
|
-
[APP_PAGE_USE_CACHE_MARKER]: true
|
|
660
|
-
});
|
|
630
|
+
return replaceArgument(args, index, pageProps);
|
|
661
631
|
}
|
|
662
632
|
/**
|
|
663
633
|
* Give page props at `index` without `searchParams` (a Response Store replay of
|
|
@@ -673,35 +643,5 @@ function withErroringPageSearchParams(args, index) {
|
|
|
673
643
|
searchParams: makeThenableParams({}, { observeParamAccess: () => throwIfInsideCacheScope("searchParams") })
|
|
674
644
|
});
|
|
675
645
|
}
|
|
676
|
-
function unwrapThenableObjectArray(values, options) {
|
|
677
|
-
return values.map((value, index) => unwrapThenableObjects(value, {
|
|
678
|
-
omitAppPageSearchParamsAtRoot: index === options.pagePropsIndex,
|
|
679
|
-
omitMarkedAppPageSearchParams: options.omitMarkedAppPageSearchParams
|
|
680
|
-
}));
|
|
681
|
-
}
|
|
682
|
-
function stableStringify(value, seen) {
|
|
683
|
-
if (value === void 0) return "undefined";
|
|
684
|
-
if (value === null) return "null";
|
|
685
|
-
if (typeof value === "function") throw new Error("Cannot serialize function");
|
|
686
|
-
if (typeof value === "symbol") throw new Error("Cannot serialize symbol");
|
|
687
|
-
if (Array.isArray(value)) {
|
|
688
|
-
if (!seen) seen = /* @__PURE__ */ new Set();
|
|
689
|
-
if (seen.has(value)) throw new Error("Circular reference");
|
|
690
|
-
seen.add(value);
|
|
691
|
-
const result = "[" + value.map((v) => stableStringify(v, seen)).join(",") + "]";
|
|
692
|
-
seen.delete(value);
|
|
693
|
-
return result;
|
|
694
|
-
}
|
|
695
|
-
if (typeof value === "object" && value !== null) {
|
|
696
|
-
if (value instanceof Date) return `Date(${value.getTime()})`;
|
|
697
|
-
if (!seen) seen = /* @__PURE__ */ new Set();
|
|
698
|
-
if (seen.has(value)) throw new Error("Circular reference");
|
|
699
|
-
seen.add(value);
|
|
700
|
-
const result = "{" + Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k], seen)}`).join(",") + "}";
|
|
701
|
-
seen.delete(value);
|
|
702
|
-
return result;
|
|
703
|
-
}
|
|
704
|
-
return JSON.stringify(value);
|
|
705
|
-
}
|
|
706
646
|
//#endregion
|
|
707
|
-
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext,
|
|
647
|
+
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isUseCacheFunction, memoizeInCacheScope, registerCachedFunction, replayCachedFunction, runWithPrivateCache };
|
package/dist/shims/cache.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExecutionContextLike, getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
|
|
2
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, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
3
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheLifeSink, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
4
4
|
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";
|
|
5
5
|
//#region src/shims/cache.d.ts
|
|
6
6
|
/**
|
|
@@ -142,4 +142,4 @@ type UnstableCacheOptions = {
|
|
|
142
142
|
*/
|
|
143
143
|
export declare function unstable_cache<T extends (...args: any[]) => Promise<any>>(fn: T, keyParts?: string[], options?: UnstableCacheOptions): T;
|
|
144
144
|
//#endregion
|
|
145
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
|
|
145
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheControlMetadata, CacheHandler, CacheHandlerContext, CacheHandlerValue, CacheLifeConfig, CacheLifeSink, CacheState, CachedAppPageValue, CachedFetchValue, CachedImageValue, CachedPagesValue, CachedRedirectValue, CachedRouteValue, type ExecutionContextLike, IncrementalCacheValue, MemoryCacheHandler, NoOpCacheHandler, UnstableCacheObservation, UnstableCacheRevalidationMode, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, markActionRevalidation, unstable_noStore as noStore, recordUnstableCacheObservation, registerDataCacheHandler, registerLazyDataCacheHandler, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry };
|
package/dist/shims/cache.js
CHANGED
|
@@ -11,8 +11,8 @@ import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
|
11
11
|
import { getHeadersAccessPhase, markDynamicUsage } from "./internal/headers-state.js";
|
|
12
12
|
import { isDraftModeEnabled } from "./headers.js";
|
|
13
13
|
import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
|
|
14
|
-
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
15
|
-
import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
|
|
14
|
+
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
15
|
+
import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache.js";
|
|
16
16
|
//#region src/shims/cache.ts
|
|
17
17
|
/**
|
|
18
18
|
* next/cache shim
|
|
@@ -322,6 +322,7 @@ const UNSTABLE_CACHE_KEY_PREFIX = "unstable_cache:v2";
|
|
|
322
322
|
* a direct import (avoiding circular dependencies).
|
|
323
323
|
*/
|
|
324
324
|
const _unstableCacheAls = getOrCreateAls("vinext.unstableCache.als");
|
|
325
|
+
const _useCacheContextAls = getOrCreateAls("vinext.cacheRuntime.contextAls");
|
|
325
326
|
function serializeUnstableCacheResult(value) {
|
|
326
327
|
return JSON.stringify(value === void 0 ? { undef: true } : { v: value });
|
|
327
328
|
}
|
|
@@ -362,7 +363,7 @@ function waitUntilUnstableCacheRevalidation(promise) {
|
|
|
362
363
|
function scheduleUnstableCacheBackgroundRevalidation(cacheKey, refresh) {
|
|
363
364
|
const pending = getPendingUnstableCacheRevalidations();
|
|
364
365
|
if (pending.has(cacheKey)) return;
|
|
365
|
-
const trackedRevalidation =
|
|
366
|
+
const trackedRevalidation = runWithDetachedCacheObservations(() => runWithDetachedFetchObservations(() => _useCacheContextAls.exit(refresh))).then(() => void 0).catch((err) => {
|
|
366
367
|
console.error(`[vinext] unstable_cache background revalidation failed for ${cacheKey}:`, err);
|
|
367
368
|
}).finally(() => {
|
|
368
369
|
if (pending.get(cacheKey) === trackedRevalidation) pending.delete(cacheKey);
|
|
@@ -436,4 +437,4 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
436
437
|
return cachedFn;
|
|
437
438
|
}
|
|
438
439
|
//#endregion
|
|
439
|
-
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
|
|
440
|
+
export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
|
|
@@ -10,6 +10,13 @@ export type RouteCacheabilityOutcome = {
|
|
|
10
10
|
searchParamsUnread?: true;
|
|
11
11
|
/** A transient classification failure that may succeed on another bounded attempt. */
|
|
12
12
|
retryable?: true;
|
|
13
|
+
/**
|
|
14
|
+
* App page RSC: the status and headers that replace the streamed 200 of a
|
|
15
|
+
* render whose special error rejected its document's shell, once the
|
|
16
|
+
* response is complete.
|
|
17
|
+
*/
|
|
18
|
+
status?: number;
|
|
19
|
+
headers?: Readonly<Record<string, string>>;
|
|
13
20
|
tags?: readonly string[];
|
|
14
21
|
};
|
|
15
22
|
export type RouteCacheabilityState = {
|
|
@@ -2,4 +2,11 @@ import { AppRouterInstance } from "./internal/app-router-context.js";
|
|
|
2
2
|
//#region src/shims/error-boundary-navigation.d.ts
|
|
3
3
|
export declare function useErrorBoundaryPathname(): string;
|
|
4
4
|
export declare function useErrorBoundaryRouter(): AppRouterInstance;
|
|
5
|
+
/**
|
|
6
|
+
* Whether following a redirect() would refetch the URL the browser is at,
|
|
7
|
+
* which renders the same redirect again. As in the navigation planner, only the
|
|
8
|
+
* exact URL refreshes the page; any hash change, including removing the
|
|
9
|
+
* current hash, only scrolls.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isRedirectToCurrentUrl(redirect: string): boolean;
|
|
5
12
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { markPprFallbackShellDynamicBoundary } from "./ppr-fallback-shell.js";
|
|
3
3
|
import { AppRouterContext } from "./internal/app-router-context.js";
|
|
4
|
+
import { toCanonicalBrowserNavigationHref, toSameOriginAppPath } from "./url-utils.js";
|
|
4
5
|
import { getNavigationContext } from "./navigation-context-state.js";
|
|
5
6
|
import "./navigation-server.js";
|
|
6
7
|
import * as React$1 from "react";
|
|
@@ -8,6 +9,7 @@ import * as React$1 from "react";
|
|
|
8
9
|
const CLIENT_NAVIGATION_STATE_KEY = Symbol.for("vinext.clientNavigationState");
|
|
9
10
|
const CLIENT_NAVIGATION_RENDER_CONTEXT_KEY = Symbol.for("vinext.clientNavigationRenderContext");
|
|
10
11
|
const BASE_PATH = process.env.__NEXT_ROUTER_BASEPATH ?? "";
|
|
12
|
+
const TRAILING_SLASH = process.env.__VINEXT_TRAILING_SLASH === "true";
|
|
11
13
|
function getClientNavigationState() {
|
|
12
14
|
return globalThis[CLIENT_NAVIGATION_STATE_KEY];
|
|
13
15
|
}
|
|
@@ -40,5 +42,21 @@ function useErrorBoundaryRouter() {
|
|
|
40
42
|
if (router === null) throw new Error("invariant expected app router to be mounted");
|
|
41
43
|
return router;
|
|
42
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether following a redirect() would refetch the URL the browser is at,
|
|
47
|
+
* which renders the same redirect again. As in the navigation planner, only the
|
|
48
|
+
* exact URL refreshes the page; any hash change, including removing the
|
|
49
|
+
* current hash, only scrolls.
|
|
50
|
+
*/
|
|
51
|
+
function isRedirectToCurrentUrl(redirect) {
|
|
52
|
+
if (typeof window === "undefined") return false;
|
|
53
|
+
try {
|
|
54
|
+
const current = new URL(window.location.href);
|
|
55
|
+
const target = new URL(toCanonicalBrowserNavigationHref(toSameOriginAppPath(redirect, BASE_PATH) ?? redirect, current.href, BASE_PATH, TRAILING_SLASH), current.href);
|
|
56
|
+
return target.hash === current.hash && target.origin === current.origin && target.pathname === current.pathname && target.search === current.search;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
43
61
|
//#endregion
|
|
44
|
-
export { useErrorBoundaryPathname, useErrorBoundaryRouter };
|
|
62
|
+
export { isRedirectToCurrentUrl, useErrorBoundaryPathname, useErrorBoundaryRouter };
|