vinext 1.0.0-beta.12 → 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.
Files changed (132) hide show
  1. package/README.md +39 -12
  2. package/dist/build/action-owner-manifest.js +23 -5
  3. package/dist/build/lifecycle.d.ts +42 -0
  4. package/dist/build/lifecycle.js +246 -0
  5. package/dist/build/nitro-route-rules.js +1 -1
  6. package/dist/build/pages-client-assets-module.d.ts +0 -3
  7. package/dist/build/pages-client-assets-module.js +1 -13
  8. package/dist/build/precompress.js +1 -1
  9. package/dist/build/prerender-paths.d.ts +1 -1
  10. package/dist/build/prerender-paths.js +6 -6
  11. package/dist/build/prerender-server-pool.js +1 -1
  12. package/dist/build/prerender.d.ts +1 -1
  13. package/dist/build/prerender.js +5 -5
  14. package/dist/build/preview-credentials.d.ts +1 -1
  15. package/dist/build/preview-credentials.js +2 -2
  16. package/dist/build/report.js +1 -1
  17. package/dist/build/run-prerender.d.ts +2 -2
  18. package/dist/build/run-prerender.js +5 -5
  19. package/dist/build/standalone.js +2 -2
  20. package/dist/cli-args.d.ts +5 -13
  21. package/dist/cli-args.js +2 -45
  22. package/dist/cli-dev-config.d.ts +6 -2
  23. package/dist/cli-dev-config.js +160 -3
  24. package/dist/cli.js +104 -439
  25. package/dist/config/config-matchers.js +1 -1
  26. package/dist/config/next-config.d.ts +2 -2
  27. package/dist/config/next-config.js +5 -5
  28. package/dist/config/prerender.d.ts +3 -0
  29. package/dist/config/prerender.js +8 -2
  30. package/dist/entries/app-browser-entry.js +1 -1
  31. package/dist/entries/app-rsc-entry.js +1 -1
  32. package/dist/entries/pages-client-entry.d.ts +1 -0
  33. package/dist/entries/pages-client-entry.js +17 -2
  34. package/dist/index.d.ts +6 -8
  35. package/dist/index.js +262 -101
  36. package/dist/init-cloudflare.d.ts +3 -2
  37. package/dist/init-cloudflare.js +117 -5
  38. package/dist/init-platform.d.ts +2 -0
  39. package/dist/init-platform.js +9 -3
  40. package/dist/init.d.ts +7 -5
  41. package/dist/init.js +41 -22
  42. package/dist/plugins/dynamic-preload-metadata.js +1 -1
  43. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  44. package/dist/plugins/fonts.js +1 -1
  45. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  46. package/dist/plugins/import-meta-url.js +1 -1
  47. package/dist/plugins/instrumentation-client.js +1 -1
  48. package/dist/plugins/og-assets.js +32 -13
  49. package/dist/plugins/og-harfbuzz.d.ts +24 -0
  50. package/dist/plugins/og-harfbuzz.js +260 -0
  51. package/dist/plugins/optimize-imports.js +1 -1
  52. package/dist/plugins/require-condition-resolution.js +2 -2
  53. package/dist/plugins/require-context.js +2 -2
  54. package/dist/plugins/typeof-window.js +1 -1
  55. package/dist/plugins/use-cache-callable.d.ts +0 -2
  56. package/dist/plugins/use-cache-callable.js +8 -16
  57. package/dist/plugins/worker-image-imports.js +1 -1
  58. package/dist/routing/app-route-graph.js +1 -1
  59. package/dist/routing/app-router.js +1 -1
  60. package/dist/routing/pages-router.js +1 -1
  61. package/dist/server/app-action-forwarding.js +1 -1
  62. package/dist/server/app-browser-error.js +1 -1
  63. package/dist/server/app-elements-wire.js +2 -2
  64. package/dist/server/app-middleware.js +1 -1
  65. package/dist/server/app-optimistic-routing.js +1 -1
  66. package/dist/server/app-page-dispatch.js +1 -1
  67. package/dist/server/app-page-element-builder.js +3 -2
  68. package/dist/server/app-page-probe.js +3 -3
  69. package/dist/server/app-request-stage-independent-entry.js +2 -2
  70. package/dist/server/app-route-handler-dispatch.js +1 -1
  71. package/dist/server/app-route-handler-runtime.js +1 -1
  72. package/dist/server/app-router-entry.js +2 -2
  73. package/dist/server/app-rsc-handler.d.ts +1 -1
  74. package/dist/server/app-rsc-handler.js +4 -4
  75. package/dist/server/app-rsc-response-stage.js +1 -1
  76. package/dist/server/app-rsc-route-matching.js +1 -1
  77. package/dist/server/app-server-action-execution.js +4 -4
  78. package/dist/server/artifact-compatibility.js +1 -1
  79. package/dist/server/client-reuse-manifest.js +1 -1
  80. package/dist/server/dev-lockfile.d.ts +1 -1
  81. package/dist/server/dev-lockfile.js +4 -1
  82. package/dist/server/dev-server.d.ts +1 -1
  83. package/dist/server/dev-server.js +28 -6
  84. package/dist/server/dev-stack-sourcemap.js +1 -1
  85. package/dist/server/isr-cache.js +1 -1
  86. package/dist/server/metadata-route-response.js +8 -0
  87. package/dist/server/middleware-runtime.js +3 -3
  88. package/dist/server/pages-data-route.js +1 -1
  89. package/dist/server/pages-dev-hydration.d.ts +6 -0
  90. package/dist/server/pages-dev-hydration.js +19 -7
  91. package/dist/server/pages-page-data.js +2 -2
  92. package/dist/server/pages-page-handler.js +1 -1
  93. package/dist/server/pages-page-response.js +1 -1
  94. package/dist/server/pages-request-pipeline.js +3 -3
  95. package/dist/server/pages-request-stage-entry.js +3 -3
  96. package/dist/server/pages-revalidate.js +1 -1
  97. package/dist/server/prerender-route-params.js +1 -1
  98. package/dist/server/prod-server.js +7 -7
  99. package/dist/server/request-pipeline.js +2 -2
  100. package/dist/server/socket-error-backstop.js +1 -1
  101. package/dist/shims/cache-callable-runtime.d.ts +38 -0
  102. package/dist/shims/cache-callable-runtime.js +162 -11
  103. package/dist/shims/cache-runtime.d.ts +6 -8
  104. package/dist/shims/cache-runtime.js +82 -22
  105. package/dist/shims/font-local.js +1 -1
  106. package/dist/shims/form.js +1 -1
  107. package/dist/shims/headers.js +2 -2
  108. package/dist/shims/internal/app-page-props-cache-key.d.ts +29 -0
  109. package/dist/shims/internal/app-page-props-cache-key.js +53 -1
  110. package/dist/shims/internal/format-url-object.d.ts +7 -0
  111. package/dist/shims/internal/format-url-object.js +53 -0
  112. package/dist/shims/internal/normalize-router-href.d.ts +15 -0
  113. package/dist/shims/internal/normalize-router-href.js +41 -0
  114. package/dist/shims/internal/pages-data-target.d.ts +4 -1
  115. package/dist/shims/internal/pages-data-target.js +28 -35
  116. package/dist/shims/internal/route-pattern-for-warning.d.ts +2 -2
  117. package/dist/shims/internal/route-pattern-for-warning.js +3 -3
  118. package/dist/shims/link.js +31 -92
  119. package/dist/shims/metadata.js +5 -4
  120. package/dist/shims/navigation.js +2 -2
  121. package/dist/shims/router-state.js +1 -1
  122. package/dist/shims/router.d.ts +8 -7
  123. package/dist/shims/router.js +312 -148
  124. package/dist/shims/server.js +3 -3
  125. package/dist/utils/built-asset-url.js +1 -1
  126. package/dist/utils/project.d.ts +1 -11
  127. package/dist/utils/project.js +19 -28
  128. package/dist/utils/react-version.d.ts +3 -1
  129. package/dist/utils/react-version.js +19 -1
  130. package/dist/utils/vite-cli-invocation.d.ts +21 -0
  131. package/dist/utils/vite-cli-invocation.js +144 -0
  132. package/package.json +10 -2
