vinext 0.1.8 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/README.md +51 -30
  2. package/dist/build/css-url-assets.d.ts +3 -1
  3. package/dist/build/css-url-assets.js +18 -1
  4. package/dist/build/inject-pregenerated-paths.d.ts +7 -0
  5. package/dist/build/inject-pregenerated-paths.js +21 -0
  6. package/dist/build/layout-classification.js +1 -1
  7. package/dist/build/nitro-route-rules.js +1 -1
  8. package/dist/build/pages-client-assets-module.d.ts +11 -0
  9. package/dist/build/pages-client-assets-module.js +27 -0
  10. package/dist/build/prerender-server-entry.d.ts +1 -0
  11. package/dist/build/prerender-server-entry.js +49 -0
  12. package/dist/build/prerender-server-pool.d.ts +44 -0
  13. package/dist/build/prerender-server-pool.js +194 -0
  14. package/dist/build/prerender.d.ts +2 -1
  15. package/dist/build/prerender.js +98 -27
  16. package/dist/build/report.d.ts +13 -2
  17. package/dist/build/report.js +99 -2
  18. package/dist/build/run-prerender.d.ts +7 -0
  19. package/dist/build/run-prerender.js +12 -2
  20. package/dist/build/standalone.js +2 -0
  21. package/dist/cache/cache-adapters-virtual.js +3 -3
  22. package/dist/check.d.ts +4 -6
  23. package/dist/check.js +48 -11
  24. package/dist/cli-args.d.ts +1 -2
  25. package/dist/cli-args.js +1 -1
  26. package/dist/cli-dev-config.d.ts +12 -0
  27. package/dist/cli-dev-config.js +23 -0
  28. package/dist/cli.js +112 -96
  29. package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
  30. package/dist/{server → client}/dev-error-overlay-store.js +1 -1
  31. package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
  32. package/dist/{server → client}/dev-error-overlay.js +2 -2
  33. package/dist/client/navigation-runtime.d.ts +2 -0
  34. package/dist/client/navigation-runtime.js +3 -1
  35. package/dist/client/vinext-next-data.d.ts +4 -1
  36. package/dist/client/window-next.d.ts +2 -1
  37. package/dist/cloudflare/index.d.ts +2 -2
  38. package/dist/cloudflare/index.js +2 -2
  39. package/dist/config/config-matchers.js +45 -19
  40. package/dist/config/next-config.d.ts +41 -9
  41. package/dist/config/next-config.js +60 -3
  42. package/dist/config/prerender.d.ts +34 -0
  43. package/dist/config/prerender.js +55 -0
  44. package/dist/entries/app-browser-entry.js +5 -1
  45. package/dist/entries/app-rsc-entry.d.ts +5 -3
  46. package/dist/entries/app-rsc-entry.js +44 -10
  47. package/dist/entries/app-rsc-manifest.js +2 -0
  48. package/dist/entries/pages-client-entry.d.ts +3 -0
  49. package/dist/entries/pages-client-entry.js +28 -3
  50. package/dist/entries/pages-server-entry.js +23 -6
  51. package/dist/image/image-adapters-virtual.d.ts +59 -0
  52. package/dist/image/image-adapters-virtual.js +59 -0
  53. package/dist/index.d.ts +33 -0
  54. package/dist/index.js +482 -120
  55. package/dist/init-cloudflare.d.ts +43 -0
  56. package/dist/init-cloudflare.js +839 -0
  57. package/dist/init-platform.d.ts +40 -0
  58. package/dist/init-platform.js +195 -0
  59. package/dist/init.d.ts +16 -38
  60. package/dist/init.js +209 -99
  61. package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
  62. package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
  63. package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
  64. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
  65. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +9 -2
  66. package/dist/packages/cloudflare/src/deploy-config.js +150 -0
  67. package/dist/packages/cloudflare/src/deploy-help.js +55 -0
  68. package/dist/packages/cloudflare/src/deploy.js +272 -0
  69. package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
  70. package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +44 -20
  71. package/dist/plugins/ast-scope.d.ts +16 -0
  72. package/dist/plugins/ast-scope.js +62 -0
  73. package/dist/plugins/ast-utils.d.ts +27 -1
  74. package/dist/plugins/ast-utils.js +32 -1
  75. package/dist/plugins/css-module-imports.d.ts +14 -0
  76. package/dist/plugins/css-module-imports.js +59 -0
  77. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  78. package/dist/plugins/fonts.js +1 -1
  79. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  80. package/dist/plugins/ignore-dynamic-requests.js +530 -0
  81. package/dist/plugins/og-assets.js +2 -1
  82. package/dist/plugins/optimize-imports.js +1 -1
  83. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  84. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  85. package/dist/plugins/sass.d.ts +17 -1
  86. package/dist/plugins/sass.js +74 -1
  87. package/dist/plugins/styled-jsx.d.ts +16 -0
  88. package/dist/plugins/styled-jsx.js +149 -0
  89. package/dist/plugins/typeof-window.d.ts +1 -1
  90. package/dist/plugins/typeof-window.js +28 -56
  91. package/dist/routing/app-route-graph.d.ts +23 -2
  92. package/dist/routing/app-route-graph.js +138 -38
  93. package/dist/routing/file-matcher.d.ts +11 -1
  94. package/dist/routing/file-matcher.js +18 -3
  95. package/dist/routing/pages-router.js +2 -2
  96. package/dist/server/api-handler.js +9 -14
  97. package/dist/server/app-browser-action-result.d.ts +4 -1
  98. package/dist/server/app-browser-action-result.js +8 -1
  99. package/dist/server/app-browser-entry.js +198 -57
  100. package/dist/server/app-browser-interception-context.d.ts +1 -0
  101. package/dist/server/app-browser-interception-context.js +4 -2
  102. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  103. package/dist/server/app-browser-navigation-controller.js +60 -31
  104. package/dist/server/app-browser-server-action-client.d.ts +1 -1
  105. package/dist/server/app-browser-server-action-client.js +8 -7
  106. package/dist/server/app-browser-state.d.ts +12 -1
  107. package/dist/server/app-browser-state.js +25 -8
  108. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  109. package/dist/server/app-browser-visible-commit.js +42 -24
  110. package/dist/server/app-elements-wire.d.ts +9 -2
  111. package/dist/server/app-elements-wire.js +8 -1
  112. package/dist/server/app-elements.d.ts +2 -2
  113. package/dist/server/app-elements.js +4 -3
  114. package/dist/server/app-fallback-renderer.d.ts +2 -1
  115. package/dist/server/app-fallback-renderer.js +10 -6
  116. package/dist/server/app-hydration-cache-publication.d.ts +11 -0
  117. package/dist/server/app-hydration-cache-publication.js +43 -0
  118. package/dist/server/app-middleware.d.ts +4 -3
  119. package/dist/server/app-middleware.js +8 -3
  120. package/dist/server/app-optimistic-routing.js +11 -4
  121. package/dist/server/app-page-boundary.js +2 -1
  122. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  123. package/dist/server/app-page-cache-finalizer.js +5 -4
  124. package/dist/server/app-page-cache-render.d.ts +1 -0
  125. package/dist/server/app-page-cache-render.js +8 -4
  126. package/dist/server/app-page-cache.d.ts +1 -0
  127. package/dist/server/app-page-cache.js +27 -7
  128. package/dist/server/app-page-dispatch.d.ts +1 -0
  129. package/dist/server/app-page-dispatch.js +26 -8
  130. package/dist/server/app-page-element-builder.d.ts +2 -1
  131. package/dist/server/app-page-element-builder.js +59 -4
  132. package/dist/server/app-page-execution.js +2 -1
  133. package/dist/server/app-page-probe.js +5 -0
  134. package/dist/server/app-page-render-identity.d.ts +2 -0
  135. package/dist/server/app-page-render-identity.js +3 -2
  136. package/dist/server/app-page-render.d.ts +2 -0
  137. package/dist/server/app-page-render.js +85 -16
  138. package/dist/server/app-page-request.d.ts +14 -0
  139. package/dist/server/app-page-request.js +69 -4
  140. package/dist/server/app-page-response.d.ts +7 -0
  141. package/dist/server/app-page-response.js +16 -4
  142. package/dist/server/app-page-route-wiring.d.ts +8 -1
  143. package/dist/server/app-page-route-wiring.js +32 -18
  144. package/dist/server/app-page-segment-state.d.ts +2 -1
  145. package/dist/server/app-page-segment-state.js +3 -1
  146. package/dist/server/app-page-stream.d.ts +7 -1
  147. package/dist/server/app-page-stream.js +3 -1
  148. package/dist/server/app-route-handler-execution.js +5 -1
  149. package/dist/server/app-route-handler-response.js +1 -0
  150. package/dist/server/app-route-handler-runtime.js +1 -1
  151. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  152. package/dist/server/app-route-tree-prefetch.js +187 -0
  153. package/dist/server/app-router-entry.js +9 -2
  154. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  155. package/dist/server/app-rsc-cache-busting.js +9 -4
  156. package/dist/server/app-rsc-handler.d.ts +7 -0
  157. package/dist/server/app-rsc-handler.js +148 -39
  158. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  159. package/dist/server/app-rsc-render-mode.js +4 -1
  160. package/dist/server/app-rsc-request-normalization.d.ts +6 -6
  161. package/dist/server/app-rsc-request-normalization.js +10 -8
  162. package/dist/server/app-segment-config.d.ts +11 -0
  163. package/dist/server/app-segment-config.js +62 -6
  164. package/dist/server/app-server-action-execution.d.ts +1 -0
  165. package/dist/server/app-server-action-execution.js +61 -30
  166. package/dist/server/app-ssr-entry.d.ts +3 -0
  167. package/dist/server/app-ssr-entry.js +13 -5
  168. package/dist/server/app-ssr-stream.d.ts +7 -3
  169. package/dist/server/app-ssr-stream.js +10 -6
  170. package/dist/server/app-visited-response-cache.d.ts +6 -0
  171. package/dist/server/app-visited-response-cache.js +3 -1
  172. package/dist/server/cache-control.d.ts +3 -1
  173. package/dist/server/cache-control.js +13 -1
  174. package/dist/server/client-trace-metadata.js +26 -0
  175. package/dist/server/default-global-not-found-module.d.ts +14 -0
  176. package/dist/server/default-global-not-found-module.js +14 -0
  177. package/dist/server/dev-route-files.js +4 -0
  178. package/dist/server/dev-server.d.ts +11 -1
  179. package/dist/server/dev-server.js +94 -35
  180. package/dist/server/dev-stack-sourcemap.d.ts +1 -1
  181. package/dist/server/dev-stack-sourcemap.js +1 -1
  182. package/dist/server/fetch-handler.d.ts +2 -0
  183. package/dist/server/fetch-handler.js +18 -0
  184. package/dist/server/headers.d.ts +7 -15
  185. package/dist/server/headers.js +11 -18
  186. package/dist/server/image-optimization.d.ts +51 -1
  187. package/dist/server/image-optimization.js +52 -2
  188. package/dist/server/implicit-tags.js +1 -1
  189. package/dist/server/isr-cache.d.ts +3 -2
  190. package/dist/server/isr-cache.js +9 -5
  191. package/dist/server/metadata-routes.d.ts +3 -1
  192. package/dist/server/metadata-routes.js +12 -2
  193. package/dist/server/middleware-runtime.js +6 -1
  194. package/dist/server/navigation-planner.d.ts +1 -0
  195. package/dist/server/navigation-planner.js +14 -3
  196. package/dist/server/pages-api-route.js +2 -2
  197. package/dist/server/pages-asset-tags.d.ts +4 -6
  198. package/dist/server/pages-asset-tags.js +12 -12
  199. package/dist/server/pages-client-assets.d.ts +12 -0
  200. package/dist/server/pages-client-assets.js +10 -0
  201. package/dist/server/pages-data-route.d.ts +4 -2
  202. package/dist/server/pages-data-route.js +18 -4
  203. package/dist/server/pages-dev-module-url.d.ts +2 -1
  204. package/dist/server/pages-dev-module-url.js +6 -3
  205. package/dist/server/pages-node-compat.d.ts +19 -1
  206. package/dist/server/pages-node-compat.js +81 -4
  207. package/dist/server/pages-page-data.d.ts +33 -1
  208. package/dist/server/pages-page-data.js +62 -33
  209. package/dist/server/pages-page-handler.d.ts +2 -1
  210. package/dist/server/pages-page-handler.js +38 -19
  211. package/dist/server/pages-page-response.d.ts +8 -0
  212. package/dist/server/pages-page-response.js +7 -3
  213. package/dist/server/pages-request-pipeline.d.ts +9 -5
  214. package/dist/server/pages-request-pipeline.js +55 -7
  215. package/dist/server/pages-router-entry.d.ts +30 -0
  216. package/dist/server/pages-router-entry.js +108 -0
  217. package/dist/server/prerender-manifest.d.ts +3 -1
  218. package/dist/server/prerender-route-params.js +1 -1
  219. package/dist/server/prod-server.d.ts +5 -3
  220. package/dist/server/prod-server.js +68 -39
  221. package/dist/server/request-pipeline.js +2 -1
  222. package/dist/server/seed-cache.js +4 -4
  223. package/dist/shims/app-router-scroll-state.d.ts +1 -0
  224. package/dist/shims/app-router-scroll-state.js +1 -0
  225. package/dist/shims/app-router-scroll.js +2 -1
  226. package/dist/shims/cache-handler.js +8 -1
  227. package/dist/shims/cache.js +22 -15
  228. package/dist/shims/cdn-cache.js +1 -1
  229. package/dist/shims/dynamic-preload-chunks.js +2 -1
  230. package/dist/shims/fetch-cache.d.ts +3 -1
  231. package/dist/shims/fetch-cache.js +77 -52
  232. package/dist/shims/form.d.ts +4 -2
  233. package/dist/shims/form.js +37 -43
  234. package/dist/shims/headers.d.ts +7 -1
  235. package/dist/shims/headers.js +17 -3
  236. package/dist/shims/image.js +75 -14
  237. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  238. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  239. package/dist/shims/internal/app-route-detection.d.ts +2 -17
  240. package/dist/shims/internal/app-route-detection.js +4 -17
  241. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
  242. package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
  243. package/dist/shims/internal/hybrid-client-route-owner.d.ts +3 -15
  244. package/dist/shims/internal/hybrid-client-route-owner.js +40 -58
  245. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +10 -5
  246. package/dist/shims/internal/pages-data-fetch-dedup.js +84 -14
  247. package/dist/shims/internal/pages-data-target.d.ts +18 -12
  248. package/dist/shims/internal/pages-data-target.js +97 -13
  249. package/dist/shims/internal/pages-router-components.d.ts +7 -0
  250. package/dist/shims/internal/pages-router-components.js +13 -0
  251. package/dist/shims/layout-segment-context.d.ts +4 -1
  252. package/dist/shims/layout-segment-context.js +18 -4
  253. package/dist/shims/link.d.ts +1 -1
  254. package/dist/shims/link.js +224 -58
  255. package/dist/shims/navigation.d.ts +19 -3
  256. package/dist/shims/navigation.js +245 -47
  257. package/dist/shims/request-context.js +18 -0
  258. package/dist/shims/root-params.d.ts +15 -1
  259. package/dist/shims/root-params.js +21 -1
  260. package/dist/shims/router.d.ts +5 -7
  261. package/dist/shims/router.js +387 -102
  262. package/dist/shims/server.js +3 -2
  263. package/dist/shims/slot.js +3 -6
  264. package/dist/shims/unified-request-context.js +1 -0
  265. package/dist/typegen.js +1 -1
  266. package/dist/utils/client-runtime-metadata.d.ts +2 -18
  267. package/dist/utils/client-runtime-metadata.js +31 -22
  268. package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
  269. package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
  270. package/dist/utils/domain-locale.d.ts +6 -3
  271. package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
  272. package/dist/{server → utils}/middleware-request-headers.js +3 -3
  273. package/dist/utils/project.d.ts +48 -2
  274. package/dist/utils/project.js +225 -4
  275. package/dist/utils/protocol-headers.d.ts +23 -0
  276. package/dist/utils/protocol-headers.js +23 -0
  277. package/dist/utils/react-version.d.ts +4 -0
  278. package/dist/utils/react-version.js +44 -0
  279. package/dist/utils/vite-version.d.ts +2 -0
  280. package/dist/utils/vite-version.js +11 -1
  281. package/package.json +47 -2
  282. package/dist/deploy.d.ts +0 -197
  283. package/dist/deploy.js +0 -1040
  284. package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
  285. /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
