vinext 1.0.0-beta.1 → 1.0.0-beta.3

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 (234) hide show
  1. package/README.md +10 -10
  2. package/dist/build/client-build-config.js +8 -1
  3. package/dist/build/report.d.ts +8 -1
  4. package/dist/build/report.js +12 -2
  5. package/dist/check.js +19 -2
  6. package/dist/cli.js +3 -2
  7. package/dist/config/config-matchers.d.ts +13 -37
  8. package/dist/config/config-matchers.js +35 -122
  9. package/dist/config/next-config.d.ts +15 -5
  10. package/dist/config/next-config.js +7 -1
  11. package/dist/config/request-context.d.ts +14 -0
  12. package/dist/config/request-context.js +26 -0
  13. package/dist/entries/app-browser-entry.d.ts +4 -10
  14. package/dist/entries/app-browser-entry.js +20 -4
  15. package/dist/entries/app-rsc-entry.js +30 -9
  16. package/dist/entries/app-rsc-manifest.js +36 -0
  17. package/dist/entries/pages-client-entry.js +0 -1
  18. package/dist/entries/pages-server-entry.js +13 -5
  19. package/dist/index.js +194 -101
  20. package/dist/init-cloudflare.d.ts +3 -1
  21. package/dist/init-cloudflare.js +59 -5
  22. package/dist/init.d.ts +6 -4
  23. package/dist/init.js +20 -22
  24. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  25. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  26. package/dist/plugins/import-meta-url.js +17 -6
  27. package/dist/plugins/og-assets.js +1 -1
  28. package/dist/plugins/require-context.js +20 -15
  29. package/dist/plugins/transform-cache.d.ts +19 -0
  30. package/dist/plugins/transform-cache.js +36 -0
  31. package/dist/routing/app-route-graph.d.ts +27 -11
  32. package/dist/routing/app-route-graph.js +158 -22
  33. package/dist/routing/app-router.js +12 -6
  34. package/dist/routing/file-matcher.d.ts +11 -22
  35. package/dist/routing/file-matcher.js +21 -33
  36. package/dist/routing/pages-router.js +23 -29
  37. package/dist/routing/route-matching.d.ts +14 -1
  38. package/dist/routing/route-matching.js +13 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +7 -4
  41. package/dist/routing/route-trie.d.ts +5 -1
  42. package/dist/routing/route-trie.js +5 -2
  43. package/dist/server/api-handler.d.ts +2 -0
  44. package/dist/server/api-handler.js +3 -3
  45. package/dist/server/app-browser-entry.js +110 -37
  46. package/dist/server/app-browser-history-controller.d.ts +1 -1
  47. package/dist/server/app-browser-history-controller.js +3 -3
  48. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  49. package/dist/server/app-browser-navigation-controller.js +2 -2
  50. package/dist/server/app-browser-state.js +1 -1
  51. package/dist/server/app-browser-visible-commit.js +1 -1
  52. package/dist/server/app-fallback-renderer.d.ts +3 -0
  53. package/dist/server/app-fallback-renderer.js +4 -2
  54. package/dist/server/app-middleware.js +2 -1
  55. package/dist/server/app-page-boundary-render.d.ts +12 -1
  56. package/dist/server/app-page-boundary-render.js +84 -2
  57. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  58. package/dist/server/app-page-cache-finalizer.js +1 -1
  59. package/dist/server/app-page-cache.d.ts +2 -2
  60. package/dist/server/app-page-cache.js +16 -2
  61. package/dist/server/app-page-dispatch.d.ts +19 -2
  62. package/dist/server/app-page-dispatch.js +45 -23
  63. package/dist/server/app-page-element-builder.d.ts +9 -2
  64. package/dist/server/app-page-element-builder.js +144 -33
  65. package/dist/server/app-page-head.d.ts +56 -4
  66. package/dist/server/app-page-head.js +216 -85
  67. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  68. package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
  69. package/dist/server/app-page-probe.d.ts +4 -0
  70. package/dist/server/app-page-probe.js +6 -2
  71. package/dist/server/app-page-render.d.ts +2 -2
  72. package/dist/server/app-page-render.js +1 -1
  73. package/dist/server/app-page-request.d.ts +15 -0
  74. package/dist/server/app-page-request.js +134 -14
  75. package/dist/server/app-page-response.js +1 -1
  76. package/dist/server/app-page-route-wiring.d.ts +16 -0
  77. package/dist/server/app-page-route-wiring.js +254 -52
  78. package/dist/server/app-pages-bridge.d.ts +1 -1
  79. package/dist/server/app-pages-bridge.js +2 -1
  80. package/dist/server/app-post-middleware-context.d.ts +1 -1
  81. package/dist/server/app-post-middleware-context.js +1 -1
  82. package/dist/server/app-route-handler-cache.js +4 -0
  83. package/dist/server/app-route-handler-dispatch.js +40 -20
  84. package/dist/server/app-route-handler-execution.d.ts +6 -1
  85. package/dist/server/app-route-handler-execution.js +42 -16
  86. package/dist/server/app-route-handler-policy.d.ts +2 -0
  87. package/dist/server/app-route-handler-policy.js +3 -3
  88. package/dist/server/app-route-handler-response.js +1 -1
  89. package/dist/server/app-route-module-loader.d.ts +9 -1
  90. package/dist/server/app-route-module-loader.js +4 -0
  91. package/dist/server/app-router-entry.js +6 -3
  92. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  93. package/dist/server/app-rsc-errors.d.ts +1 -1
  94. package/dist/server/app-rsc-errors.js +22 -2
  95. package/dist/server/app-rsc-handler.d.ts +10 -5
  96. package/dist/server/app-rsc-handler.js +73 -33
  97. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  98. package/dist/server/app-rsc-request-normalization.js +8 -2
  99. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  100. package/dist/server/app-rsc-response-finalizer.js +5 -11
  101. package/dist/server/app-rsc-route-matching.d.ts +29 -0
  102. package/dist/server/app-rsc-route-matching.js +93 -11
  103. package/dist/server/app-segment-config.js +13 -3
  104. package/dist/server/app-server-action-execution.d.ts +3 -1
  105. package/dist/server/app-server-action-execution.js +9 -7
  106. package/dist/server/app-ssr-entry.js +6 -6
  107. package/dist/server/app-ssr-stream.d.ts +1 -7
  108. package/dist/server/app-ssr-stream.js +2 -10
  109. package/dist/server/cache-control.d.ts +2 -2
  110. package/dist/server/cache-control.js +2 -1
  111. package/dist/server/config-headers.d.ts +24 -0
  112. package/dist/server/config-headers.js +52 -0
  113. package/dist/server/dev-initial-server-error.d.ts +1 -1
  114. package/dist/server/dev-server.d.ts +3 -1
  115. package/dist/server/dev-server.js +170 -321
  116. package/dist/server/headers.d.ts +2 -2
  117. package/dist/server/headers.js +4 -3
  118. package/dist/server/isr-cache.d.ts +11 -34
  119. package/dist/server/isr-cache.js +33 -43
  120. package/dist/server/isr-decision.d.ts +2 -2
  121. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  122. package/dist/server/middleware-matcher-pattern.js +219 -0
  123. package/dist/server/middleware-matcher.d.ts +2 -7
  124. package/dist/server/middleware-matcher.js +13 -60
  125. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  126. package/dist/server/middleware-path-to-regexp.js +228 -0
  127. package/dist/server/middleware-runtime.js +4 -3
  128. package/dist/server/middleware.d.ts +1 -1
  129. package/dist/server/middleware.js +2 -1
  130. package/dist/server/pages-api-route.d.ts +2 -0
  131. package/dist/server/pages-api-route.js +4 -1
  132. package/dist/server/pages-data-route.d.ts +11 -1
  133. package/dist/server/pages-data-route.js +16 -1
  134. package/dist/server/pages-dev-hydration.js +0 -1
  135. package/dist/server/pages-get-initial-props.d.ts +16 -3
  136. package/dist/server/pages-get-initial-props.js +17 -10
  137. package/dist/server/pages-i18n.js +64 -16
  138. package/dist/server/pages-node-compat.d.ts +2 -0
  139. package/dist/server/pages-node-compat.js +7 -3
  140. package/dist/server/pages-page-data.d.ts +64 -10
  141. package/dist/server/pages-page-data.js +349 -80
  142. package/dist/server/pages-page-handler.d.ts +9 -3
  143. package/dist/server/pages-page-handler.js +131 -36
  144. package/dist/server/pages-page-response.d.ts +5 -3
  145. package/dist/server/pages-page-response.js +24 -27
  146. package/dist/server/pages-readiness.d.ts +3 -3
  147. package/dist/server/pages-request-pipeline.d.ts +8 -0
  148. package/dist/server/pages-request-pipeline.js +30 -12
  149. package/dist/server/pages-revalidate.d.ts +1 -1
  150. package/dist/server/pages-revalidate.js +54 -8
  151. package/dist/server/pages-router-entry.d.ts +1 -0
  152. package/dist/server/pages-router-entry.js +16 -4
  153. package/dist/server/prerender-route-params.js +2 -2
  154. package/dist/server/prod-server.d.ts +3 -5
  155. package/dist/server/prod-server.js +72 -35
  156. package/dist/server/request-pipeline.d.ts +15 -29
  157. package/dist/server/request-pipeline.js +24 -59
  158. package/dist/server/revalidation-host.d.ts +11 -0
  159. package/dist/server/revalidation-host.js +19 -0
  160. package/dist/server/rsc-stream-hints.js +122 -18
  161. package/dist/server/worker-revalidation-context.d.ts +13 -0
  162. package/dist/server/worker-revalidation-context.js +29 -0
  163. package/dist/shims/app.d.ts +1 -1
  164. package/dist/shims/cache-handler.d.ts +1 -1
  165. package/dist/shims/cache-handler.js +10 -7
  166. package/dist/shims/cache-request-state.d.ts +27 -1
  167. package/dist/shims/cache-request-state.js +60 -1
  168. package/dist/shims/cache-runtime.d.ts +18 -1
  169. package/dist/shims/cache-runtime.js +26 -8
  170. package/dist/shims/cache.d.ts +5 -5
  171. package/dist/shims/cache.js +27 -11
  172. package/dist/shims/document.d.ts +42 -83
  173. package/dist/shims/document.js +62 -53
  174. package/dist/shims/dynamic.d.ts +5 -25
  175. package/dist/shims/dynamic.js +29 -8
  176. package/dist/shims/error.d.ts +1 -1
  177. package/dist/shims/error.js +2 -2
  178. package/dist/shims/fetch-cache.js +13 -4
  179. package/dist/shims/font-google-base.d.ts +11 -4
  180. package/dist/shims/font-google-base.js +17 -8
  181. package/dist/shims/font-local.d.ts +10 -3
  182. package/dist/shims/font-local.js +41 -10
  183. package/dist/shims/head.d.ts +13 -2
  184. package/dist/shims/head.js +3 -3
  185. package/dist/shims/headers.d.ts +37 -43
  186. package/dist/shims/headers.js +183 -74
  187. package/dist/shims/image.d.ts +27 -37
  188. package/dist/shims/image.js +21 -14
  189. package/dist/shims/internal/cookie-serialize.d.ts +12 -9
  190. package/dist/shims/internal/cookie-serialize.js +10 -7
  191. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  192. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  193. package/dist/shims/internal/interpolate-as.js +27 -2
  194. package/dist/shims/internal/utils.d.ts +3 -3
  195. package/dist/shims/legacy-image.d.ts +3 -37
  196. package/dist/shims/legacy-image.js +6 -16
  197. package/dist/shims/link.d.ts +15 -22
  198. package/dist/shims/link.js +34 -13
  199. package/dist/shims/metadata.d.ts +7 -17
  200. package/dist/shims/metadata.js +74 -24
  201. package/dist/shims/navigation-context-state.d.ts +1 -1
  202. package/dist/shims/navigation.d.ts +7 -3
  203. package/dist/shims/navigation.js +25 -14
  204. package/dist/shims/navigation.react-server.js +1 -1
  205. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  206. package/dist/shims/next-shims-public.d.ts +1 -0
  207. package/dist/shims/public-shim-map.json.js +103 -0
  208. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  209. package/dist/shims/readonly-url-search-params.js +3 -3
  210. package/dist/shims/request-context.d.ts +4 -1
  211. package/dist/shims/request-state-types.d.ts +1 -1
  212. package/dist/shims/router.d.ts +55 -21
  213. package/dist/shims/router.js +180 -44
  214. package/dist/shims/script.d.ts +6 -10
  215. package/dist/shims/script.js +7 -4
  216. package/dist/shims/server.d.ts +50 -26
  217. package/dist/shims/server.js +193 -55
  218. package/dist/shims/unified-request-context.d.ts +22 -3
  219. package/dist/shims/unified-request-context.js +84 -1
  220. package/dist/shims/url-safety.d.ts +1 -1
  221. package/dist/shims/url-safety.js +2 -2
  222. package/dist/typegen.d.ts +8 -2
  223. package/dist/typegen.js +76 -15
  224. package/dist/utils/cache-control-metadata.d.ts +2 -1
  225. package/dist/utils/cache-control-metadata.js +5 -1
  226. package/dist/utils/domain-locale.d.ts +2 -2
  227. package/dist/utils/external-url.d.ts +5 -0
  228. package/dist/utils/external-url.js +7 -0
  229. package/dist/utils/html-limited-bots.js +1 -1
  230. package/dist/utils/protocol-headers.d.ts +7 -1
  231. package/dist/utils/protocol-headers.js +7 -1
  232. package/dist/utils/regex-safety.d.ts +8 -0
  233. package/dist/utils/regex-safety.js +737 -0
  234. package/package.json +13 -2