@@ -1,23 +1,23 @@
1
1
  import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
2
+ import { isUnknownRecord } from "../utils/record.js";
3
+ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
4
+ import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
5
+ import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
2
6
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
3
7
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
4
- import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
5
8
  import { VINEXT_PRERENDER_RENDER_ERROR_HEADER } from "./headers.js";
6
9
  import { normalizePath } from "./normalize-path.js";
7
10
  import { notFoundResponse } from "./http-error-responses.js";
8
11
  import { isOpenRedirectShaped } from "./open-redirect.js";
9
12
  import { readStaticFileSignal } from "./static-file-signal.js";
10
13
  import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
11
- import { isUnknownRecord } from "../utils/record.js";
12
14
  import { parseHttpDate } from "./http-date.js";
13
15
  import { evaluateStaticPreconditions } from "./http-conditional.js";
14
16
  import { buildNextDataNotFoundResponse, encodeUrlParserIgnoredCharacters, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname, shouldAddTrailingSlashToPagesDataPath, urlParserCreatesPagesDataPath } from "./pages-data-route.js";
15
- import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
16
17
  import { setPagesClientAssets } from "./pages-client-assets.js";
17
18
  import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
18
19
  import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, isSafeImageContentType, parseImageParams } from "./image-optimization.js";
19
20
  import { installSocketErrorBackstop } from "./socket-error-backstop.js";