@@ -1,8 +1,8 @@
1
1
  import { isrCacheKey, isrSetPrerenderedAppPage } from "./isr-cache.js";
2
+ import { getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
2
3
  import { buildAppPageCacheTags } from "./app-page-cache.js";
3
4
  import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
4
5
  import { addPregeneratedConcretePath, clearPregeneratedConcretePaths, normalizePregeneratedPathname } from "./pregenerated-concrete-paths.js";
5
- import { getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest } from "./prerender-manifest.js";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
8
  //#region src/server/seed-cache.ts
@@ -67,7 +67,7 @@ async function seedMemoryCacheFromPrerender(serverDir, options) {
67
67
  const revalidateSeconds = typeof route.revalidate === "number" ? route.revalidate : void 0;
68
68
  const expireSeconds = typeof route.expire === "number" ? route.expire : void 0;
69
69
  const tags = buildAppPageCacheTags(cachePathname, []);
70
- if (await seedHtml(writeAppPageEntry, prerenderDir, htmlKey, artifactPathname, trailingSlash, revalidateSeconds, expireSeconds, tags)) {
70
+ if (await seedHtml(writeAppPageEntry, prerenderDir, htmlKey, artifactPathname, trailingSlash, route.headers, revalidateSeconds, expireSeconds, tags)) {
71
71
  await seedRsc(writeAppPageEntry, prerenderDir, rscKey, artifactPathname, revalidateSeconds, expireSeconds, tags);
72
72
  seeded++;
73
73
  }
@@ -81,7 +81,7 @@ function createDefaultAppPageEntryWriter() {
81
81
  * Seed the HTML cache entry for a single route.
82
82
  * Returns true if the file existed and was seeded.
83
83
  */
84
- async function seedHtml(writeAppPageEntry, prerenderDir, key, pathname, trailingSlash, revalidateSeconds, expireSeconds, tags) {
84
+ async function seedHtml(writeAppPageEntry, prerenderDir, key, pathname, trailingSlash, headers, revalidateSeconds, expireSeconds, tags) {
85
85
  const relPath = getOutputPath(pathname, trailingSlash);
86
86
  const fullPath = path.join(prerenderDir, relPath);
87
87
  if (!fs.existsSync(fullPath)) return false;
@@ -89,7 +89,7 @@ async function seedHtml(writeAppPageEntry, prerenderDir, key, pathname, trailing
89
89
  kind: "APP_PAGE",
90
90
  html: fs.readFileSync(fullPath, "utf-8"),
91
91
  rscData: void 0,
92
- headers: void 0,
92
+ headers,
93
93
  postponed: void 0,
94
94
  status: void 0
95
95
  }, {
@@ -2,6 +2,7 @@
2
2
  type AppRouterScrollIntent = Readonly<{
3
3
  commitId: number | null;
4
4
  hash: string | null;
5
+ headElements: ReadonlySet<Element> | null;
5
6
  id: number;
6
7
  targetHoistedInHead: boolean;
7
8
  }>;
@@ -14,6 +14,7 @@ function beginAppRouterScrollIntent(hash) {
14
14
  const intent = {
15
15
  commitId: null,
16
16
  hash,
17
+ headElements: typeof document === "undefined" ? null : new Set(document.head?.children ?? []),
17
18
  id: store.nextId,
18
19
  targetHoistedInHead: false
19
20
  };
@@ -99,7 +99,8 @@ var AppRouterScrollTargetInner = class extends React$1.Component {
99
99
  else node = null;
100
100
  if (node === null) {
101
101
  node = findDOMNode(this);
102
- if (node !== null && isInDocumentHead(node)) {
102
+ const headElement = node instanceof Element ? node : node?.parentElement;
103
+ if (node !== null && headElement != null && isInDocumentHead(node) && !intent.headElements?.has(headElement)) {
103
104
  markAppRouterScrollIntentHeadHoisted(intent, this.props.commitId);
104
105
  return;
105
106
  }
@@ -42,6 +42,10 @@ function readStringArrayField(ctx, field) {
42
42
  if (!Array.isArray(value)) return [];
43
43
  return value.filter((item) => typeof item === "string");
44
44
  }
45
+ function readPositiveNumberField(ctx, field) {
46
+ const value = ctx?.[field];
47
+ return typeof value === "number" && value > 0 ? value : void 0;
48
+ }
45
49
  var MemoryCacheHandler = class {
46
50
  store = /* @__PURE__ */ new Map();
47
51
  tagRevalidatedAt = /* @__PURE__ */ new Map();
@@ -89,7 +93,10 @@ var MemoryCacheHandler = class {
89
93
  return null;
90
94
  }
91
95
  this.touchEntry(key, entry);
92
- if (entry.revalidateAt !== null && Date.now() > entry.revalidateAt) return {
96
+ const now = Date.now();
97
+ const requestedRevalidate = readPositiveNumberField(ctx, "revalidate");
98
+ const requestedRevalidateAt = requestedRevalidate === void 0 ? null : entry.lastModified + requestedRevalidate * 1e3;
99
+ if (entry.revalidateAt !== null && now > entry.revalidateAt || requestedRevalidateAt !== null && now > requestedRevalidateAt) return {
93
100
  lastModified: entry.lastModified,
94
101
  value: entry.value,
95
102
  cacheState: "stale",
@@ -5,9 +5,10 @@ import { MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getC
5
5
  import { getCdnCacheAdapter } from "./cdn-cache.js";
6
6
  import { fnv1a64 } from "../utils/hash.js";
7
7
  import { makeHangingPromise } from "./internal/make-hanging-promise.js";
8
- import { getHeadersAccessPhase, markDynamicUsage } from "./headers.js";
8
+ import { getHeadersAccessPhase, isDraftModeEnabled, markDynamicUsage } from "./headers.js";
9
9
  import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
10
10
  import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
11
+ import { addCollectedRequestTags } from "./fetch-cache.js";
11
12
  import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
12
13
  //#region src/shims/cache.ts
13
14
  /**
@@ -110,10 +111,10 @@ function refresh() {
110
111
  *
111
112
  * @see https://nextjs.org/docs/app/api-reference/functions/updateTag
112
113
  */
113
- async function updateTag(tag) {
114
+ function updateTag(tag) {
114
115
  if (getHeadersAccessPhase() !== "action") throw new Error("updateTag can only be called from within a Server Action. To invalidate cache tags in Route Handlers or other contexts, use revalidateTag instead. See more info here: https://nextjs.org/docs/app/api-reference/functions/updateTag");
115
116
  markActionRevalidation(1);
116
- await _invalidateEncodedTag(encodeCacheTag(tag));
117
+ return _invalidateEncodedTag(encodeCacheTag(tag));
117
118
  }
118
119
  /**
119
120
  * Opt out of static rendering and indicate a particular component should not be cached.
@@ -124,6 +125,7 @@ async function updateTag(tag) {
124
125
  * It's provided for API compatibility so apps importing it don't break.
125
126
  */
126
127
  function unstable_noStore() {
128
+ if (isInsideUnstableCacheScope()) return;
127
129
  markDynamicUsage();
128
130
  }
129
131
  /**
@@ -373,6 +375,7 @@ function unstable_cache(fn, keyParts, options) {
373
375
  const revalidateSeconds = options?.revalidate;
374
376
  const cachedFn = async (...args) => {
375
377
  const cacheKey = `unstable_cache:${baseKey}:${JSON.stringify(args)}`;
378
+ addCollectedRequestTags(tags);
376
379
  recordUnstableCacheObservation({
377
380
  kind: "unstable_cache",
378
381
  keyHash: fnv1a64(cacheKey),
@@ -380,19 +383,23 @@ function unstable_cache(fn, keyParts, options) {
380
383
  tagCount: tags.length,
381
384
  tagHash: tags.length > 0 ? fnv1a64(JSON.stringify(tags)) : null
382
385
  });
383
- const existing = await getDataCacheHandler().get(cacheKey, {
384
- kind: "FETCH",
385
- tags
386
- });
387
- if (existing?.value && existing.value.kind === "FETCH") {
388
- const cached = tryDeserializeUnstableCacheResult(existing.value.data.body);
389
- if (cached.ok) if (existing.cacheState === "stale") {
390
- if (shouldServeStaleUnstableCacheEntry()) {
391
- scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds));
392
- return cached.value;
393
- }
394
- } else return cached.value;
386
+ const isDraftMode = isDraftModeEnabled();
387
+ if (!isDraftMode) {
388
+ const existing = await getDataCacheHandler().get(cacheKey, {
389
+ kind: "FETCH",
390
+ tags
391
+ });
392
+ if (existing?.value && existing.value.kind === "FETCH") {
393
+ const cached = tryDeserializeUnstableCacheResult(existing.value.data.body);
394
+ if (cached.ok) if (existing.cacheState === "stale") {
395
+ if (shouldServeStaleUnstableCacheEntry()) {
396
+ scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds));
397
+ return cached.value;
398
+ }
399
+ } else return cached.value;
400
+ }
395
401
  }
402
+ if (isDraftMode) return await _unstableCacheAls.run(true, () => fn(...args));
396
403
  return await refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds);
397
404
  };
398
405
  return cachedFn;
@@ -1,6 +1,6 @@
1
1
  import { getRequestExecutionContext } from "./request-context.js";
2
2
  import { getDataCacheHandler } from "./cache-handler.js";
3
- import { CloudflareCdnCacheAdapter } from "../cloudflare/src/cache/cdn-adapter.runtime.js";
3
+ import { CloudflareCdnCacheAdapter } from "../packages/cloudflare/src/cache/cdn-adapter.runtime.js";
4
4
  //#region src/shims/cdn-cache.ts
5
5
  /**
6
6
  * CDN cache adapter — owns the *page-level ISR serving strategy*.
@@ -3,6 +3,7 @@ import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
3
3
  import { useScriptNonce } from "./script-nonce-context.js";
4
4
  import React from "react";
5
5
  import * as ReactDOM from "react-dom";
6
+ import { getPagesClientAssets } from "vinext/server/pages-client-assets";
6
7
  //#region src/shims/dynamic-preload-chunks.tsx
7
8
  /**
8
9
  * Preload links for rendered next/dynamic() boundaries.
@@ -34,7 +35,7 @@ function dynamicPreloadHref(file) {
34
35
  }
35
36
  function resolveDynamicPreloadFiles(moduleIds) {
36
37
  if (!moduleIds || moduleIds.length === 0) return [];
37
- const preloadMap = globalThis.__VINEXT_DYNAMIC_PRELOADS__;
38
+ const preloadMap = getPagesClientAssets().dynamicPreloads;
38
39
  if (!preloadMap) return [];
39
40
  const files = [];
40
41
  const seen = /* @__PURE__ */ new Set();
@@ -42,6 +42,7 @@ type FetchCacheState = {
42
42
  currentFetchCacheMode: FetchCacheMode | null;
43
43
  currentForceDynamicFetchDefault: boolean;
44
44
  dynamicFetchUrls: Set<string>;
45
+ refreshStaleFetchesInForeground: boolean;
45
46
  isFetchDedupeActive: boolean;
46
47
  currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
47
48
  };
@@ -86,6 +87,7 @@ declare function setCurrentFetchSoftTags(tags: string[]): void;
86
87
  declare function getCurrentFetchSoftTags(): string[];
87
88
  declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
88
89
  declare function setCurrentForceDynamicFetchDefault(enabled: boolean): void;
90
+ declare function setRefreshStaleFetchesInForeground(enabled: boolean): void;
89
91
  /**
90
92
  * Install the patched fetch and reset per-request tag state.
91
93
  * Returns a cleanup function that clears tags.
@@ -133,4 +135,4 @@ declare function ensureFetchPatch(): void;
133
135
  */
134
136
  declare function getOriginalFetch(): typeof globalThis.fetch;
135
137
  //#endregion
136
- export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
138
+ export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground, withFetchCache };
@@ -3,6 +3,7 @@ import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation }
3
3
  import { getRequestExecutionContext } from "./request-context.js";
4
4
  import { getDataCacheHandler } from "./cache-handler.js";
5
5
  import { markDynamicUsage } from "./headers.js";
6
+ import { _setRequestScopedCacheLife } from "./cache-request-state.js";
6
7
  import { encodeCacheTags } from "../utils/encode-cache-tag.js";
7
8
  //#region src/shims/fetch-cache.ts
8
9
  /**
@@ -296,6 +297,7 @@ const _fallbackState = _g[_FALLBACK_KEY] ??= {
296
297
  currentFetchCacheMode: null,
297
298
  currentForceDynamicFetchDefault: false,
298
299
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
300
+ refreshStaleFetchesInForeground: false,
299
301
  isFetchDedupeActive: false,
300
302
  currentFetchDedupeEntries: /* @__PURE__ */ new Map()
301
303
  };
@@ -314,6 +316,7 @@ function _resetFallbackState(isFetchDedupeActive) {
314
316
  _fallbackState.currentFetchCacheMode = null;
315
317
  _fallbackState.currentForceDynamicFetchDefault = false;
316
318
  _fallbackState.dynamicFetchUrls = /* @__PURE__ */ new Set();
319
+ _fallbackState.refreshStaleFetchesInForeground = false;
317
320
  _fallbackState.isFetchDedupeActive = isFetchDedupeActive;
318
321
  _fallbackState.currentFetchDedupeEntries = /* @__PURE__ */ new Map();
319
322
  }
@@ -330,6 +333,56 @@ function markUncachedFetchForPageOutput(input) {
330
333
  function recordCacheableFetchObservation(input) {
331
334
  _getState().cacheableFetchUrls.add(getFetchObservationUrl(input));
332
335
  }
336
+ function recordFiniteFetchRevalidate(revalidateSeconds) {
337
+ if (Number.isFinite(revalidateSeconds) && revalidateSeconds > 0) _setRequestScopedCacheLife({ revalidate: revalidateSeconds });
338
+ }
339
+ function shouldRefreshStaleFetchInForeground() {
340
+ return _getState().refreshStaleFetchesInForeground;
341
+ }
342
+ async function buildFetchCacheValue(response, tags, revalidateSeconds, options) {
343
+ if (response.status !== 200) return null;
344
+ const responseForCache = options?.cloneForReturn === false ? response : response.clone();
345
+ const body = await responseForCache.text();
346
+ const headers = {};
347
+ responseForCache.headers.forEach((v, k) => {
348
+ if (k.toLowerCase() === "set-cookie") return;
349
+ headers[k] = v;
350
+ });
351
+ return {
352
+ kind: "FETCH",
353
+ data: {
354
+ headers,
355
+ body,
356
+ url: response.url,
357
+ status: responseForCache.status
358
+ },
359
+ tags,
360
+ revalidate: revalidateSeconds
361
+ };
362
+ }
363
+ async function writeFetchCacheResponse(handler, cacheKey, response, tags, revalidateSeconds, options) {
364
+ const cacheValue = await buildFetchCacheValue(response, tags, revalidateSeconds, options);
365
+ if (!cacheValue) return;
366
+ await handler.set(cacheKey, cacheValue, {
367
+ fetchCache: true,
368
+ tags,
369
+ revalidate: revalidateSeconds
370
+ });
371
+ }
372
+ async function lowerFetchCacheRevalidateIfNeeded(handler, cacheKey, cachedValue, tags, revalidateSeconds) {
373
+ if (!Number.isFinite(revalidateSeconds) || revalidateSeconds <= 0 || typeof cachedValue.revalidate !== "number" || cachedValue.revalidate <= revalidateSeconds) return;
374
+ const mergedTags = Array.from(new Set([...cachedValue.tags ?? [], ...tags]));
375
+ const updatedValue = {
376
+ ...cachedValue,
377
+ tags: mergedTags,
378
+ revalidate: revalidateSeconds
379
+ };
380
+ await handler.set(cacheKey, updatedValue, {
381
+ fetchCache: true,
382
+ tags: mergedTags,
383
+ revalidate: revalidateSeconds
384
+ });
385
+ }
333
386
  function peekCacheableFetchObservations() {
334
387
  return [..._getState().cacheableFetchUrls].sort();
335
388
  }
@@ -393,6 +446,9 @@ function setCurrentFetchCacheMode(mode) {
393
446
  function setCurrentForceDynamicFetchDefault(enabled) {
394
447
  _getState().currentForceDynamicFetchDefault = enabled;
395
448
  }
449
+ function setRefreshStaleFetchesInForeground(enabled) {
450
+ _getState().refreshStaleFetchesInForeground = enabled;
451
+ }
396
452
  function isNoStoreFetch(cacheDirective, nextOpts) {
397
453
  return cacheDirective === "no-store" || cacheDirective === "no-cache" || nextOpts?.revalidate === 0;
398
454
  }
@@ -562,6 +618,7 @@ function createPatchedFetch() {
562
618
  return dedupeFetch(input, cleanInit);
563
619
  }
564
620
  recordCacheableFetchObservation(input);
621
+ recordFiniteFetchRevalidate(revalidateSeconds);
565
622
  const reqTags = _getState().currentRequestTags;
566
623
  const tags = encodeCacheTags(nextOpts?.tags ?? []);
567
624
  if (tags.length > 0) {
@@ -586,39 +643,24 @@ function createPatchedFetch() {
586
643
  const cached = await handler.get(cacheKey, {
587
644
  kind: "FETCH",
588
645
  tags,
589
- softTags
646
+ softTags,
647
+ revalidate: revalidateSeconds
590
648
  });
591
649
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState !== "stale") {
650
+ await lowerFetchCacheRevalidateIfNeeded(handler, cacheKey, cached.value, tags, revalidateSeconds);
592
651
  const cachedData = cached.value.data;
593
652
  return buildCachedFetchResponse(cachedData, input);
594
653
  }
595
654
  if (cached?.value && cached.value.kind === "FETCH" && cached.cacheState === "stale") {
655
+ if (shouldRefreshStaleFetchInForeground()) {
656
+ const freshResponse = await dedupeFetch(input, fetchInit);
657
+ await writeFetchCacheResponse(handler, cacheKey, freshResponse, tags, revalidateSeconds);
658
+ return freshResponse;
659
+ }
596
660
  const staleData = cached.value.data;
597
661
  if (!pendingRefetches.has(cacheKey)) {
598
662
  const refetchPromise = originalFetch(input, fetchInit).then(async (freshResp) => {
599
- if (freshResp.status !== 200) return;
600
- const freshBody = await freshResp.text();
601
- const freshHeaders = {};
602
- freshResp.headers.forEach((v, k) => {
603
- if (k.toLowerCase() === "set-cookie") return;
604
- freshHeaders[k] = v;
605
- });
606
- const freshValue = {
607
- kind: "FETCH",
608
- data: {
609
- headers: freshHeaders,
610
- body: freshBody,
611
- url: freshResp.url,
612
- status: freshResp.status
613
- },
614
- tags,
615
- revalidate: revalidateSeconds
616
- };
617
- await handler.set(cacheKey, freshValue, {
618
- fetchCache: true,
619
- tags,
620
- revalidate: revalidateSeconds
621
- });
663
+ await writeFetchCacheResponse(handler, cacheKey, freshResp, tags, revalidateSeconds, { cloneForReturn: false });
622
664
  }).catch((err) => {
623
665
  const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
624
666
  console.error(`[vinext] fetch cache background revalidation failed for ${url} (key=${cacheKey.slice(0, 12)}...):`, err);
@@ -638,33 +680,14 @@ function createPatchedFetch() {
638
680
  console.error("[vinext] fetch cache read error:", cacheErr);
639
681
  }
640
682
  const response = await dedupeFetch(input, fetchInit);
641
- if (response.status === 200) {
642
- const cloned = response.clone();
643
- const body = await cloned.text();
644
- const headers = {};
645
- cloned.headers.forEach((v, k) => {
646
- if (k.toLowerCase() === "set-cookie") return;
647
- headers[k] = v;
648
- });
649
- const cacheValue = {
650
- kind: "FETCH",
651
- data: {
652
- headers,
653
- body,
654
- url: response.url,
655
- status: cloned.status
656
- },
657
- tags,
658
- revalidate: revalidateSeconds
659
- };
660
- handler.set(cacheKey, cacheValue, {
661
- fetchCache: true,
662
- tags,
663
- revalidate: revalidateSeconds
664
- }).catch((err) => {
665
- console.error("[vinext] fetch cache write error:", err);
666
- });
667
- }
683
+ const cacheValue = await buildFetchCacheValue(response, tags, revalidateSeconds);
684
+ if (cacheValue) handler.set(cacheKey, cacheValue, {
685
+ fetchCache: true,
686
+ tags,
687
+ revalidate: revalidateSeconds
688
+ }).catch((err) => {
689
+ console.error("[vinext] fetch cache write error:", err);
690
+ });
668
691
  return response;
669
692
  };
670
693
  }
@@ -716,6 +739,7 @@ async function runWithFetchCache(fn) {
716
739
  uCtx.currentRequestTags = [];
717
740
  uCtx.currentFetchSoftTags = [];
718
741
  uCtx.dynamicFetchUrls = /* @__PURE__ */ new Set();
742
+ uCtx.refreshStaleFetchesInForeground = false;
719
743
  uCtx.isFetchDedupeActive = true;
720
744
  uCtx.currentFetchDedupeEntries = /* @__PURE__ */ new Map();
721
745
  }, fn);
@@ -726,6 +750,7 @@ async function runWithFetchCache(fn) {
726
750
  currentFetchCacheMode: null,
727
751
  currentForceDynamicFetchDefault: false,
728
752
  dynamicFetchUrls: /* @__PURE__ */ new Set(),
753
+ refreshStaleFetchesInForeground: false,
729
754
  isFetchDedupeActive: true,
730
755
  currentFetchDedupeEntries: /* @__PURE__ */ new Map()
731
756
  }, fn);
@@ -763,4 +788,4 @@ function getOriginalFetch() {
763
788
  return originalFetch;
764
789
  }
765
790
  //#endregion
766
- export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
791
+ export { _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground, withFetchCache };
@@ -1,6 +1,8 @@
1
1
  import { FormHTMLAttributes, useActionState } from "react";
2
2
 
3
3
  //#region src/shims/form.d.ts
4
+ type FormSubmitter = HTMLButtonElement | HTMLInputElement;
5
+ declare function createFormSubmitDestinationUrl(action: string, form: HTMLFormElement, submitter: FormSubmitter | null): string;
4
6
  declare const Form: import("react").ForwardRefExoticComponent<{
5
7
  /** Target URL for GET forms, or server action for POST forms */action: string | ((formData: FormData) => void | Promise<void>); /** Replace instead of push in history (default: false) */
6
8
  replace?: boolean; /** Scroll to top after navigation (default: true) */
@@ -14,6 +16,6 @@ declare const Form: import("react").ForwardRefExoticComponent<{
14
16
  * In pages dir, prefetch is not supported and the prop has no effect.
15
17
  */
16
18
  prefetch?: false | null;
17
- } & Omit<FormHTMLAttributes<HTMLFormElement>, "method" | "encType" | "target"> & import("react").RefAttributes<HTMLFormElement>>;
19
+ } & Omit<FormHTMLAttributes<HTMLFormElement>, "target" | "method" | "encType"> & import("react").RefAttributes<HTMLFormElement>>;
18
20
  //#endregion
19
- export { Form as default, useActionState };
21
+ export { createFormSubmitDestinationUrl, Form as default, useActionState };
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { VINEXT_MOUNTED_SLOTS_HEADER } from "../server/headers.js";
3
- import { isDangerousScheme } from "./url-safety.js";
3
+ import { assertSafeNavigationUrl } from "./url-safety.js";
4
4
  import { AppElementsWire } from "../server/app-elements-wire.js";
5
+ import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "../server/app-rsc-render-mode.js";
5
6
  import "../server/app-elements.js";
6
- import { toSameOriginPath, withBasePath } from "./url-utils.js";
7
+ import { withBasePath } from "./url-utils.js";
8
+ import { isBotUserAgent } from "../utils/html-limited-bots.js";
7
9
  import { createRscRequestHeaders, createRscRequestUrl } from "../server/app-rsc-cache-busting.js";
8
10
  import { hasAppNavigationRuntime } from "../client/navigation-runtime.js";
9
11
  import { getMountedSlotsHeader, getPrefetchInterceptionContext, getPrefetchedUrls, hasPrefetchCacheEntryForNavigation, navigateClientSide, prefetchRscResponse } from "./navigation.js";
@@ -37,18 +39,13 @@ const DISALLOWED_FORM_PROPS = [
37
39
  const SUPPORTED_FORM_ENCTYPE = "application/x-www-form-urlencoded";
38
40
  const SUPPORTED_FORM_METHOD = "GET";
39
41
  const SUPPORTED_FORM_TARGET = "_self";
40
- function isSafeAction(action) {
41
- if (isDangerousScheme(action)) return false;
42
- if (action.startsWith("//")) return false;
43
- if (/^https?:\/\//i.test(action)) {
44
- if (typeof window !== "undefined") try {
45
- return new URL(action).origin === window.location.origin;
46
- } catch {
47
- return false;
48
- }
42
+ function isPrefetchableAction(action) {
43
+ try {
44
+ const actionUrl = new URL(action, window.location.href);
45
+ return (actionUrl.protocol === "http:" || actionUrl.protocol === "https:") && actionUrl.origin === window.location.origin;
46
+ } catch {
49
47
  return false;
50
48
  }
51
- return true;
52
49
  }
53
50
  function getSubmitter(nativeEvent) {
54
51
  const submitter = nativeEvent && typeof nativeEvent === "object" && "submitter" in nativeEvent && nativeEvent.submitter instanceof Element ? nativeEvent.submitter : null;
@@ -103,7 +100,7 @@ function createFormSubmitDestinationUrl(action, form, submitter) {
103
100
  if (process.env.NODE_ENV !== "production") console.warn("<Form> only supports file inputs if `action` is a function. File inputs cannot be used if `action` is a string, because files cannot be encoded as search params.");
104
101
  targetUrl.searchParams.append(name, value.name);
105
102
  } else targetUrl.searchParams.append(name, value);
106
- return toSameOriginPath(targetUrl.href) ?? targetUrl.href;
103
+ return targetUrl.href;
107
104
  }
108
105
  function buildFormData(form, submitter) {
109
106
  if (!submitter) return new FormData(form);
@@ -137,7 +134,7 @@ const Form = forwardRef(function Form(props, ref) {
137
134
  useEffect(() => {
138
135
  if (typeof action !== "string") return;
139
136
  if (prefetch === false || process.env.NODE_ENV !== "production") return;
140
- if (!isSafeAction(action)) return;
137
+ if (!isPrefetchableAction(actionHref)) return;
141
138
  if (!hasAppNavigationRuntime()) return;
142
139
  const node = formRef.current;
143
140
  if (!node) return;
@@ -145,9 +142,13 @@ const Form = forwardRef(function Form(props, ref) {
145
142
  const observer = new IntersectionObserver((entries) => {
146
143
  for (const entry of entries) if (entry.isIntersecting || entry.intersectionRatio > 0) {
147
144
  (async () => {
145
+ if (isBotUserAgent(window.navigator?.userAgent ?? "")) return;
148
146
  const interceptionContext = getPrefetchInterceptionContext(actionHref);
149
147
  const mountedSlotsHeader = getMountedSlotsHeader();
150
- const headers = createRscRequestHeaders({ interceptionContext });
148
+ const headers = createRscRequestHeaders({
149
+ interceptionContext,
150
+ renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
151
+ });
151
152
  if (mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
152
153
  const rscUrl = await createRscRequestUrl(actionHref, headers);
153
154
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
@@ -161,8 +162,8 @@ const Form = forwardRef(function Form(props, ref) {
161
162
  priority: "low",
162
163
  purpose: "prefetch"
163
164
  }), interceptionContext, mountedSlotsHeader, void 0, {
164
- cacheForNavigation: true,
165
- optimisticRouteShell: false
165
+ cacheForNavigation: false,
166
+ optimisticRouteShell: true
166
167
  });
167
168
  })();
168
169
  observer.unobserve(node);
@@ -183,15 +184,7 @@ const Form = forwardRef(function Form(props, ref) {
183
184
  onSubmit,
184
185
  ...cleanRest
185
186
  });
186
- if (!isSafeAction(action)) {
187
- if (process.env.NODE_ENV !== "production") console.warn(`<Form> blocked unsafe action: ${action}`);
188
- return /* @__PURE__ */ jsx("form", {
189
- ref: setRefs,
190
- onSubmit,
191
- ...cleanRest
192
- });
193
- }
194
- async function handleSubmit(e) {
187
+ function handleSubmit(e) {
195
188
  if (onSubmit) {
196
189
  onSubmit(e);
197
190
  if (e.defaultPrevented) return;
@@ -204,23 +197,24 @@ const Form = forwardRef(function Form(props, ref) {
204
197
  }
205
198
  const effectiveAction = getEffectiveAction(submitter, actionHref);
206
199
  if (process.env.NODE_ENV !== "production" && submitter?.getAttribute("formaction") !== null) checkFormActionUrl(effectiveAction, "formAction");
207
- if (!isSafeAction(effectiveAction)) {
208
- if (process.env.NODE_ENV !== "production") console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);
209
- e.preventDefault();
210
- return;
211
- }
212
- e.preventDefault();
213
200
  const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);
214
- if (hasAppNavigationRuntime()) await navigateClientSide(url, replace ? "replace" : "push", scroll);
215
- else try {
216
- const Router = (await import("./router.js")).default;
217
- if (replace) await Router.replace(url, void 0, { scroll });
218
- else await Router.push(url, void 0, { scroll });
219
- } catch {
220
- if (replace) window.history.replaceState({}, "", url);
221
- else window.history.pushState({}, "", url);
222
- window.dispatchEvent(new PopStateEvent("popstate"));
223
- if (scroll) window.scrollTo(0, 0);
201
+ e.preventDefault();
202
+ if (hasAppNavigationRuntime()) {
203
+ assertSafeNavigationUrl(url);
204
+ navigateClientSide(url, replace ? "replace" : "push", scroll);
205
+ } else {
206
+ assertSafeNavigationUrl(url);
207
+ (async () => {
208
+ let Router;
209
+ try {
210
+ Router = (await import("./router.js")).default;
211
+ if (replace) await Router.replace(url, void 0, { scroll });
212
+ else await Router.push(url, void 0, { scroll });
213
+ } catch {
214
+ if (replace) window.location.replace(url);
215
+ else window.location.assign(url);
216
+ }
217
+ })();
224
218
  }
225
219
  }
226
220
  return /* @__PURE__ */ jsx("form", {
@@ -233,4 +227,4 @@ const Form = forwardRef(function Form(props, ref) {
233
227
  });
234
228
  });
235
229
  //#endregion
236
- export { Form as default, useActionState };
230
+ export { createFormSubmitDestinationUrl, Form as default, useActionState };
@@ -179,6 +179,12 @@ declare function getAndClearPendingCookies(): string[];
179
179
  */
180
180
  declare function getDraftModeCookieHeader(): string | null;
181
181
  declare function isDraftModeRequest(request: Request, draftModeSecret: string): boolean;
182
+ /**
183
+ * Read the active request's draft-mode state without recording request API usage.
184
+ * Internal cache implementations use this to bypass persistent reads and writes,
185
+ * matching Next.js's request-level `workStore.isDraftMode` guard.
186
+ */
187
+ declare function isDraftModeEnabled(): boolean;
182
188
  type DraftModeResult = {
183
189
  readonly isEnabled: boolean;
184
190
  enable(): void;
@@ -252,4 +258,4 @@ declare class RequestCookies {
252
258
  toString(): string;
253
259
  }
254
260
  //#endregion
255
- export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };
261
+ export { HeadersAccessPhase, HeadersContext, type RequestCookies, VinextHeadersShimState, applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };
@@ -1,7 +1,8 @@
1
1
  import { getOrCreateAls } from "./internal/als-registry.js";
2
2
  import { getRequestContext, isInsideUnifiedScope, runWithUnifiedStateMutation } from "./unified-request-context.js";
3
- import { FLIGHT_HEADERS, MIDDLEWARE_SET_COOKIE_HEADER, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER } from "../server/headers.js";
4
- import { buildRequestHeadersFromMiddlewareResponse } from "../server/middleware-request-headers.js";
3
+ import { MIDDLEWARE_SET_COOKIE_HEADER } from "../utils/protocol-headers.js";
4
+ import { FLIGHT_HEADERS, NEXT_HTML_REQUEST_ID_HEADER, NEXT_REQUEST_ID_HEADER } from "../server/headers.js";
5
+ import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
5
6
  import { serializeSetCookie, validateCookieAttributeValue, validateCookieName } from "./internal/cookie-serialize.js";
6
7
  import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
7
8
  import { createPprFallbackShellSuspensePromise } from "./ppr-fallback-shell.js";
@@ -609,6 +610,19 @@ function isDraftModeRequest(request, draftModeSecret) {
609
610
  if (!cookieHeader) return false;
610
611
  return parseEdgeRequestCookieHeader(cookieHeader).get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(draftModeSecret);
611
612
  }
613
+ /**
614
+ * Read the active request's draft-mode state without recording request API usage.
615
+ * Internal cache implementations use this to bypass persistent reads and writes,
616
+ * matching Next.js's request-level `workStore.isDraftMode` guard.
617
+ */
618
+ function isDraftModeEnabled() {
619
+ const context = _getState().headersContext;
620
+ if (!context) return false;
621
+ if (context.draftModeEnabled !== void 0) return context.draftModeEnabled;
622
+ const secret = context.draftModeSecret;
623
+ if (secret === void 0) return false;
624
+ return context.cookies.get(DRAFT_MODE_COOKIE) === validateDraftModeSecret(secret);
625
+ }
612
626
  function draftModeCookieAttributes() {
613
627
  if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") return "Path=/; HttpOnly; SameSite=Lax";
614
628
  return "Path=/; HttpOnly; SameSite=None; Secure";
@@ -762,4 +776,4 @@ var RequestCookies = class {
762
776
  }
763
777
  };
764
778
  //#endregion
765
- export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };
779
+ export { applyMiddlewareRequestHeaders, consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, cookies, draftMode, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersAccessPhase, getHeadersContext, headers, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, markDynamicUsage, markRenderRequestApiUsage, peekDynamicUsage, peekRenderRequestApiUsage, runWithConnectionProbe, runWithHeadersContext, setHeadersAccessPhase, setHeadersContext, suspendConnectionProbe, throwIfInsideCacheScope, throwIfStaticGenerationAccessError };