@@ -1,10 +1,21 @@
1
- import { NextHeader } from "../config/next-config.js";
2
- import { BasePathMatchState, RequestContext } from "../config/config-matchers.js";
3
1
  import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS } from "./headers.js";
4
- import { isOpenRedirectShaped } from "./open-redirect.js";
5
2
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
3
+ import { isOpenRedirectShaped } from "./open-redirect.js";
6
4
 
7
5
  //#region src/server/request-pipeline.d.ts
6
+ /**
7
+ * Apply the URL Standard's pathname canonicalization without decoding and
8
+ * re-encoding ordinary percent escapes.
9
+ *
10
+ * In particular, WHATWG URLs remove literal and percent-encoded dot segments
11
+ * (`/%2e/about` becomes `/about`) while preserving unrelated spellings such
12
+ * as `/%61bout`, `%2F`, `%5C`, and `%252F` byte-for-byte. Node request adapters
13
+ * must do this before comparing raw route/config/basePath identity so those
14
+ * comparisons agree with the `Request` that userland eventually receives.
15
+ */
16
+ declare function canonicalizeRequestPathname(pathname: string): string;
17
+ /** Canonicalize only the pathname portion while preserving the raw query. */
18
+ declare function canonicalizeRequestUrlPathname(url: string): string;
8
19
  /**
9
20
  * Shared request pipeline utilities.
10
21
  *
@@ -44,18 +55,6 @@ import { hasBasePath, stripBasePath } from "../utils/base-path.js";
44
55
  */
