vinext 1.0.0-beta.11 → 1.0.0-beta.13
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 +39 -12
- package/dist/build/action-owner-manifest.js +23 -5
- package/dist/build/lifecycle.d.ts +42 -0
- package/dist/build/lifecycle.js +246 -0
- package/dist/build/nitro-route-rules.js +1 -1
- package/dist/build/pages-client-assets-module.d.ts +0 -3
- package/dist/build/pages-client-assets-module.js +1 -13
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender-paths.d.ts +1 -1
- package/dist/build/prerender-paths.js +6 -6
- package/dist/build/prerender-server-pool.js +1 -1
- package/dist/build/prerender.d.ts +1 -1
- package/dist/build/prerender.js +5 -5
- package/dist/build/preview-credentials.d.ts +1 -1
- package/dist/build/preview-credentials.js +2 -2
- package/dist/build/report.js +1 -1
- package/dist/build/run-prerender.d.ts +2 -2
- package/dist/build/run-prerender.js +5 -5
- package/dist/build/standalone.js +2 -2
- package/dist/cli-args.d.ts +5 -13
- package/dist/cli-args.js +2 -45
- package/dist/cli-dev-config.d.ts +6 -2
- package/dist/cli-dev-config.js +160 -3
- package/dist/cli.js +104 -439
- package/dist/config/config-matchers.js +1 -1
- package/dist/config/next-config.d.ts +2 -2
- package/dist/config/next-config.js +5 -5
- package/dist/config/prerender.d.ts +3 -0
- package/dist/config/prerender.js +8 -2
- package/dist/entries/app-browser-entry.js +1 -1
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +25 -5
- package/dist/entries/pages-client-entry.d.ts +1 -0
- package/dist/entries/pages-client-entry.js +17 -2
- package/dist/index.d.ts +6 -8
- package/dist/index.js +282 -105
- package/dist/init-cloudflare.d.ts +3 -2
- package/dist/init-cloudflare.js +117 -5
- package/dist/init-platform.d.ts +2 -0
- package/dist/init-platform.js +9 -3
- package/dist/init.d.ts +7 -5
- package/dist/init.js +41 -22
- package/dist/plugins/dynamic-preload-metadata.js +1 -1
- package/dist/plugins/extensionless-dynamic-import.js +2 -2
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/import-meta-url.js +1 -1
- package/dist/plugins/instrumentation-client.js +1 -1
- package/dist/plugins/og-assets.js +32 -13
- package/dist/plugins/og-harfbuzz.d.ts +24 -0
- package/dist/plugins/og-harfbuzz.js +260 -0
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/require-condition-resolution.js +2 -2
- package/dist/plugins/require-context.js +2 -2
- package/dist/plugins/typeof-window.js +1 -1
- package/dist/plugins/use-cache-callable.d.ts +0 -2
- package/dist/plugins/use-cache-callable.js +40 -22
- package/dist/plugins/worker-image-imports.js +1 -1
- package/dist/routing/app-route-graph.js +1 -1
- package/dist/routing/app-router.js +1 -1
- package/dist/routing/pages-router.js +1 -1
- package/dist/server/app-action-forwarding.js +1 -1
- package/dist/server/app-browser-entry.js +1 -0
- package/dist/server/app-browser-error.js +1 -1
- package/dist/server/app-elements-wire.js +2 -2
- package/dist/server/app-middleware.js +1 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +14 -2
- package/dist/server/app-page-dispatch.js +1 -1
- package/dist/server/app-page-element-builder.js +3 -2
- package/dist/server/app-page-probe.js +3 -3
- package/dist/server/app-page-render.js +1 -0
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +16 -12
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +2 -2
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +3 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +2 -2
- package/dist/server/app-route-handler-runtime.js +1 -1
- package/dist/server/app-router-entry.js +2 -2
- package/dist/server/app-rsc-handler.d.ts +9 -2
- package/dist/server/app-rsc-handler.js +30 -10
- package/dist/server/app-rsc-response-stage.js +6 -3
- package/dist/server/app-rsc-route-matching.js +1 -1
- package/dist/server/app-server-action-execution.js +35 -6
- package/dist/server/app-ssr-entry.js +7 -2
- package/dist/server/app-ssr-stream.js +25 -6
- package/dist/server/app-worker-stages.d.ts +4 -1
- package/dist/server/app-worker-stages.js +4 -4
- package/dist/server/artifact-compatibility.js +1 -1
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/dev-lockfile.d.ts +1 -1
- package/dist/server/dev-lockfile.js +4 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +28 -6
- package/dist/server/dev-stack-sourcemap.js +1 -1
- package/dist/server/html.d.ts +0 -20
- package/dist/server/html.js +16 -1
- package/dist/server/instrumentation.d.ts +4 -9
- package/dist/server/instrumentation.js +10 -15
- package/dist/server/isr-cache.js +3 -3
- package/dist/server/metadata-route-response.d.ts +1 -0
- package/dist/server/metadata-route-response.js +65 -0
- package/dist/server/middleware-runtime.js +3 -3
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +37 -2
- package/dist/server/pages-client-assets.d.ts +7 -0
- package/dist/server/pages-data-route.js +1 -1
- package/dist/server/pages-dev-hydration.d.ts +6 -0
- package/dist/server/pages-dev-hydration.js +19 -7
- package/dist/server/pages-document-initial-props.d.ts +1 -0
- package/dist/server/pages-document-initial-props.js +1 -1
- package/dist/server/pages-page-data.js +2 -2
- package/dist/server/pages-page-handler.js +5 -2
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.js +3 -3
- package/dist/server/pages-request-stage-entry.js +3 -3
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/prerender-route-params.js +1 -1
- package/dist/server/prod-server.js +19 -13
- package/dist/server/request-pipeline.js +2 -2
- package/dist/server/rsc-stream-hints.d.ts +12 -0
- package/dist/server/rsc-stream-hints.js +70 -35
- package/dist/server/seed-cache.js +3 -4
- package/dist/server/socket-error-backstop.js +1 -1
- package/dist/shims/cache-callable-runtime.d.ts +38 -0
- package/dist/shims/cache-callable-runtime.js +162 -11
- package/dist/shims/cache-runtime.d.ts +6 -8
- package/dist/shims/cache-runtime.js +89 -24
- package/dist/shims/constants.js +1 -1
- package/dist/shims/dynamic-preload-chunks.js +6 -2
- package/dist/shims/font-local.js +1 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/head.js +1 -1
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image-config.js +2 -0
- package/dist/shims/internal/app-page-props-cache-key.d.ts +29 -0
- package/dist/shims/internal/app-page-props-cache-key.js +53 -1
- package/dist/shims/internal/format-url-object.d.ts +7 -0
- package/dist/shims/internal/format-url-object.js +53 -0
- package/dist/shims/internal/normalize-router-href.d.ts +15 -0
- package/dist/shims/internal/normalize-router-href.js +41 -0
- package/dist/shims/internal/pages-data-target.d.ts +4 -1
- package/dist/shims/internal/pages-data-target.js +28 -35
- package/dist/shims/internal/route-pattern-for-warning.d.ts +2 -2
- package/dist/shims/internal/route-pattern-for-warning.js +3 -3
- package/dist/shims/link.js +31 -92
- package/dist/shims/metadata.js +5 -4
- package/dist/shims/navigation.js +2 -2
- package/dist/shims/router-state.js +1 -1
- package/dist/shims/router.d.ts +8 -7
- package/dist/shims/router.js +312 -148
- package/dist/shims/script-nonce-context.d.ts +4 -1
- package/dist/shims/script-nonce-context.js +15 -6
- package/dist/shims/server.js +3 -3
- package/dist/utils/built-asset-url.js +1 -1
- package/dist/utils/client-runtime-metadata.d.ts +6 -0
- package/dist/utils/client-runtime-metadata.js +16 -0
- package/dist/utils/lazy-chunks.js +1 -1
- package/dist/utils/project.d.ts +1 -11
- package/dist/utils/project.js +20 -29
- package/dist/utils/react-version.d.ts +3 -1
- package/dist/utils/react-version.js +19 -1
- package/dist/utils/vite-cli-invocation.d.ts +21 -0
- package/dist/utils/vite-cli-invocation.js +144 -0
- package/package.json +10 -2
|
@@ -51,7 +51,7 @@ function concatBytes(first, second) {
|
|
|
51
51
|
combined.set(second, first.byteLength);
|
|
52
52
|
return combined;
|
|
53
53
|
}
|
|
54
|
-
function indexOfByte(bytes, byte, from
|
|
54
|
+
function indexOfByte(bytes, byte, from) {
|
|
55
55
|
for (let index = from; index < bytes.byteLength; index++) if (bytes[index] === byte) return index;
|
|
56
56
|
return -1;
|
|
57
57
|
}
|
|
@@ -70,8 +70,35 @@ function parseHexBytes(bytes, start, end) {
|
|
|
70
70
|
function isUntaggedJsonRowStart(byte) {
|
|
71
71
|
return byte === 34 || byte === 45 || byte >= 48 && byte <= 57 || byte === 91 || byte === 102 || byte === 110 || byte === 116 || byte === 123;
|
|
72
72
|
}
|
|
73
|
+
const COLON_BYTE = 58;
|
|
74
|
+
const COMMA_BYTE = 44;
|
|
75
|
+
const NEWLINE_BYTE = 10;
|
|
76
|
+
const HINT_TAG_BYTE = 72;
|
|
77
|
+
const LINK_HINT_CODE_BYTE = 76;
|
|
78
|
+
function createAsciiTagTable(tags) {
|
|
79
|
+
const table = /* @__PURE__ */ new Uint8Array(128);
|
|
80
|
+
for (const tag of tags) table[tag.charCodeAt(0)] = 1;
|
|
81
|
+
return table;
|
|
82
|
+
}
|
|
83
|
+
const LENGTH_PREFIXED_ROW_TAG_TABLE = createAsciiTagTable(LENGTH_PREFIXED_ROW_TAGS);
|
|
84
|
+
const NEWLINE_PREFIXED_ROW_TAG_TABLE = createAsciiTagTable(NEWLINE_PREFIXED_ROW_TAGS);
|
|
85
|
+
function isTagInTable(table, byte) {
|
|
86
|
+
return byte < 128 && table[byte] === 1;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Rewrite stylesheet preload hints in a React Flight stream.
|
|
90
|
+
*
|
|
91
|
+
* The rewrite is byte-length preserving, so this transform keeps React's
|
|
92
|
+
* text chunk boundaries instead of re-emitting one chunk per Flight row. Every
|
|
93
|
+
* downstream consumer (the tee, the SSR Flight client, the inline RSC embed,
|
|
94
|
+
* RSC response wrappers) pays a per-chunk cost, and splitting per row
|
|
95
|
+
* multiplied the chunk count roughly 8x on content-heavy pages. Chunks with
|
|
96
|
+
* no stylesheet hint are forwarded as-is without copying; only rows whose
|
|
97
|
+
* tag is `HL` are decoded and inspected. Length-prefixed bodies remain separate
|
|
98
|
+
* so binary bytes do not force adjacent text through the embed's base64 path.
|
|
99
|
+
*/
|
|
73
100
|
function normalizeReactFlightPreloadHints(stream) {
|
|
74
|
-
let carry =
|
|
101
|
+
let carry = null;
|
|
75
102
|
let rawBytesRemaining = 0;
|
|
76
103
|
let passThrough = false;
|
|
77
104
|
return stream.pipeThrough(new TransformStream({
|
|
@@ -80,56 +107,64 @@ function normalizeReactFlightPreloadHints(stream) {
|
|
|
80
107
|
controller.enqueue(chunk);
|
|
81
108
|
return;
|
|
82
109
|
}
|
|
83
|
-
|
|
84
|
-
carry =
|
|
85
|
-
|
|
110
|
+
const bytes = carry === null ? chunk : concatBytes(carry, chunk);
|
|
111
|
+
carry = null;
|
|
112
|
+
const byteLength = bytes.byteLength;
|
|
113
|
+
let offset = 0;
|
|
114
|
+
let emittedThrough = 0;
|
|
115
|
+
let output = bytes;
|
|
116
|
+
let ownsOutput = bytes !== chunk;
|
|
117
|
+
while (offset < byteLength) {
|
|
86
118
|
if (rawBytesRemaining > 0) {
|
|
87
|
-
const length = Math.min(rawBytesRemaining,
|
|
88
|
-
controller.enqueue(
|
|
119
|
+
const length = Math.min(rawBytesRemaining, byteLength - offset);
|
|
120
|
+
if (offset > emittedThrough) controller.enqueue(output.subarray(emittedThrough, offset));
|
|
121
|
+
controller.enqueue(bytes.subarray(offset, offset + length));
|
|
89
122
|
rawBytesRemaining -= length;
|
|
90
|
-
|
|
123
|
+
offset += length;
|
|
124
|
+
emittedThrough = offset;
|
|
91
125
|
continue;
|
|
92
126
|
}
|
|
93
|
-
const colon = indexOfByte(bytes,
|
|
94
|
-
if (colon === -1 || colon + 1 ===
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (LENGTH_PREFIXED_ROW_TAGS.has(tag)) {
|
|
100
|
-
const comma = indexOfByte(bytes, 44, colon + 2);
|
|
101
|
-
if (comma === -1) {
|
|
102
|
-
carry = bytes.slice();
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
127
|
+
const colon = indexOfByte(bytes, COLON_BYTE, offset);
|
|
128
|
+
if (colon === -1 || colon + 1 === byteLength) break;
|
|
129
|
+
const tagByte = bytes[colon + 1];
|
|
130
|
+
if (isTagInTable(LENGTH_PREFIXED_ROW_TAG_TABLE, tagByte)) {
|
|
131
|
+
const comma = indexOfByte(bytes, COMMA_BYTE, colon + 2);
|
|
132
|
+
if (comma === -1) break;
|
|
105
133
|
const length = parseHexBytes(bytes, colon + 2, comma);
|
|
106
134
|
if (length != null) {
|
|
107
|
-
controller.enqueue(bytes.slice(0, comma + 1));
|
|
108
135
|
rawBytesRemaining = length;
|
|
109
|
-
|
|
136
|
+
offset = comma + 1;
|
|
110
137
|
continue;
|
|
111
138
|
}
|
|
112
139
|
passThrough = true;
|
|
113
|
-
|
|
114
|
-
|
|
140
|
+
offset = byteLength;
|
|
141
|
+
break;
|
|
115
142
|
}
|
|
116
|
-
|
|
117
|
-
if (!NEWLINE_PREFIXED_ROW_TAGS.has(tag) && !isUntaggedJsonRowStart(tagByte)) {
|
|
143
|
+
if (!isTagInTable(NEWLINE_PREFIXED_ROW_TAG_TABLE, tagByte) && !isUntaggedJsonRowStart(tagByte)) {
|
|
118
144
|
passThrough = true;
|
|
119
|
-
|
|
120
|
-
|
|
145
|
+
offset = byteLength;
|
|
146
|
+
break;
|
|
121
147
|
}
|
|
122
|
-
const newline = indexOfByte(bytes,
|
|
123
|
-
if (newline === -1)
|
|
124
|
-
|
|
125
|
-
|
|
148
|
+
const newline = indexOfByte(bytes, NEWLINE_BYTE, offset);
|
|
149
|
+
if (newline === -1) break;
|
|
150
|
+
if (tagByte === HINT_TAG_BYTE && bytes[colon + 2] === LINK_HINT_CODE_BYTE) {
|
|
151
|
+
const line = bytes.subarray(offset, newline + 1);
|
|
152
|
+
const normalized = normalizeReactFlightHintLine(line);
|
|
153
|
+
if (normalized !== line) {
|
|
154
|
+
if (!ownsOutput) {
|
|
155
|
+
output = bytes.slice();
|
|
156
|
+
ownsOutput = true;
|
|
157
|
+
}
|
|
158
|
+
output.set(normalized, offset);
|
|
159
|
+
}
|
|
126
160
|
}
|
|
127
|
-
|
|
128
|
-
bytes = bytes.subarray(newline + 1);
|
|
161
|
+
offset = newline + 1;
|
|
129
162
|
}
|
|
163
|
+
if (offset < byteLength) carry = bytes.slice(offset);
|
|
164
|
+
if (offset > emittedThrough) controller.enqueue(offset === byteLength && emittedThrough === 0 ? output : output.subarray(emittedThrough, offset));
|
|
130
165
|
},
|
|
131
166
|
flush(controller) {
|
|
132
|
-
if (carry.byteLength > 0) controller.enqueue(rawBytesRemaining > 0 ? carry : normalizeReactFlightHintLine(carry));
|
|
167
|
+
if (carry !== null && carry.byteLength > 0) controller.enqueue(rawBytesRemaining > 0 ? carry : normalizeReactFlightHintLine(carry));
|
|
133
168
|
}
|
|
134
169
|
}));
|
|
135
170
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { appIsrCacheKey,
|
|
2
|
+
import { appIsrCacheKey, isrSet, isrSetPrerenderedAppPage } from "./isr-cache.js";
|
|
3
3
|
import { addPregeneratedConcretePath, addPregeneratedRoute, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
|
|
4
4
|
import { getRenderedAppRoutes, getRenderedMetadataRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
|
|
5
5
|
import { buildAppPageCacheTags, buildAppRouteCacheTags } from "./app-page-cache.js";
|
|
@@ -64,9 +64,8 @@ async function seedMemoryCacheFromPrerender(serverDir, options) {
|
|
|
64
64
|
if (!isFallbackShellArtifactPath(concretePathname, route)) addPregeneratedConcretePath(route.route, concretePathname);
|
|
65
65
|
const artifactPathname = route.path ?? route.route;
|
|
66
66
|
const cachePathname = normalizePregeneratedPathname(artifactPathname);
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const rscKey = options?.buildAppPageRscKey?.(cachePathname) ?? baseKey + ":rsc";
|
|
67
|
+
const htmlKey = options?.buildAppPageHtmlKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "html", buildId);
|
|
68
|
+
const rscKey = options?.buildAppPageRscKey?.(cachePathname) ?? appIsrCacheKey(cachePathname, "rsc", buildId);
|
|
70
69
|
const revalidateSeconds = typeof route.revalidate === "number" ? route.revalidate : void 0;
|
|
71
70
|
const expireSeconds = typeof route.expire === "number" ? route.expire : void 0;
|
|
72
71
|
const staleSeconds = typeof route.stale === "number" && route.stale >= 0 ? route.stale : void 0;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
*
|
|
34
34
|
* **Prerender check is dynamic, not install-time.** Prerender (in
|
|
35
35
|
* `build/prerender.ts` and `build/run-prerender.ts`) calls
|
|
36
|
-
* `startProdServer()` from inside `
|
|
36
|
+
* `startProdServer()` from inside `vite build` to render pages
|
|
37
37
|
* against a real HTTP server. User `fetch()` calls during prerender
|
|
38
38
|
* hit external APIs that can drop connections; absorbing those would
|
|
39
39
|
* silently produce corrupt prerendered output instead of crashing
|
|
@@ -6,7 +6,45 @@ type CacheCaptureEnvelope = {
|
|
|
6
6
|
type: typeof CACHE_CAPTURE_TYPE;
|
|
7
7
|
encrypted: string | PromiseLike<string>;
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* Flight serializes a promise as its resolved value and drops its own fields.
|
|
11
|
+
* Next.js params are promises that also expose their resolved fields, and the
|
|
12
|
+
* cache key is built from those fields, so the payload carries each such
|
|
13
|
+
* promise's fields next to the arguments and decoding assigns them back.
|
|
14
|
+
*/
|
|
15
|
+
type EncodedCacheArguments = {
|
|
16
|
+
args: unknown[];
|
|
17
|
+
thenableObjects: EncodedThenableObject[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Flight writes each object once, so `promise` decodes to the same promise as
|
|
21
|
+
* every other reference to it, including ones inside resolved values, and the
|
|
22
|
+
* fields share references with the arguments. The fields build the cache key;
|
|
23
|
+
* the resolved value can differ: the params proxy hides params named like
|
|
24
|
+
* promise or React fields (`value`, `status`) from its own keys but still
|
|
25
|
+
* resolves to them.
|
|
26
|
+
*/
|
|
27
|
+
type EncodedThenableObject = {
|
|
28
|
+
fields: Record<string, unknown>;
|
|
29
|
+
promise: PromiseLike<unknown>;
|
|
30
|
+
};
|
|
9
31
|
export declare function encryptCacheCaptures(captures: unknown[]): CacheCaptureEnvelope;
|
|
32
|
+
/**
|
|
33
|
+
* What to do when a read would run a getter: `reject` throws
|
|
34
|
+
* `UnreplayableCacheArgumentsError`, `skip` leaves the getter unread.
|
|
35
|
+
*/
|
|
36
|
+
type GetterHandling = "reject" | "skip";
|
|
37
|
+
/**
|
|
38
|
+
* Collect the own fields of every promise-augmented object in the arguments,
|
|
39
|
+
* including ones inside resolved promise values. The arguments are passed to
|
|
40
|
+
* Flight as they are, so Flight keeps their shared references and cycles.
|
|
41
|
+
* With `getters: "reject"`, throws `UnreplayableCacheArgumentsError` when the
|
|
42
|
+
* arguments hold a getter; with `"skip"`, promise fields behind a getter are
|
|
43
|
+
* not recorded.
|
|
44
|
+
*/
|
|
45
|
+
export declare function encodeCacheArguments(args: unknown[], getters?: GetterHandling): Promise<EncodedCacheArguments>;
|
|
46
|
+
/** Restore the promise fields that `encodeCacheArguments` captured before Flight encoding. */
|
|
47
|
+
export declare function decodeCacheArguments(value: unknown): unknown[];
|
|
10
48
|
export declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant: string, options: RegisterCachedFunctionOptions): (...args: TArgs) => Promise<TResult>;
|
|
11
49
|
/** Load and invoke one transformed cache function through its server-reference identity. */
|
|
12
50
|
export declare function invokeCacheFunction(invocation: VinextCacheFunctionInvocation, loadServerAction: (id: string) => Promise<unknown>): Promise<void>;
|
|
@@ -1,39 +1,190 @@
|
|
|
1
|
-
import { isUseCacheFunction, registerCachedFunction as registerCachedFunction$1 } from "./cache-runtime.js";
|
|
1
|
+
import { isThenableObject, isUseCacheFunction, registerCachedFunction as registerCachedFunction$1 } from "./cache-runtime.js";
|
|
2
2
|
import { decryptActionBoundArgs, encryptActionBoundArgs } from "@vitejs/plugin-rsc/utils/encryption-runtime";
|
|
3
3
|
//#region src/shims/cache-callable-runtime.ts
|
|
4
4
|
const CACHE_CAPTURE_TYPE = "use-cache-captures";
|
|
5
5
|
function encryptCacheCaptures(captures) {
|
|
6
6
|
return {
|
|
7
7
|
type: CACHE_CAPTURE_TYPE,
|
|
8
|
-
encrypted:
|
|
8
|
+
encrypted: encryptCaptures(captures)
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
async function decryptCacheCaptures(value) {
|
|
12
12
|
if (!isCacheCaptureEnvelope(value)) return;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
return decryptCacheArguments(value.encrypted);
|
|
14
|
+
}
|
|
15
|
+
async function encryptCaptures(captures) {
|
|
16
|
+
return encryptActionBoundArgs(await encodeCacheArguments(captures, "skip"));
|
|
17
|
+
}
|
|
18
|
+
async function encryptCacheArguments(args) {
|
|
19
|
+
return encryptActionBoundArgs(await encodeCacheArguments(args));
|
|
20
|
+
}
|
|
21
|
+
async function decryptCacheArguments(encrypted) {
|
|
22
|
+
return decodeCacheArguments(await decryptActionBoundArgs(Promise.resolve(encrypted)));
|
|
23
|
+
}
|
|
24
|
+
function isThenable(value) {
|
|
25
|
+
return "then" in value && typeof value.then === "function";
|
|
26
|
+
}
|
|
27
|
+
function isPlainRecord(value) {
|
|
28
|
+
const prototype = Object.getPrototypeOf(value);
|
|
29
|
+
return (prototype === Object.prototype || prototype === null) && !("$$typeof" in value);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The arguments hold a getter. Flight reads it again while serializing, and a
|
|
33
|
+
* getter can return a different value, such as a new promise, on every read,
|
|
34
|
+
* so the recorded promise fields may not match what Flight serializes.
|
|
35
|
+
*/
|
|
36
|
+
var UnreplayableCacheArgumentsError = class extends Error {
|
|
37
|
+
constructor() {
|
|
38
|
+
super("Cache function arguments with getters cannot be replayed");
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The own entries of `value` that Flight serializes: every index below an
|
|
43
|
+
* array's `length`, including holes and non-enumerable indices, as
|
|
44
|
+
* `JSON.stringify` reads them, and the enumerable own keys of anything else.
|
|
45
|
+
* A getter, own or inherited through an array hole, is never run.
|
|
46
|
+
*/
|
|
47
|
+
function ownEntries(value, getters) {
|
|
48
|
+
const keys = Array.isArray(value) ? Array.from({ length: value.length }, (_, index) => String(index)) : Object.keys(value);
|
|
49
|
+
const entries = [];
|
|
50
|
+
for (const key of keys) {
|
|
51
|
+
if (readsGetter(value, key)) {
|
|
52
|
+
if (getters === "reject") throw new UnreplayableCacheArgumentsError();
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
entries.push([key, Reflect.get(value, key)]);
|
|
56
|
+
}
|
|
57
|
+
return entries;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether reading `key` from `value` runs a getter. An array hole reads
|
|
61
|
+
* through the prototype chain, which can hold an indexed data property or
|
|
62
|
+
* accessor. A setter-only accessor reads as `undefined` without running code.
|
|
63
|
+
*/
|
|
64
|
+
function readsGetter(value, key) {
|
|
65
|
+
for (let target = value; target !== null; target = Reflect.getPrototypeOf(target)) {
|
|
66
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
67
|
+
if (descriptor) return typeof descriptor.get === "function";
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/** Members of the values Flight serializes recursively, which can hold params. */
|
|
72
|
+
function flightMembers(value, getters) {
|
|
73
|
+
if (value instanceof Map) return [...value].flat();
|
|
74
|
+
if (value instanceof Set) return [...value];
|
|
75
|
+
if (isThenableObject(value) || Array.isArray(value) || isPlainRecord(value)) return ownEntries(value, getters).map(([, member]) => member);
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Collect the own fields of every promise-augmented object in the arguments,
|
|
80
|
+
* including ones inside resolved promise values. The arguments are passed to
|
|
81
|
+
* Flight as they are, so Flight keeps their shared references and cycles.
|
|
82
|
+
* With `getters: "reject"`, throws `UnreplayableCacheArgumentsError` when the
|
|
83
|
+
* arguments hold a getter; with `"skip"`, promise fields behind a getter are
|
|
84
|
+
* not recorded.
|
|
85
|
+
*/
|
|
86
|
+
async function encodeCacheArguments(args, getters = "reject") {
|
|
87
|
+
const settled = /* @__PURE__ */ new Map();
|
|
88
|
+
for (;;) {
|
|
89
|
+
const thenableObjects = [];
|
|
90
|
+
const unsettled = [];
|
|
91
|
+
const visited = /* @__PURE__ */ new Set();
|
|
92
|
+
const pending = [args];
|
|
93
|
+
while (pending.length > 0) {
|
|
94
|
+
const value = pending.pop();
|
|
95
|
+
if (typeof value !== "object" || value === null || visited.has(value)) continue;
|
|
96
|
+
visited.add(value);
|
|
97
|
+
const children = flightMembers(value, getters);
|
|
98
|
+
if (isThenableObject(value)) {
|
|
99
|
+
const fields = Object.fromEntries(ownEntries(value, getters));
|
|
100
|
+
thenableObjects.push({
|
|
101
|
+
fields,
|
|
102
|
+
promise: value
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (isThenable(value)) {
|
|
106
|
+
const result = settled.get(value);
|
|
107
|
+
if (!result) unsettled.push(value);
|
|
108
|
+
else if (result.status === "fulfilled") children.push(result.value);
|
|
109
|
+
}
|
|
110
|
+
for (const child of children) pending.push(child);
|
|
111
|
+
}
|
|
112
|
+
if (unsettled.length === 0) return {
|
|
113
|
+
args,
|
|
114
|
+
thenableObjects
|
|
115
|
+
};
|
|
116
|
+
const results = await Promise.allSettled(unsettled);
|
|
117
|
+
unsettled.forEach((thenable, index) => settled.set(thenable, results[index]));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Restore the promise fields that `encodeCacheArguments` captured before Flight encoding. */
|
|
121
|
+
function decodeCacheArguments(value) {
|
|
122
|
+
if (typeof value !== "object" || value === null || !("args" in value) || !Array.isArray(value.args) || !("thenableObjects" in value) || !Array.isArray(value.thenableObjects)) throw new Error("Invalid cache function arguments");
|
|
123
|
+
adoptFlightThenables(value);
|
|
124
|
+
for (const thenableObject of value.thenableObjects) {
|
|
125
|
+
if (!isEncodedThenableObject(thenableObject)) throw new Error("Invalid cache function arguments");
|
|
126
|
+
Object.assign(thenableObject.promise, thenableObject.fields);
|
|
127
|
+
}
|
|
128
|
+
return value.args;
|
|
129
|
+
}
|
|
130
|
+
function isEncodedThenableObject(value) {
|
|
131
|
+
if (typeof value !== "object" || value === null || !isPlainRecord(value)) return false;
|
|
132
|
+
const { fields, promise } = value;
|
|
133
|
+
return typeof fields === "object" && fields !== null && isPlainRecord(fields) && promise instanceof Promise;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Flight decodes promises as React chunks whose own fields are React's
|
|
137
|
+
* internal state. Adopt them into native promises, which have no own fields,
|
|
138
|
+
* so key serialization sees a promise exactly as the original call did.
|
|
139
|
+
* Flight shares one chunk between references to the same promise, so each
|
|
140
|
+
* chunk is adopted once, including references inside resolved values.
|
|
141
|
+
*/
|
|
142
|
+
function adoptFlightThenables(value, adopted = /* @__PURE__ */ new WeakMap()) {
|
|
143
|
+
if (typeof value !== "object" || value === null) return value;
|
|
144
|
+
if (adopted.has(value)) return adopted.get(value);
|
|
145
|
+
if (isThenable(value)) {
|
|
146
|
+
const promise = Promise.resolve(value).then((resolved) => adoptFlightThenables(resolved, adopted));
|
|
147
|
+
promise.catch(() => {});
|
|
148
|
+
adopted.set(value, promise);
|
|
149
|
+
return promise;
|
|
150
|
+
}
|
|
151
|
+
if (value instanceof Map) {
|
|
152
|
+
adopted.set(value, value);
|
|
153
|
+
const entries = [...value];
|
|
154
|
+
value.clear();
|
|
155
|
+
for (const [key, item] of entries) value.set(adoptFlightThenables(key, adopted), adoptFlightThenables(item, adopted));
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
if (value instanceof Set) {
|
|
159
|
+
adopted.set(value, value);
|
|
160
|
+
const items = [...value];
|
|
161
|
+
value.clear();
|
|
162
|
+
for (const item of items) value.add(adoptFlightThenables(item, adopted));
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
if (!Array.isArray(value) && !isPlainRecord(value)) return value;
|
|
166
|
+
adopted.set(value, value);
|
|
167
|
+
for (const key of Object.keys(value)) Reflect.set(value, key, adoptFlightThenables(Reflect.get(value, key), adopted));
|
|
168
|
+
return value;
|
|
16
169
|
}
|
|
17
170
|
function isCacheCaptureEnvelope(value) {
|
|
18
171
|
if (typeof value !== "object" || value === null) return false;
|
|
19
172
|
if (!("type" in value) || value.type !== CACHE_CAPTURE_TYPE || !("encrypted" in value)) return false;
|
|
20
173
|
const encrypted = value.encrypted;
|
|
21
|
-
return typeof encrypted === "string" || typeof encrypted === "object" && encrypted !== null &&
|
|
174
|
+
return typeof encrypted === "string" || typeof encrypted === "object" && encrypted !== null && isThenable(encrypted);
|
|
22
175
|
}
|
|
23
176
|
function registerCachedFunction(fn, id, variant, options) {
|
|
24
177
|
return registerCachedFunction$1(fn, id, variant, {
|
|
25
178
|
...options,
|
|
26
179
|
decryptCaptures: decryptCacheCaptures,
|
|
27
|
-
encodeInvocationArgs:
|
|
180
|
+
encodeInvocationArgs: encryptCacheArguments
|
|
28
181
|
});
|
|
29
182
|
}
|
|
30
183
|
/** Load and invoke one transformed cache function through its server-reference identity. */
|
|
31
184
|
async function invokeCacheFunction(invocation, loadServerAction) {
|
|
32
185
|
const fn = await loadServerAction(invocation.referenceId);
|
|
33
186
|
if (!isUseCacheFunction(fn)) throw new Error(`Server reference ${invocation.referenceId} is not a cache function`);
|
|
34
|
-
|
|
35
|
-
if (!Array.isArray(args)) throw new Error("Invalid cache function arguments");
|
|
36
|
-
await fn(...args);
|
|
187
|
+
await fn(...await decryptCacheArguments(invocation.encryptedArgs));
|
|
37
188
|
}
|
|
38
189
|
//#endregion
|
|
39
|
-
export { encryptCacheCaptures, invokeCacheFunction, registerCachedFunction };
|
|
190
|
+
export { decodeCacheArguments, encodeCacheArguments, encryptCacheCaptures, invokeCacheFunction, registerCachedFunction };
|
|
@@ -83,14 +83,6 @@ export type RegisterCachedFunctionOptions = {
|
|
|
83
83
|
* transform records this separately for metadata parent resolution.
|
|
84
84
|
*/
|
|
85
85
|
acceptsSecondArgument?: boolean;
|
|
86
|
-
/**
|
|
87
|
-
* Internal transform metadata for file-level `"use cache"` default exports
|
|
88
|
-
* in App Router `page.*` files. Page components receive framework-owned
|
|
89
|
-
* `{ params, searchParams }` props. React may copy that props object before
|
|
90
|
-
* invocation, so this invariant must live at the cached function boundary
|
|
91
|
-
* rather than on the intermediate createElement config object.
|
|
92
|
-
*/
|
|
93
|
-
appPageDefaultExport?: boolean;
|
|
94
86
|
/** Number of declared arguments supplied by the directive transform. */
|
|
95
87
|
argumentCount?: number;
|
|
96
88
|
decryptCaptures?: (value: unknown) => Promise<unknown[] | undefined>;
|
|
@@ -109,5 +101,11 @@ export type RegisterCachedFunctionOptions = {
|
|
|
109
101
|
export declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant?: string, options?: RegisterCachedFunctionOptions): (...args: TArgs) => Promise<TResult>;
|
|
110
102
|
/** Whether a loaded server reference is a transformed `"use cache"` function. */
|
|
111
103
|
export declare function isUseCacheFunction(value: unknown): value is (...args: unknown[]) => Promise<unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* A thenable (not an array) with own enumerable properties — the
|
|
106
|
+
* `Object.assign(Promise.resolve(obj), obj)` pattern Next.js params use. The
|
|
107
|
+
* cache key is built from its fields instead of the promise.
|
|
108
|
+
*/
|
|
109
|
+
export declare function isThenableObject(value: object): value is PromiseLike<unknown>;
|
|
112
110
|
//#endregion
|
|
113
111
|
export { markAppPagePropsForUseCache };
|
|
@@ -6,10 +6,11 @@ import { isRouteCacheabilityProbe, recordRouteCacheabilityProbeBailout } from ".
|
|
|
6
6
|
import { getDataCacheHandler } from "./cache-handler.js";
|
|
7
7
|
import { suppressHangingPromiseAbortRejections } from "./internal/make-hanging-promise.js";
|
|
8
8
|
import { createPprFallbackShellSuspensePromise, trackPprFallbackShellCacheTask } from "./ppr-fallback-shell.js";
|
|
9
|
-
import { isDraftModeEnabled, markDynamicUsage } from "./headers.js";
|
|
9
|
+
import { isDraftModeEnabled, markDynamicUsage, throwIfInsideCacheScope } from "./headers.js";
|
|
10
10
|
import { _hasPendingRevalidatedTag, _registerCacheContextAccessor, _setRequestScopedCacheLife, cacheLifeProfiles } from "./cache-request-state.js";
|
|
11
11
|
import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
|
|
12
|
-
import {
|
|
12
|
+
import { makeThenableParams } from "./thenable-params.js";
|
|
13
|
+
import { APP_PAGE_USE_CACHE_MARKER, hasUseCachePageMarker, isMarkedAppPagePropsObject, isUseCacheFunctionReference, markAppPagePropsForUseCache } from "./internal/app-page-props-cache-key.js";
|
|
13
14
|
import { getCurrentRootParams } from "./root-params.js";
|
|
14
15
|
//#region src/shims/cache-runtime.ts
|
|
15
16
|
/**
|
|
@@ -309,7 +310,8 @@ function propagateRootParamNamesToParent(names) {
|
|
|
309
310
|
*/
|
|
310
311
|
function registerCachedFunction(fn, id, variant, options = {}) {
|
|
311
312
|
const cacheVariant = variant ?? "";
|
|
312
|
-
const
|
|
313
|
+
const omitAppPageSearchParams = cacheVariant !== "private";
|
|
314
|
+
const cacheFunctionId = options.serverReferenceId ? JSON.stringify([id, options.serverReferenceId]) : id;
|
|
313
315
|
const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
|
|
314
316
|
const cachedFn = (...args) => {
|
|
315
317
|
if (cacheVariant === "private") {
|
|
@@ -346,16 +348,27 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
346
348
|
const keySeed = getUseCacheKeySeed();
|
|
347
349
|
const captures = options.decryptCaptures ? await options.decryptCaptures(args[0]) : void 0;
|
|
348
350
|
const hasCaptureEnvelope = captures !== void 0;
|
|
349
|
-
const
|
|
351
|
+
const pagePropsArgIndex = args.findIndex(hasUseCachePageMarker);
|
|
352
|
+
const isPageInvocation = pagePropsArgIndex !== -1;
|
|
353
|
+
const invocationArgs = isPageInvocation ? replaceArgument(args, pagePropsArgIndex, withoutUseCachePageMarker(args[pagePropsArgIndex])) : args;
|
|
354
|
+
const admittedArgs = options.argumentCount === void 0 ? invocationArgs : hasCaptureEnvelope ? [invocationArgs[0], ...invocationArgs.slice(1, 1 + options.argumentCount)] : invocationArgs.slice(0, options.argumentCount);
|
|
350
355
|
const executionArgs = hasCaptureEnvelope ? [captures, ...admittedArgs.slice(1)] : admittedArgs;
|
|
351
|
-
const
|
|
356
|
+
const pagePropsIndex = omitAppPageSearchParams && isPageInvocation ? pagePropsArgIndex : void 0;
|
|
357
|
+
const callArgs = pagePropsIndex === void 0 ? executionArgs : withErroringPageSearchParams(executionArgs, pagePropsIndex);
|
|
352
358
|
let cacheKey;
|
|
353
359
|
try {
|
|
354
|
-
const processedArgs = executionArgs.length > 0 ? unwrapThenableObjectArray(executionArgs, {
|
|
360
|
+
const processedArgs = executionArgs.length > 0 ? unwrapThenableObjectArray(executionArgs, {
|
|
361
|
+
pagePropsIndex,
|
|
362
|
+
omitMarkedAppPageSearchParams: omitAppPageSearchParams
|
|
363
|
+
}) : [];
|
|
355
364
|
if (rsc && executionArgs.length > 0) {
|
|
356
365
|
const tempRefs = rsc.createClientTemporaryReferenceSet();
|
|
357
|
-
|
|
358
|
-
|
|
366
|
+
const encoded = await rsc.encodeReply(processedArgs, { temporaryReferences: tempRefs });
|
|
367
|
+
cacheKey = buildUseCacheKey(cacheFunctionId, keySeed, await replyToCacheKey(encoded));
|
|
368
|
+
} else {
|
|
369
|
+
const argsKey = processedArgs.length > 0 ? stableStringify(processedArgs) : void 0;
|
|
370
|
+
cacheKey = buildUseCacheKey(cacheFunctionId, keySeed, argsKey);
|
|
371
|
+
}
|
|
359
372
|
} catch {
|
|
360
373
|
return (await executeWithContext(fn, callArgs, cacheVariant)).result;
|
|
361
374
|
}
|
|
@@ -418,7 +431,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
|
|
|
418
431
|
let cacheFunctionInvocation;
|
|
419
432
|
if (options.serverReferenceId && options.encodeInvocationArgs) try {
|
|
420
433
|
cacheFunctionInvocation = {
|
|
421
|
-
encryptedArgs: await options.encodeInvocationArgs(admittedArgs),
|
|
434
|
+
encryptedArgs: await options.encodeInvocationArgs(pagePropsIndex === void 0 ? admittedArgs : toReplayablePageArgs(admittedArgs, pagePropsIndex)),
|
|
422
435
|
referenceId: options.serverReferenceId,
|
|
423
436
|
rootParams: Object.fromEntries(Object.entries(rootParams ?? {}).filter((entry) => entry[1] !== void 0)),
|
|
424
437
|
softTags
|
|
@@ -482,7 +495,7 @@ const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
|
|
|
482
495
|
const USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL = Symbol.for("vinext.useCacheAcceptsSecondArgument");
|
|
483
496
|
/** Whether a loaded server reference is a transformed `"use cache"` function. */
|
|
484
497
|
function isUseCacheFunction(value) {
|
|
485
|
-
return
|
|
498
|
+
return isUseCacheFunctionReference(value);
|
|
486
499
|
}
|
|
487
500
|
function throwPrivateUseCacheInsidePublicUseCacheError() {
|
|
488
501
|
const error = /* @__PURE__ */ new Error("\"use cache: private\" must not be used within \"use cache\". It can only be nested inside of another \"use cache: private\".");
|
|
@@ -590,27 +603,79 @@ async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
|
|
|
590
603
|
collectedResult
|
|
591
604
|
};
|
|
592
605
|
}
|
|
593
|
-
function unwrapThenableObjects(value, options
|
|
606
|
+
function unwrapThenableObjects(value, options) {
|
|
594
607
|
if (value === null || value === void 0 || typeof value !== "object") return value;
|
|
595
|
-
|
|
596
|
-
if (
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return plain;
|
|
602
|
-
}
|
|
603
|
-
return value;
|
|
608
|
+
const childOptions = { omitMarkedAppPageSearchParams: options.omitMarkedAppPageSearchParams };
|
|
609
|
+
if (Array.isArray(value)) return value.map((item) => unwrapThenableObjects(item, childOptions));
|
|
610
|
+
if (isThenableObject(value)) {
|
|
611
|
+
const plain = {};
|
|
612
|
+
for (const key of Object.keys(value)) plain[key] = unwrapThenableObjects(value[key], childOptions);
|
|
613
|
+
return plain;
|
|
604
614
|
}
|
|
615
|
+
if (typeof value.then === "function") return value;
|
|
605
616
|
const result = {};
|
|
606
617
|
for (const key of Object.keys(value)) {
|
|
607
|
-
if (key === "searchParams" && (options.omitAppPageSearchParamsAtRoot || isMarkedAppPagePropsObject(value))) continue;
|
|
608
|
-
result[key] = unwrapThenableObjects(value[key]);
|
|
618
|
+
if (key === "searchParams" && (options.omitAppPageSearchParamsAtRoot || options.omitMarkedAppPageSearchParams && isMarkedAppPagePropsObject(value))) continue;
|
|
619
|
+
result[key] = unwrapThenableObjects(value[key], childOptions);
|
|
609
620
|
}
|
|
610
621
|
return result;
|
|
611
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* A thenable (not an array) with own enumerable properties — the
|
|
625
|
+
* `Object.assign(Promise.resolve(obj), obj)` pattern Next.js params use. The
|
|
626
|
+
* cache key is built from its fields instead of the promise.
|
|
627
|
+
*/
|
|
628
|
+
function isThenableObject(value) {
|
|
629
|
+
return !Array.isArray(value) && "then" in value && typeof value.then === "function" && Object.keys(value).length > 0;
|
|
630
|
+
}
|
|
631
|
+
function isPagePropsObject(value) {
|
|
632
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
633
|
+
}
|
|
634
|
+
function replaceArgument(args, index, value) {
|
|
635
|
+
const result = [...args];
|
|
636
|
+
result[index] = value;
|
|
637
|
+
return result;
|
|
638
|
+
}
|
|
639
|
+
/** Remove the `$$isPage` invocation marker before props reach the key or user code. */
|
|
640
|
+
function withoutUseCachePageMarker(props) {
|
|
641
|
+
const { [APP_PAGE_USE_CACHE_MARKER]: _marker, ...pageProps } = props;
|
|
642
|
+
return isMarkedAppPagePropsObject(props) ? markAppPagePropsForUseCache(pageProps) : pageProps;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Response Store replay args for a public page cache: drop `searchParams` from
|
|
646
|
+
* the page props at `index` (after a capture envelope, if any), as Next.js does
|
|
647
|
+
* for the serialized arguments (use-cache-wrapper.ts, `isPageSegmentFunction`),
|
|
648
|
+
* and keep the `$$isPage` marker so a replay regains page semantics, including
|
|
649
|
+
* the erroring searchParams fallback.
|
|
650
|
+
*/
|
|
651
|
+
function toReplayablePageArgs(args, index) {
|
|
652
|
+
const props = args[index];
|
|
653
|
+
if (!isPagePropsObject(props)) return [...args];
|
|
654
|
+
const { searchParams: _searchParams, ...pageProps } = props;
|
|
655
|
+
return replaceArgument(args, index, {
|
|
656
|
+
...pageProps,
|
|
657
|
+
[APP_PAGE_USE_CACHE_MARKER]: true
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Give page props at `index` without `searchParams` (a Response Store replay of
|
|
662
|
+
* args encoded by `toReplayablePageArgs`) a value that throws on
|
|
663
|
+
* access inside the cache scope, like Next.js's
|
|
664
|
+
* `makeErroringSearchParamsForUseCache`, instead of `undefined`.
|
|
665
|
+
*/
|
|
666
|
+
function withErroringPageSearchParams(args, index) {
|
|
667
|
+
const props = args[index];
|
|
668
|
+
if (!isPagePropsObject(props) || "searchParams" in props) return args;
|
|
669
|
+
return replaceArgument(args, index, {
|
|
670
|
+
...props,
|
|
671
|
+
searchParams: makeThenableParams({}, { observeParamAccess: () => throwIfInsideCacheScope("searchParams") })
|
|
672
|
+
});
|
|
673
|
+
}
|
|
612
674
|
function unwrapThenableObjectArray(values, options) {
|
|
613
|
-
return values.map((value, index) => unwrapThenableObjects(value, {
|
|
675
|
+
return values.map((value, index) => unwrapThenableObjects(value, {
|
|
676
|
+
omitAppPageSearchParamsAtRoot: index === options.pagePropsIndex,
|
|
677
|
+
omitMarkedAppPageSearchParams: options.omitMarkedAppPageSearchParams
|
|
678
|
+
}));
|
|
614
679
|
}
|
|
615
680
|
function stableStringify(value, seen) {
|
|
616
681
|
if (value === void 0) return "undefined";
|
|
@@ -637,4 +702,4 @@ function stableStringify(value, seen) {
|
|
|
637
702
|
return JSON.stringify(value);
|
|
638
703
|
}
|
|
639
704
|
//#endregion
|
|
640
|
-
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isUseCacheFunction, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|
|
705
|
+
export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isThenableObject, isUseCacheFunction, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
|
package/dist/shims/constants.js
CHANGED
|
@@ -91,7 +91,7 @@ const CONFIG_FILES = [
|
|
|
91
91
|
"next.config.js",
|
|
92
92
|
"next.config.mjs",
|
|
93
93
|
"next.config.ts",
|
|
94
|
-
...process
|
|
94
|
+
...typeof process !== "undefined" && process.features?.typescript ? ["next.config.mts"] : []
|
|
95
95
|
];
|
|
96
96
|
const BUILD_ID_FILE = "BUILD_ID";
|
|
97
97
|
const BLOCKED_PAGES = [
|