20
- import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
21
21
  import { collectInlineCssManifest } from "../build/inline-css.js";
22
22
  import { readTrustedRevalidationHostname } from "./revalidation-host.js";
23
23
  import { traceFrameworkRequest } from "./request-tracing.js";
@@ -32,8 +32,8 @@ import { ifRangeAllowsRange, parseByteRange } from "./http-range.js";
32
32
  import { createRequire } from "node:module";
33
33
  import { AsyncLocalStorage } from "node:async_hooks";
34
34
  import fs from "node:fs";
35
- import fsp from "node:fs/promises";
36
35
  import { pathToFileURL } from "node:url";
36
+ import fsp from "node:fs/promises";
37
37
  import { Readable, pipeline } from "node:stream";
38
38
  import zlib from "node:zlib";
39
39
  import { createServer } from "node:http";
@@ -41,7 +41,7 @@ import { createServer } from "node:http";
41
41
  /**
42
42
  * Production server for vinext.
43
43
  *
44
- * Serves the built output from `vinext build`. Handles:
44
+ * Serves the built output from `vite build`. Handles:
45
45
  * - Static asset serving from client build output
46
46
  * - Pages Router: SSR rendering + API route handling
47
47
  * - App Router: RSC/SSR rendering, route handlers, server actions
@@ -842,7 +842,7 @@ async function startProdServer(options = {}) {
842
842
  const isAppRouter = fs.existsSync(rscEntryPath);
843
843
  if (!isAppRouter && !fs.existsSync(serverEntryPath)) {
844
844
  console.error(`[vinext] No build output found in ${outDir}`);
845
- console.error("Run `vinext build` first.");
845
+ console.error("Run `vite build` first.");
846
846
  process.exit(1);
847
847
  }
848
848
  if (isAppRouter) return startAppRouterServer({
@@ -1,7 +1,7 @@
1
- import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
2
1
  import "../utils/protocol-headers.js";
3
- import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS } from "./headers.js";
4
2
  import { getUnconsumedMiddlewareRequestHeaders } from "../utils/middleware-request-headers.js";
3
+ import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
4
+ import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS } from "./headers.js";
5
5
  import { forbiddenResponse, methodNotAllowedResponse, notFoundResponse } from "./http-error-responses.js";
6
6
  import { isOpenRedirectShaped } from "./open-redirect.js";
7
7
  import { createStaticFileSignal } from "./static-file-signal.js";
@@ -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 `vinext build` to render pages
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: encryptActionBoundArgs(captures)
8
+ encrypted: encryptCaptures(captures)
9
9
  };
10
10
  }
11
11
  async function decryptCacheCaptures(value) {
12
12
  if (!isCacheCaptureEnvelope(value)) return;
13
- const captures = await decryptActionBoundArgs(Promise.resolve(value.encrypted));
14
- if (!Array.isArray(captures)) throw new Error("Invalid cache capture payload");
15
- return captures;
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 && "then" in encrypted && typeof encrypted.then === "function";
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: encryptActionBoundArgs
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
- const args = await decryptActionBoundArgs(Promise.resolve(invocation.encryptedArgs));
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 { isMarkedAppPagePropsObject, markAppPagePropsForUseCache } from "./internal/app-page-props-cache-key.js";
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,7 @@ function propagateRootParamNamesToParent(names) {
309
310
  */