45
56
  declare function guardProtocolRelativeUrl(rawPathname: string): Response | null;
46
57
  type HeaderRecord = Record<string, string | string[]>;
47
- type ApplyConfigHeadersOptions = {
48
- configHeaders: NextHeader[];
49
- pathname: string;
50
- requestContext: RequestContext;
51
- /**
52
- * basePath gating state. When omitted, every rule is treated as a default
53
- * (basePath: true) rule for backward compatibility — callers that need to
54
- * support `basePath: false` headers must pass this in.
55
- */
56
- basePathState?: BasePathMatchState; /** Existing framework-generated headers that matching config rules may replace. */
57
- overwriteExisting?: ReadonlySet<string>;
58
- };
59
58
  type StaticFileSignalContext = {
60
59
  headers: Headers | null;
61
60
  status: number | null;
@@ -67,19 +66,6 @@ type ResolvePublicFileRouteOptions = {
67
66
  publicFiles: ReadonlySet<string>;
68
67
  request: Request;
69
68
  };
70
- /**
71
- * Apply matched next.config.js headers to a Web Headers object.
72
- *
73
- * Next.js evaluates config header match conditions against the original
74
- * request snapshot. Middleware response headers still win for the same
75
- * response key, while multi-value headers are additive.
76
- */
77
- declare function applyConfigHeadersToResponse(responseHeaders: Headers, options: ApplyConfigHeadersOptions): void;
78
- /**
79
- * Apply matched next.config.js headers to the early response header record used
80
- * by Node and Worker Pages Router pipelines before a concrete response exists.
81
- */
82
- declare function applyConfigHeadersToHeaderRecord(headers: HeaderRecord, options: ApplyConfigHeadersOptions): void;
83
69
  declare function createStaticFileSignal(pathname: string, context: StaticFileSignalContext): Response;
84
70
  /**
85
71
  * Resolve the public/ filesystem-route slot in the Next.js routing order.
@@ -184,4 +170,4 @@ declare function cloneRequestWithHeaders(request: Request, headers: Headers): Re
184
170
  */
185
171
  declare function cloneRequestWithUrl(request: Request, url: string): Request;
186
172
  //#endregion
187
- export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
173
+ export { HeaderRecord, INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
@@ -1,10 +1,32 @@
1
1
  import { hasBasePath, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
2
2
  import "../utils/protocol-headers.js";
3
3
  import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, VINEXT_STATIC_FILE_HEADER } from "./headers.js";
4
- import { matchHeaders } from "../config/config-matchers.js";
5
4
  import { forbiddenResponse, notFoundResponse } from "./http-error-responses.js";
6
5
  import { isOpenRedirectShaped } from "./open-redirect.js";
7
6
  //#region src/server/request-pipeline.ts
7
+ const PATHNAME_CANONICALIZATION_BASE = new URL("http://vinext.invalid/");
8
+ /**
9
+ * Apply the URL Standard's pathname canonicalization without decoding and
10
+ * re-encoding ordinary percent escapes.
11
+ *
12
+ * In particular, WHATWG URLs remove literal and percent-encoded dot segments
13
+ * (`/%2e/about` becomes `/about`) while preserving unrelated spellings such
14
+ * as `/%61bout`, `%2F`, `%5C`, and `%252F` byte-for-byte. Node request adapters
15
+ * must do this before comparing raw route/config/basePath identity so those
16
+ * comparisons agree with the `Request` that userland eventually receives.
17
+ */
18
+ function canonicalizeRequestPathname(pathname) {
19
+ const url = new URL(PATHNAME_CANONICALIZATION_BASE);
20
+ url.pathname = pathname;
21
+ return url.pathname;
22
+ }
23
+ /** Canonicalize only the pathname portion while preserving the raw query. */
24
+ function canonicalizeRequestUrlPathname(url) {
25
+ const queryIndex = url.indexOf("?");
26
+ const pathname = queryIndex === -1 ? url : url.slice(0, queryIndex);
27
+ const search = queryIndex === -1 ? "" : url.slice(queryIndex);
28
+ return canonicalizeRequestPathname(pathname) + search;
29
+ }
8
30
  /**
9
31
  * Shared request pipeline utilities.
10
32
  *
@@ -50,63 +72,6 @@ const FILE_LIKE_PATHNAME_RE = /\.[^/]+\/?$/;
50
72
  function isWellKnownPathname(pathname) {
51
73
  return pathname === "/.well-known" || pathname.startsWith("/.well-known/");
52
74
  }
53
- function findHeaderRecordKey(headers, lowerName) {
54
- for (const key of Object.keys(headers)) if (key.toLowerCase() === lowerName) return key;
55
- }
56
- function appendHeaderRecord(headers, lowerName, value) {
57
- const key = findHeaderRecordKey(headers, lowerName) ?? lowerName;
58
- const existing = headers[key];
59
- if (existing === void 0) {
60
- headers[key] = value;
61
- return;
62
- }
63
- if (Array.isArray(existing)) {
64
- existing.push(value);
65
- return;
66
- }
67
- headers[key] = [existing, value];
68
- }
69
- function appendVaryHeaderRecord(headers, value) {
70
- const key = findHeaderRecordKey(headers, "vary") ?? "vary";
71
- const existing = headers[key];
72
- if (existing === void 0) {
73
- headers[key] = value;
74
- return;
75
- }
76
- if (Array.isArray(existing)) {
77
- existing.push(value);
78
- return;
79
- }
80
- headers[key] = existing + ", " + value;
81
- }
82
- /**
83
- * Apply matched next.config.js headers to a Web Headers object.
84
- *
85
- * Next.js evaluates config header match conditions against the original
86
- * request snapshot. Middleware response headers still win for the same
87
- * response key, while multi-value headers are additive.
88
- */
89
- function applyConfigHeadersToResponse(responseHeaders, options) {
90
- const matched = matchHeaders(options.pathname, options.configHeaders, options.requestContext, options.basePathState);
91
- for (const header of matched) {
92
- const lowerName = header.key.toLowerCase();
93
- if (lowerName === "vary" || lowerName === "set-cookie") responseHeaders.append(header.key, header.value);
94
- else if (options.overwriteExisting?.has(lowerName) || !responseHeaders.has(lowerName)) responseHeaders.set(header.key, header.value);
95
- }
96
- }
97
- /**
98
- * Apply matched next.config.js headers to the early response header record used
99
- * by Node and Worker Pages Router pipelines before a concrete response exists.
100
- */
101
- function applyConfigHeadersToHeaderRecord(headers, options) {
102
- const matched = matchHeaders(options.pathname, options.configHeaders, options.requestContext, options.basePathState);
103
- for (const header of matched) {
104
- const lowerName = header.key.toLowerCase();
105
- if (lowerName === "set-cookie") appendHeaderRecord(headers, lowerName, header.value);
106
- else if (lowerName === "vary") appendVaryHeaderRecord(headers, header.value);
107
- else if (findHeaderRecordKey(headers, lowerName) === void 0) headers[lowerName] = header.value;
108
- }
109
- }
110
75
  function createStaticFileSignal(pathname, context) {
111
76
  const headers = new Headers({ [VINEXT_STATIC_FILE_HEADER]: encodeURIComponent(pathname) });
112
77
  if (context.headers) for (const [key, value] of context.headers) headers.append(key, value);
@@ -445,4 +410,4 @@ function cloneRequestWithUrl(request, url) {
445
410
  return cloned;
446
411
  }
447
412
  //#endregion
448
- export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, applyConfigHeadersToHeaderRecord, applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
413
+ export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, filterInternalHeaders, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
@@ -0,0 +1,11 @@
1
+ import { NextI18nConfig } from "../config/next-config.js";
2
+
3
+ //#region src/server/revalidation-host.d.ts
4
+ /**
5
+ * Read the logical request hostname carried by a server-pinned revalidation
6
+ * loopback. The side channel is accepted only as part of the authenticated
7
+ * revalidation protocol and only for an exact configured i18n domain.
8
+ */
9
+ declare function readTrustedRevalidationHostname(headers: Headers, i18nConfig: NextI18nConfig | null | undefined, authorizeRevalidation?: (headerValue: string | null) => boolean): string | null;
10
+ //#endregion
11
+ export { readTrustedRevalidationHostname };
@@ -0,0 +1,19 @@
1
+ import { VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
2
+ import { isOnDemandRevalidateRequest } from "./isr-cache.js";
3
+ import { normalizeDomainHostname } from "../utils/domain-locale.js";
4
+ //#region src/server/revalidation-host.ts
5
+ /**
6
+ * Read the logical request hostname carried by a server-pinned revalidation
7
+ * loopback. The side channel is accepted only as part of the authenticated
8
+ * revalidation protocol and only for an exact configured i18n domain.
9
+ */
10
+ function readTrustedRevalidationHostname(headers, i18nConfig, authorizeRevalidation = isOnDemandRevalidateRequest) {
11
+ if (!i18nConfig?.domains?.length || !authorizeRevalidation(headers.get("x-prerender-revalidate"))) return null;
12
+ const rawHostname = headers.get(VINEXT_REVALIDATE_HOST_HEADER);
13
+ if (!rawHostname) return null;
14
+ const hostname = rawHostname.trim().toLowerCase();
15
+ if (normalizeDomainHostname(hostname) !== hostname) return null;
16
+ return i18nConfig.domains.find((item) => normalizeDomainHostname(item.domain) === hostname)?.domain.toLowerCase() ?? null;
17
+ }
18
+ //#endregion
19
+ export { readTrustedRevalidationHostname };
@@ -1,31 +1,135 @@
1
1
  //#region src/server/rsc-stream-hints.ts
2
- const REACT_FLIGHT_STYLESHEET_PRELOAD_HINT = /(\d*:HL\[.*?),"stylesheet"(\]|,)/g;
3
- /**
4
- * React Flight emits HL hints with "stylesheet" for CSS preloads, but the
5
- * HTML spec requires "style" for <link rel="preload">. Rewrite each complete
6
- * Flight line so SSR embeds, navigation, and server actions see valid hints.
7
- */
2
+ const REACT_FLIGHT_STYLESHEET_PRELOAD_HINT = /^([0-9a-f]*:HL\[.*?),"stylesheet"(\]|,)/;
3
+ const STYLESHEET_TO_STYLE_JSON_PADDING = " ".repeat(5);
4
+ const LENGTH_PREFIXED_ROW_TAGS = /* @__PURE__ */ new Set([
5
+ "T",
6
+ "A",
7
+ "O",
8
+ "o",
9
+ "b",
10
+ "U",
11
+ "S",
12
+ "s",
13
+ "L",
14
+ "l",
15
+ "G",
16
+ "g",
17
+ "M",
18
+ "m",
19
+ "V"
20
+ ]);
21
+ const NEWLINE_PREFIXED_ROW_TAGS = /* @__PURE__ */ new Set([
22
+ "I",
23
+ "H",
24
+ "E",
25
+ "N",
26
+ "D",
27
+ "J",
28
+ "W",
29
+ "R",
30
+ "r",
31
+ "X",
32
+ "x",
33
+ "C",
34
+ "P",
35
+ "#"
36
+ ]);
37
+ const decoder = new TextDecoder();
38
+ const encoder = new TextEncoder();
39
+ /** Rewrite only a complete React Flight stylesheet hint row. */
8
40
  function normalizeReactFlightHintLine(line) {
9
- return line.replace(REACT_FLIGHT_STYLESHEET_PRELOAD_HINT, "$1,\"style\"$2");
41
+ const text = decoder.decode(line);
42
+ const normalized = text.replace(REACT_FLIGHT_STYLESHEET_PRELOAD_HINT, `$1,"style"${STYLESHEET_TO_STYLE_JSON_PADDING}$2`);
43
+ if (normalized === text) return line;
44
+ const normalizedBytes = encoder.encode(normalized);
45
+ return normalizedBytes.byteLength === line.byteLength ? normalizedBytes : line;
46
+ }
47
+ function concatBytes(first, second) {
48
+ if (first.byteLength === 0) return second;
49
+ const combined = new Uint8Array(first.byteLength + second.byteLength);
50
+ combined.set(first);
51
+ combined.set(second, first.byteLength);
52
+ return combined;
53
+ }
54
+ function indexOfByte(bytes, byte, from = 0) {
55
+ for (let index = from; index < bytes.byteLength; index++) if (bytes[index] === byte) return index;
56
+ return -1;
57
+ }
58
+ function parseHexBytes(bytes, start, end) {
59
+ if (start === end) return null;
60
+ let value = 0;
61
+ for (let index = start; index < end; index++) {
62
+ const byte = bytes[index];
63
+ const digit = byte >= 48 && byte <= 57 ? byte - 48 : byte >= 97 && byte <= 102 ? byte - 87 : -1;
64
+ if (digit === -1) return null;
65
+ value = value * 16 + digit;
66
+ if (!Number.isSafeInteger(value)) return null;
67
+ }
68
+ return value;
69
+ }
70
+ function isUntaggedJsonRowStart(byte) {
71
+ return byte === 34 || byte === 45 || byte >= 48 && byte <= 57 || byte === 91 || byte === 102 || byte === 110 || byte === 116 || byte === 123;
10
72
  }
11
73
  function normalizeReactFlightPreloadHints(stream) {
12
- const decoder = new TextDecoder();
13
- const encoder = new TextEncoder();
14
- let carry = "";
74
+ let carry = /* @__PURE__ */ new Uint8Array();
75
+ let rawBytesRemaining = 0;
76
+ let passThrough = false;
15
77
  return stream.pipeThrough(new TransformStream({
16
78
  transform(chunk, controller) {
17
- const text = carry + decoder.decode(chunk, { stream: true });
18
- const lastNewline = text.lastIndexOf("\n");
19
- if (lastNewline === -1) {
20
- carry = text;
79
+ if (passThrough) {
80
+ controller.enqueue(chunk);
21
81
  return;
22
82
  }
23
- carry = text.slice(lastNewline + 1);
24
- controller.enqueue(encoder.encode(normalizeReactFlightHintLine(text.slice(0, lastNewline + 1))));
83
+ let bytes = concatBytes(carry, chunk);
84
+ carry = /* @__PURE__ */ new Uint8Array();
85
+ while (bytes.byteLength > 0) {
86
+ if (rawBytesRemaining > 0) {
87
+ const length = Math.min(rawBytesRemaining, bytes.byteLength);
88
+ controller.enqueue(bytes.slice(0, length));
89
+ rawBytesRemaining -= length;
90
+ bytes = bytes.subarray(length);
91
+ continue;
92
+ }
93
+ const colon = indexOfByte(bytes, 58);
94
+ if (colon === -1 || colon + 1 === bytes.byteLength) {
95
+ carry = bytes.slice();
96
+ return;
97
+ }
98
+ const tag = String.fromCharCode(bytes[colon + 1]);
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
+ }
105
+ const length = parseHexBytes(bytes, colon + 2, comma);
106
+ if (length != null) {
107
+ controller.enqueue(bytes.slice(0, comma + 1));
108
+ rawBytesRemaining = length;
109
+ bytes = bytes.subarray(comma + 1);
110
+ continue;
111
+ }
112
+ passThrough = true;
113
+ controller.enqueue(bytes);
114
+ return;
115
+ }
116
+ const tagByte = bytes[colon + 1];
117
+ if (!NEWLINE_PREFIXED_ROW_TAGS.has(tag) && !isUntaggedJsonRowStart(tagByte)) {
118
+ passThrough = true;
119
+ controller.enqueue(bytes);
120
+ return;
121
+ }
122
+ const newline = indexOfByte(bytes, 10);
123
+ if (newline === -1) {
124
+ carry = bytes.slice();
125
+ return;
126
+ }
127
+ controller.enqueue(normalizeReactFlightHintLine(bytes.slice(0, newline + 1)));
128
+ bytes = bytes.subarray(newline + 1);
129
+ }
25
130
  },
26
131
  flush(controller) {
27
- const text = carry + decoder.decode();
28
- if (text) controller.enqueue(encoder.encode(normalizeReactFlightHintLine(text)));
132
+ if (carry.byteLength > 0) controller.enqueue(rawBytesRemaining > 0 ? carry : normalizeReactFlightHintLine(carry));
29
133
  }
30
134
  }));
31
135
  }
@@ -0,0 +1,13 @@
1
+ import { ExecutionContextLike } from "../shims/request-context.js";
2
+
3
+ //#region src/server/worker-revalidation-context.d.ts
4
+ type PlatformExecutionContext = Partial<ExecutionContextLike>;
5
+ /**
6
+ * Add a request-local, in-process Pages revalidation dispatcher to a Worker
7
+ * execution context. Re-entering with the derived internal context preserves
8
+ * the authenticated protocol headers while keeping ordinary inbound requests
9
+ * on the normal header-scrubbing path.
10
+ */
11
+ declare function createWorkerRevalidationContext(base: PlatformExecutionContext | undefined, handleInternalRequest: (request: Request, ctx: ExecutionContextLike) => Promise<Response>): ExecutionContextLike;
12
+ //#endregion
13
+ export { createWorkerRevalidationContext };
@@ -0,0 +1,29 @@
1
+ //#region src/server/worker-revalidation-context.ts
2
+ function deriveExecutionContext(base, dispatchPagesRevalidate, isInternalPagesRevalidation) {
3
+ return {
4
+ waitUntil(promise) {
5
+ if (typeof base?.waitUntil === "function") base.waitUntil(promise);
6
+ else Promise.resolve(promise).catch(() => {});
7
+ },
8
+ ...typeof base?.passThroughOnException === "function" ? { passThroughOnException() {
9
+ base.passThroughOnException?.();
10
+ } } : {},
11
+ ...base?.cache === void 0 ? {} : { cache: base.cache },
12
+ ...base?.trustedRevalidateOrigin === void 0 ? {} : { trustedRevalidateOrigin: base.trustedRevalidateOrigin },
13
+ dispatchPagesRevalidate,
14
+ isInternalPagesRevalidation
15
+ };
16
+ }
17
+ /**
18
+ * Add a request-local, in-process Pages revalidation dispatcher to a Worker
19
+ * execution context. Re-entering with the derived internal context preserves
20
+ * the authenticated protocol headers while keeping ordinary inbound requests
21
+ * on the normal header-scrubbing path.
22
+ */
23
+ function createWorkerRevalidationContext(base, handleInternalRequest) {
24
+ if (typeof base?.dispatchPagesRevalidate === "function") return base;
25
+ const dispatchPagesRevalidate = (request) => handleInternalRequest(request, deriveExecutionContext(base, dispatchPagesRevalidate, true));
26
+ return deriveExecutionContext(base, dispatchPagesRevalidate, false);
27
+ }
28
+ //#endregion
29
+ export { createWorkerRevalidationContext };
@@ -36,7 +36,7 @@ declare function appGetInitialProps({
36
36
  declare class App<P = any, CP = any, S = any> extends React.Component<P & AppProps<CP>, S> {
37
37
  static origGetInitialProps: typeof appGetInitialProps;
38
38
  static getInitialProps: typeof appGetInitialProps;
39
- render(): React.ReactNode;
39
+ render(): React.ReactElement;
40
40
  }
41
41
  //#endregion
42
42
  export { AppContext, AppInitialProps, AppProps, App as default };
@@ -9,7 +9,7 @@ type CacheHandlerValue = {
9
9
  value: IncrementalCacheValue | null;
10
10
  };
11
11
  type CacheControlMetadata = {
12
- revalidate: number;
12
+ revalidate: number | false;
13
13
  expire?: number;
14
14
  };
15
15
  type IncrementalCacheValue = CachedFetchValue | CachedAppPageValue | CachedPagesValue | CachedRouteValue | CachedRedirectValue | CachedImageValue;
@@ -1,4 +1,4 @@
1
- import { readCacheControlNumberField } from "../utils/cache-control-metadata.js";
1
+ import { readCacheControlNumberField, readCacheControlRevalidateField } from "../utils/cache-control-metadata.js";
2
2
  //#region src/shims/cache-handler.ts
3
3
  var NoOpCacheHandler = class {
4
4
  async get(_key, _ctx) {
@@ -88,12 +88,14 @@ var MemoryCacheHandler = class {
88
88
  const revalidatedAt = this.tagRevalidatedAt.get(tag);
89
89
  if (revalidatedAt && revalidatedAt >= entry.lastModified) return null;
90
90
  }
91
- if (entry.expireAt !== null && Date.now() > entry.expireAt) {
92
- this.deleteEntry(key);
93
- return null;
94
- }
95
91
  this.touchEntry(key, entry);
96
92
  const now = Date.now();
93
+ if (entry.expireAt !== null && now > entry.expireAt) return {
94
+ lastModified: entry.lastModified,
95
+ value: entry.value,
96
+ cacheState: "expired",
97
+ cacheControl: entry.cacheControl
98
+ };
97
99
  const requestedRevalidate = readPositiveNumberField(ctx, "revalidate");
98
100
  const requestedRevalidateAt = requestedRevalidate === void 0 ? null : entry.lastModified + requestedRevalidate * 1e3;
99
101
  if (entry.revalidateAt !== null && now > entry.revalidateAt || requestedRevalidateAt !== null && now > requestedRevalidateAt) return {
@@ -113,14 +115,15 @@ var MemoryCacheHandler = class {
113
115
  if (data && "tags" in data && Array.isArray(data.tags)) for (const tag of data.tags) tagSet.add(tag);
114
116
  for (const tag of readStringArrayField(ctx, "tags")) tagSet.add(tag);
115
117
  const tags = [...tagSet];
116
- let effectiveRevalidate = readCacheControlNumberField(ctx, "revalidate");
118
+ let effectiveRevalidate = readCacheControlRevalidateField(ctx);
117
119
  const effectiveExpire = readCacheControlNumberField(ctx, "expire");
118
120
  if (data && "revalidate" in data && typeof data.revalidate === "number") effectiveRevalidate = data.revalidate;
121
+ else if (data && "revalidate" in data && data.revalidate === false) effectiveRevalidate ??= false;
119
122
  if (effectiveRevalidate === 0) return;
120
123
  const now = Date.now();
121
124
  const revalidateAt = typeof effectiveRevalidate === "number" && effectiveRevalidate > 0 ? now + effectiveRevalidate * 1e3 : null;
122
125
  const expireAt = typeof effectiveExpire === "number" && effectiveExpire > 0 ? now + effectiveExpire * 1e3 : null;
123
- const cacheControl = typeof effectiveRevalidate === "number" ? effectiveExpire === void 0 ? { revalidate: effectiveRevalidate } : {
126
+ const cacheControl = typeof effectiveRevalidate === "number" || effectiveRevalidate === false ? effectiveExpire === void 0 ? { revalidate: effectiveRevalidate } : {
124
127
  revalidate: effectiveRevalidate,
125
128
  expire: effectiveExpire
126
129
  } : void 0;
@@ -26,6 +26,8 @@ type UnstableCacheObservation = Readonly<{
26
26
  }>;
27
27
  type CacheState = {
28
28
  actionRevalidationKind: ActionRevalidationKind;
29
+ pendingRevalidatedTags: Set<string>;
30
+ pendingRevalidations: Set<Promise<void>>;
29
31
  requestScopedCacheLife: CacheLifeConfig | null;
30
32
  unstableCacheObservations: Map<string, UnstableCacheObservation>;
31
33
  unstableCacheRevalidation: UnstableCacheRevalidationMode;
@@ -37,6 +39,30 @@ declare function _runWithCacheState<T>(fn: () => T | Promise<T>): T | Promise<T>
37
39
  declare function _initRequestScopedCacheState(): void;
38
40
  declare function markActionRevalidation(kind: ActionRevalidationKind): void;
39
41
  declare function getAndClearActionRevalidationKind(): ActionRevalidationKind;
42
+ /** @internal */
43
+ declare function _markPendingRevalidatedTag(tag: string): void;
44
+ /** @internal */
45
+ declare function _hasPendingRevalidatedTag(tags: readonly string[]): boolean;
46
+ /**
47
+ * Record a cache invalidation that must finish before the current action or
48
+ * route-handler request is finalized. The public revalidation APIs remain
49
+ * synchronous, matching Next.js, while the request boundary owns the await.
50
+ *
51
+ * Returns false outside a request-like phase so standalone calls can retain
52
+ * their historical background-work behavior without accumulating promises in
53
+ * the process-global fallback state.
54
+ *
55
+ * @internal
56
+ */
57
+ declare function _queuePendingRevalidation(promise: Promise<void>): boolean;
58
+ /**
59
+ * Await and clear every cache invalidation queued in the current request.
60
+ * Clearing before awaiting also lets a later drain observe work enqueued by
61
+ * an async continuation while this batch is settling.
62
+ *
63
+ * @internal
64
+ */
65
+ declare function _drainPendingRevalidations(): Promise<void>;
40
66
  declare function _setRequestScopedCacheLife(config: CacheLifeConfig): void;
41
67
  declare function _peekRequestScopedCacheLife(): CacheLifeConfig | null;
42
68
  declare function _consumeRequestScopedCacheLife(): CacheLifeConfig | null;
@@ -44,4 +70,4 @@ declare function recordUnstableCacheObservation(observation: UnstableCacheObserv
44
70
  declare function _peekUnstableCacheObservations(): UnstableCacheObservation[];
45
71
  declare function shouldServeStaleUnstableCacheEntry(): boolean;
46
72
  //#endregion
47
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
73
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, ActionRevalidationKind, CacheLifeConfig, CacheState, UnstableCacheObservation, UnstableCacheRevalidationMode, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
@@ -53,6 +53,8 @@ const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
53
53
  const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
54
54
  const fallbackState = globalState[FALLBACK_KEY] ??= {
55
55
  actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
56
+ pendingRevalidatedTags: /* @__PURE__ */ new Set(),
57
+ pendingRevalidations: /* @__PURE__ */ new Set(),
56
58
  requestScopedCacheLife: null,
57
59
  unstableCacheObservations: /* @__PURE__ */ new Map(),
58
60
  unstableCacheRevalidation: "foreground"
@@ -70,6 +72,8 @@ function _runWithCacheState(fn) {
70
72
  }, fn);
71
73
  const state = {
72
74
  actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
75
+ pendingRevalidatedTags: /* @__PURE__ */ new Set(),
76
+ pendingRevalidations: /* @__PURE__ */ new Set(),
73
77
  requestScopedCacheLife: null,
74
78
  unstableCacheObservations: /* @__PURE__ */ new Map(),
75
79
  unstableCacheRevalidation: "foreground"
@@ -93,6 +97,61 @@ function getAndClearActionRevalidationKind() {
93
97
  state.actionRevalidationKind = ACTION_DID_NOT_REVALIDATE;
94
98
  return kind;
95
99
  }
100
+ function hasRequestScopedCacheState() {
101
+ if (isInsideUnifiedScope() || cacheAls.getStore() !== void 0) return true;
102
+ const phase = getHeadersAccessPhase();
103
+ return phase === "action" || phase === "route-handler";
104
+ }
105
+ /** @internal */
106
+ function _markPendingRevalidatedTag(tag) {
107
+ if (!hasRequestScopedCacheState()) return;
108
+ getCacheState().pendingRevalidatedTags.add(tag);
109
+ }
110
+ /** @internal */
111
+ function _hasPendingRevalidatedTag(tags) {
112
+ if (!hasRequestScopedCacheState()) return false;
113
+ const pendingTags = getCacheState().pendingRevalidatedTags;
114
+ return tags.some((tag) => pendingTags.has(tag));
115
+ }
116
+ /**
117
+ * Record a cache invalidation that must finish before the current action or
118
+ * route-handler request is finalized. The public revalidation APIs remain
119
+ * synchronous, matching Next.js, while the request boundary owns the await.
120
+ *
121
+ * Returns false outside a request-like phase so standalone calls can retain
122
+ * their historical background-work behavior without accumulating promises in
123
+ * the process-global fallback state.
124
+ *
125
+ * @internal
126
+ */
127
+ function _queuePendingRevalidation(promise) {
128
+ if (!hasRequestScopedCacheState()) return false;
129
+ getCacheState().pendingRevalidations.add(promise);
130
+ promise.catch(() => {});
131
+ return true;
132
+ }
133
+ /**
134
+ * Await and clear every cache invalidation queued in the current request.
135
+ * Clearing before awaiting also lets a later drain observe work enqueued by
136
+ * an async continuation while this batch is settling.
137
+ *
138
+ * @internal
139
+ */
140
+ async function _drainPendingRevalidations() {
141
+ const state = getCacheState();
142
+ let didReject = false;
143
+ let firstRejection;
144
+ while (state.pendingRevalidations.size > 0) {
145
+ const pending = [...state.pendingRevalidations];
146
+ state.pendingRevalidations.clear();
147
+ const results = await Promise.allSettled(pending);
148
+ for (const result of results) if (result.status === "rejected" && !didReject) {
149
+ didReject = true;
150
+ firstRejection = result.reason;
151
+ }
152
+ }
153
+ if (didReject) throw firstRejection;
154
+ }
96
155
  function _setRequestScopedCacheLife(config) {
97
156
  const state = getCacheState();
98
157
  if (state.requestScopedCacheLife === null) {
@@ -123,4 +182,4 @@ function shouldServeStaleUnstableCacheEntry() {
123
182
  return getCacheState().unstableCacheRevalidation === "background";
124
183
  }
125
184
  //#endregion
126
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
185
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
@@ -35,6 +35,17 @@ declare const cacheContextStorage: import("node:async_hooks").AsyncLocalStorage<
35
35
  * Get the current cache context. Returns null if not inside a "use cache" function.
36
36
  */
37
37
  declare function getCacheContext(): CacheContext | null;
38
+ /**
39
+ * Build the shared-cache key for a "use cache" function from its build-scoped
40
+ * identity and serialized arguments.
41
+ *
42
+ * This is a logical handler key, not a storage key. Backend-specific adapters
43
+ * are responsible for mapping it to their physical key constraints after
44
+ * applying any storage prefixes.
45
+ *
46
+ * Exported for testing.
47
+ */
48
+ declare function buildUseCacheKey(id: string, keySeed: string | undefined, argsKey?: string): string;
38
49
  /**
39
50
  * Convert an encodeReply result (string | FormData) to a cache key string.
40
51
  * For FormData (binary args), produces a deterministic SHA-256 hash over
@@ -60,6 +71,12 @@ declare function runWithPrivateCache<T>(fn: () => T | Promise<T>): T | Promise<T
60
71
  */
61
72
  declare function clearPrivateCache(): void;
62
73
  type RegisterCachedFunctionOptions = {
74
+ /**
75
+ * Whether the original function declaration accepts a second argument.
76
+ * Function.length cannot represent default or rest parameters, so the
77
+ * transform records this separately for metadata parent resolution.
78
+ */
79
+ acceptsSecondArgument?: boolean;
63
80
  /**
64
81
  * Internal transform metadata for file-level `"use cache"` default exports
65
82
  * in App Router `page.*` files. Page components receive framework-owned
@@ -80,4 +97,4 @@ type RegisterCachedFunctionOptions = {
80
97
  */
81
98
  declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant?: string, options?: RegisterCachedFunctionOptions): (...args: TArgs) => Promise<TResult>;
82
99
  //#endregion
83
- export { CacheContext, NestedDynamicUseCacheError, PrivateCacheState, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
100
+ export { CacheContext, NestedDynamicUseCacheError, PrivateCacheState, buildUseCacheKey, cacheContextStorage, clearPrivateCache, getCacheContext, markAppPagePropsForUseCache, registerCachedFunction, replyToCacheKey, runWithPrivateCache };