310
311
  function registerCachedFunction(fn, id, variant, options = {}) {
311
312
  const cacheVariant = variant ?? "";
312
- const omitAppPageSearchParamsFromFirstArg = options.appPageDefaultExport === true;
313
+ const omitAppPageSearchParams = cacheVariant !== "private";
313
314
  const cacheFunctionId = options.serverReferenceId ? JSON.stringify([id, options.serverReferenceId]) : id;
314
315
  const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
315
316
  const cachedFn = (...args) => {
@@ -347,12 +348,19 @@ function registerCachedFunction(fn, id, variant, options = {}) {
347
348
  const keySeed = getUseCacheKeySeed();
348
349
  const captures = options.decryptCaptures ? await options.decryptCaptures(args[0]) : void 0;
349
350
  const hasCaptureEnvelope = captures !== void 0;
350
- const admittedArgs = options.argumentCount === void 0 ? args : hasCaptureEnvelope ? [args[0], ...args.slice(1, 1 + options.argumentCount)] : args.slice(0, options.argumentCount);
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);
351
355
  const executionArgs = hasCaptureEnvelope ? [captures, ...admittedArgs.slice(1)] : admittedArgs;
352
- const callArgs = executionArgs;
356
+ const pagePropsIndex = omitAppPageSearchParams && isPageInvocation ? pagePropsArgIndex : void 0;
357
+ const callArgs = pagePropsIndex === void 0 ? executionArgs : withErroringPageSearchParams(executionArgs, pagePropsIndex);
353
358
  let cacheKey;
354
359
  try {
355
- const processedArgs = executionArgs.length > 0 ? unwrapThenableObjectArray(executionArgs, { omitAppPageSearchParamsFromFirstArg }) : [];
360
+ const processedArgs = executionArgs.length > 0 ? unwrapThenableObjectArray(executionArgs, {
361
+ pagePropsIndex,
362
+ omitMarkedAppPageSearchParams: omitAppPageSearchParams
363
+ }) : [];
356
364
  if (rsc && executionArgs.length > 0) {
357
365
  const tempRefs = rsc.createClientTemporaryReferenceSet();
358
366
  const encoded = await rsc.encodeReply(processedArgs, { temporaryReferences: tempRefs });
@@ -423,7 +431,7 @@ function registerCachedFunction(fn, id, variant, options = {}) {
423
431
  let cacheFunctionInvocation;
424
432
  if (options.serverReferenceId && options.encodeInvocationArgs) try {
425
433
  cacheFunctionInvocation = {
426
- encryptedArgs: await options.encodeInvocationArgs(admittedArgs),
434
+ encryptedArgs: await options.encodeInvocationArgs(pagePropsIndex === void 0 ? admittedArgs : toReplayablePageArgs(admittedArgs, pagePropsIndex)),
427
435
  referenceId: options.serverReferenceId,
428
436
  rootParams: Object.fromEntries(Object.entries(rootParams ?? {}).filter((entry) => entry[1] !== void 0)),
429
437
  softTags
@@ -487,7 +495,7 @@ const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
487
495
  const USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL = Symbol.for("vinext.useCacheAcceptsSecondArgument");
488
496
  /** Whether a loaded server reference is a transformed `"use cache"` function. */
489
497
  function isUseCacheFunction(value) {
490
- return typeof value === "function" && Reflect.get(value, USE_CACHE_FUNCTION_SYMBOL) === true;
498
+ return isUseCacheFunctionReference(value);
491
499
  }
492
500
  function throwPrivateUseCacheInsidePublicUseCacheError() {
493
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\".");
@@ -595,27 +603,79 @@ async function runCachedFunctionWithContext(fn, args, variant, collectResult) {
595
603
  collectedResult
596
604
  };
597
605
  }
598
- function unwrapThenableObjects(value, options = {}) {
606
+ function unwrapThenableObjects(value, options) {
599
607
  if (value === null || value === void 0 || typeof value !== "object") return value;
600
- if (Array.isArray(value)) return value.map((item) => unwrapThenableObjects(item));
601
- if (typeof value.then === "function") {
602
- const keys = Object.keys(value);
603
- if (keys.length > 0) {
604
- const plain = {};
605
- for (const key of keys) plain[key] = unwrapThenableObjects(value[key]);
606
- return plain;
607
- }
608
- 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;
609
614
  }
615
+ if (typeof value.then === "function") return value;
610
616
  const result = {};
611
617
  for (const key of Object.keys(value)) {
612
- if (key === "searchParams" && (options.omitAppPageSearchParamsAtRoot || isMarkedAppPagePropsObject(value))) continue;
613
- result[key] = unwrapThenableObjects(value[key]);
618
+ if (key === "searchParams" && (options.omitAppPageSearchParamsAtRoot || options.omitMarkedAppPageSearchParams && isMarkedAppPagePropsObject(value))) continue;
619
+ result[key] = unwrapThenableObjects(value[key], childOptions);
614
620
  }
615
621
  return result;
616
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
+ }
617
674
  function unwrapThenableObjectArray(values, options) {
618
- return values.map((value, index) => unwrapThenableObjects(value, { omitAppPageSearchParamsAtRoot: index === 0 && options.omitAppPageSearchParamsFromFirstArg }));
675
+ return values.map((value, index) => unwrapThenableObjects(value, {
676
+ omitAppPageSearchParamsAtRoot: index === options.pagePropsIndex,
677
+ omitMarkedAppPageSearchParams: options.omitMarkedAppPageSearchParams
678
+ }));
619
679
  }
620
680
  function stableStringify(value, seen) {
621
681
  if (value === void 0) return "undefined";
@@ -642,4 +702,4 @@ function stableStringify(value, seen) {
642
702
  return JSON.stringify(value);
643
703
  }
644
704
  //#endregion
645
- export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isUseCacheFunction, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
705
+ export { NestedDynamicUseCacheError, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, isThenableObject, isUseCacheFunction, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
@@ -1,5 +1,5 @@
1
- import { fnv1a64 } from "../utils/hash.js";
2
1
  import { escapeCSSString, formatFontClassRule, getFontMimeType, resolveSingleFaceStyle, sanitizeCSSVarName, sanitizeFallback, sanitizeFontDescriptorValue } from "./font-utils.js";
2
+ import { fnv1a64 } from "../utils/hash.js";
3
3
  //#region src/shims/font-local.ts
4
4
  /**
5
5
  * next/font/local shim
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { isBotUserAgent } from "../utils/html-limited-bots.js";
2
3
  import { VINEXT_MOUNTED_SLOTS_HEADER } from "../server/app-rsc-vary.js";
3
4
  import "../server/headers.js";
4
5
  import { assertSafeNavigationUrl } from "./url-safety.js";
@@ -6,7 +7,6 @@ import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "../server/app-rsc-re
6
7
  import { AppElementsWire } from "../server/app-elements-wire.js";
7
8
  import "../server/app-elements.js";
8
9
  import { withBasePath } from "./url-utils.js";
9
- import { isBotUserAgent } from "../utils/html-limited-bots.js";
10
10
  import { createRscRequestHeaders, createRscRequestUrl } from "../server/app-rsc-cache-busting.js";
11
11
  import { hasAppNavigationRuntime } from "../client/navigation-runtime.js";
12
12
  import { getMountedSlotsHeader, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, navigateClientSide, prefetchRscResponse } from "./navigation.js";
@@ -1,9 +1,9 @@
1
1
  import { getOrCreateAls } from "./internal/als-registry.js";
2
2
  import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
3
- import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
4
3
  import { MIDDLEWARE_SET_COOKIE_HEADER } from "../utils/protocol-headers.js";
5
- import { FLIGHT_HEADERS, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER } from "../server/headers.js";
6
4
  import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
5
+ import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
6
+ import { FLIGHT_HEADERS, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER } from "../server/headers.js";
7
7
  import { serializeSetCookie, validateCookieName } from "./internal/cookie-serialize.js";
8
8
  import { createPprFallbackShellSuspensePromise } from "./ppr-fallback-shell.js";
9
9
  //#region src/shims/headers.ts
@@ -1,4 +1,33 @@
1
1
  //#region src/shims/internal/app-page-props-cache-key.d.ts
2
+ /**
3
+ * Enumerable page marker, matching Next.js's `$$isPage` prop. It must be an
4
+ * ordinary string key: React's createElement drops symbol and non-enumerable
5
+ * props before a server component is invoked.
6
+ */
7
+ export declare const APP_PAGE_USE_CACHE_MARKER = "$$isPage";
2
8
  export declare function markAppPagePropsForUseCache<T extends object>(props: T): T;
3
9
  export declare function isMarkedAppPagePropsObject(value: object): boolean;
10
+ /**
11
+ * Whether `fn` is a transformed `"use cache"` function, including a bound
12
+ * one. Like Next.js's `isUseCacheFunction`, this survives `.bind()`: React's
13
+ * server-reference `bind` copies `$$typeof`/`$$id` to the bound function but
14
+ * not vinext's own marker symbol.
15
+ */
16
+ export declare function isUseCacheFunctionReference(fn: unknown): boolean;
17
+ /**
18
+ * Add Next.js's `$$isPage` marker when `fn` is a `"use cache"` function
19
+ * invoked as a page component or as a page's generateMetadata/generateViewport
20
+ * (create-component-tree.tsx, resolve-metadata.ts `createSegmentProps`). The
21
+ * cache wrapper reads and removes it, so page semantics follow the invocation
22
+ * even when the cached function is defined in (or re-exported from) another
23
+ * module, or bound.
24
+ */
25
+ export declare function withUseCachePageMarker<T extends Record<string, unknown>>(fn: unknown, props: T): T;
26
+ /**
27
+ * Whether `value` is page props carrying the `$$isPage` marker. Only plain
28
+ * objects qualify: the framework always passes a plain props object, and
29
+ * reading the marker through a thenable params/searchParams proxy would be
30
+ * observed as a param access.
31
+ */
32
+ export declare function hasUseCachePageMarker(value: unknown): value is Record<string, unknown>;
4
33
  //#endregion
@@ -1,5 +1,20 @@
1
1
  //#region src/shims/internal/app-page-props-cache-key.ts
2
2
  const APP_PAGE_PROPS_CACHE_KEY_MARKER = Symbol.for("vinext.appPagePropsCacheKeyMarker");
3
+ const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
4
+ const SERVER_REFERENCE_TAG = Symbol.for("react.server.reference");
5
+ /**
6
+ * Server reference ids of transformed cache functions end in the export name
7
+ * the use-cache transform assigns (`secureExportName` in
8
+ * plugins/use-cache-callable.ts): `$$vinext_cache_` plus an HMAC-SHA256 hex
9
+ * digest. `"use server"` actions keep their own export names.
10
+ */
11
+ const USE_CACHE_SERVER_REFERENCE_ID_RE = /#\$\$vinext_cache_[0-9a-f]{64}$/;
12
+ /**
13
+ * Enumerable page marker, matching Next.js's `$$isPage` prop. It must be an
14
+ * ordinary string key: React's createElement drops symbol and non-enumerable
15
+ * props before a server component is invoked.
16
+ */
17
+ const APP_PAGE_USE_CACHE_MARKER = "$$isPage";
3
18
  function markAppPagePropsForUseCache(props) {
4
19
  Object.defineProperty(props, APP_PAGE_PROPS_CACHE_KEY_MARKER, {
5
20
  configurable: false,
@@ -12,5 +27,42 @@ function markAppPagePropsForUseCache(props) {
12
27
  function isMarkedAppPagePropsObject(value) {
13
28
  return Reflect.get(value, APP_PAGE_PROPS_CACHE_KEY_MARKER) === true;
14
29
  }
30
+ /**
31
+ * Whether `fn` is a transformed `"use cache"` function, including a bound
32
+ * one. Like Next.js's `isUseCacheFunction`, this survives `.bind()`: React's
33
+ * server-reference `bind` copies `$$typeof`/`$$id` to the bound function but
34
+ * not vinext's own marker symbol.
35
+ */
36
+ function isUseCacheFunctionReference(fn) {
37
+ if (typeof fn !== "function") return false;
38
+ if (Reflect.get(fn, USE_CACHE_FUNCTION_SYMBOL) === true) return true;
39
+ const reference = fn;
40
+ return reference.$$typeof === SERVER_REFERENCE_TAG && typeof reference.$$id === "string" && USE_CACHE_SERVER_REFERENCE_ID_RE.test(reference.$$id);
41
+ }
42
+ /**
43
+ * Add Next.js's `$$isPage` marker when `fn` is a `"use cache"` function
44
+ * invoked as a page component or as a page's generateMetadata/generateViewport
45
+ * (create-component-tree.tsx, resolve-metadata.ts `createSegmentProps`). The
46
+ * cache wrapper reads and removes it, so page semantics follow the invocation
47
+ * even when the cached function is defined in (or re-exported from) another
48
+ * module, or bound.
49
+ */
50
+ function withUseCachePageMarker(fn, props) {
51
+ return isUseCacheFunctionReference(fn) ? {
52
+ ...props,
53
+ [APP_PAGE_USE_CACHE_MARKER]: true
54
+ } : props;
55
+ }
56
+ /**
57
+ * Whether `value` is page props carrying the `$$isPage` marker. Only plain
58
+ * objects qualify: the framework always passes a plain props object, and
59
+ * reading the marker through a thenable params/searchParams proxy would be
60
+ * observed as a param access.
61
+ */
62
+ function hasUseCachePageMarker(value) {
63
+ if (value === null || typeof value !== "object") return false;
64
+ const prototype = Object.getPrototypeOf(value);
65
+ return (prototype === Object.prototype || prototype === null) && value["$$isPage"] === true;
66
+ }
15
67
  //#endregion
16
- export { isMarkedAppPagePropsObject, markAppPagePropsForUseCache };
68
+ export { APP_PAGE_USE_CACHE_MARKER, hasUseCachePageMarker, isMarkedAppPagePropsObject, isUseCacheFunctionReference, markAppPagePropsForUseCache, withUseCachePageMarker };