void 0.20.3 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/README.md +2 -2
  2. package/dist/agents-gni4eqBu.mjs +111 -0
  3. package/dist/auth-3sGB0zJ1.mjs +22 -0
  4. package/dist/{auth-DPl6kck4.mjs → auth-B9_D6ygs.mjs} +6 -241
  5. package/dist/auth-CAw7zHqj.mjs +2 -0
  6. package/dist/auth-client-BWBT8HLp.mjs +6 -0
  7. package/dist/auth-client-Bawdj38n.d.mts +7 -0
  8. package/dist/auth-client-react-7GFffu8R.d.mts +7 -0
  9. package/dist/auth-client-react-CMLwT2xI.mjs +6 -0
  10. package/dist/auth-client-solid-DyTFL4cq.d.mts +7 -0
  11. package/dist/auth-client-solid-UoreJWZG.mjs +6 -0
  12. package/dist/auth-client-svelte-Cv_WvrRk.mjs +6 -0
  13. package/dist/auth-client-svelte-zetW0KIH.d.mts +7 -0
  14. package/dist/auth-client-vue-CFk7Xbv3.mjs +6 -0
  15. package/dist/auth-client-vue-bChShbQP.d.mts +7 -0
  16. package/dist/{auth-cmd-CzwquNiP.mjs → auth-cmd-MkBG2u1f.mjs} +5 -5
  17. package/dist/{auth-link-ElDTgF7j.mjs → auth-link-Devmv96E.mjs} +5 -5
  18. package/dist/{better-auth-shared-DSCeohOK.d.mts → better-auth-shared-BoVwA5Vm.d.mts} +1 -6
  19. package/dist/{better-auth-shared-CYw1T3k4.mjs → better-auth-shared-syGYYmnY.mjs} +1 -1
  20. package/dist/{build-cmd-BpJe6boP.mjs → build-cmd-DsBGwtfs.mjs} +6 -4
  21. package/dist/{cache-D98YTqeE.mjs → cache-BMw8eMyF.mjs} +6 -4
  22. package/dist/{cancel-deploy-CPbEQLMG.mjs → cancel-deploy-B3_s9NIN.mjs} +5 -3
  23. package/dist/cf-access-rAZxzMkL.mjs +181 -0
  24. package/dist/cf-build-output-CTdlo6Rt.mjs +520 -0
  25. package/dist/cli/cf-compat.d.mts +1 -0
  26. package/dist/cli/cf-compat.mjs +934 -0
  27. package/dist/cli/cli.mjs +60 -38
  28. package/dist/cli/env-schema-probe.mjs +3 -3
  29. package/dist/client-DAAivdid.mjs +2 -0
  30. package/dist/{client-BQBrZoCX.mjs → client-PdAJ-F0t.mjs} +6 -12
  31. package/dist/{cloudflare-auth-6M5llVPC.mjs → cloudflare-auth-BCmTc1X_.mjs} +13 -44
  32. package/dist/{cloudflare-cmd-4RPGN3KB.mjs → cloudflare-cmd-D6PrKn7o.mjs} +4 -7
  33. package/dist/{cloudflare-connect-t1UU5svD.mjs → cloudflare-connect-DloREDlc.mjs} +6 -6
  34. package/dist/cloudflare-operations-BHNJVDbN.mjs +2 -0
  35. package/dist/{cloudflare-operations-BzWnlC1_.mjs → cloudflare-operations-CPEdHYhM.mjs} +37 -39
  36. package/dist/cloudflare-user-output-Q-k0QoNQ.mjs +20 -0
  37. package/dist/collect-DAUItMDS.mjs +2 -0
  38. package/dist/collect-DXHNWHcT.mjs +48 -0
  39. package/dist/config--T87TD8T.mjs +2 -0
  40. package/dist/{config-NOG_U1aK.mjs → config-BSe70f4T.mjs} +4 -6
  41. package/dist/config-DDIFxQYx.mjs +2 -0
  42. package/dist/{config-uNGuFsI2.mjs → config-Dxr6cTXn.mjs} +22 -37
  43. package/dist/config-DywxBLQC.d.mts +185 -0
  44. package/dist/config-entry.d.mts +6 -0
  45. package/dist/config-entry.mjs +7 -0
  46. package/dist/config-uP7ZDtVZ.mjs +21 -0
  47. package/dist/config-write-y3CBI_ux.mjs +60 -0
  48. package/dist/{connect-WCQZ_u3m.mjs → connect-BvC9kolB.mjs} +8 -6
  49. package/dist/{create-project-D0oXA090.mjs → create-project-C9lQhRzj.mjs} +8 -23
  50. package/dist/create-project-CI-17RVJ.mjs +2 -0
  51. package/dist/database-provider-Cx525bwX.mjs +6 -0
  52. package/dist/database-provider.mjs +1 -5
  53. package/dist/{db-DJ-9qs3S.mjs → db-R7IQgOv5.mjs} +48 -44
  54. package/dist/{delete-BZ4-WaGm.mjs → delete-CghI_NXn.mjs} +6 -4
  55. package/dist/deploy-CYPymbtG.mjs +2 -0
  56. package/dist/{deploy-BAhhcg5q.mjs → deploy-H968Lo4T.mjs} +751 -190
  57. package/dist/discover-BBzDZe_o.mjs +2 -0
  58. package/dist/{discover-xvfrgJeo.mjs → discover-C4O6YxVS.mjs} +3 -8
  59. package/dist/{dist-BrsS7cai.mjs → dist-4WkAWhWx.mjs} +1 -15
  60. package/dist/{dist-m40_XgNh.mjs → dist-Bn8Kodjp.mjs} +1 -1
  61. package/dist/dist-C5fND3R0.mjs +2 -0
  62. package/dist/dist-D7-nEOXi.mjs +2 -0
  63. package/dist/{output-B0cfNSx5.mjs → dist-Dn6nn2IU.mjs} +3 -926
  64. package/dist/{domain-BxAyhxXN.mjs → domain-CITt8lC-.mjs} +7 -5
  65. package/dist/{route-types-Da-DpyUp.mjs → drizzle-Beb2Am5S.mjs} +1 -280
  66. package/dist/{email-Ce6SQq-i.mjs → email-C5kaZXzJ.mjs} +2 -2
  67. package/dist/{email-Bj7Cvdwp.mjs → email-_8VmyX7V.mjs} +14 -12
  68. package/dist/{entry-DU3oDoQ3.mjs → entry-DdRFGK0y.mjs} +2 -2
  69. package/dist/{env-DP_EErve.mjs → env-DV4r3nHz.mjs} +9 -7
  70. package/dist/{env-DBKmK4vc.mjs → env-DX_v-Q-v.mjs} +1 -1
  71. package/dist/env-Yz4HcvHs.mjs +78 -0
  72. package/dist/env-helpers--wFmQ_5Q.mjs +136 -0
  73. package/dist/{env-types-BNPhro-M.mjs → env-types-CWDtqHgw.mjs} +6 -2
  74. package/dist/{env-validation-CF6KvTRf.mjs → env-validation-BsFEXps5.mjs} +19 -28
  75. package/dist/env-validation-DIDGM7h4.mjs +2 -0
  76. package/dist/fetch-CXDChK7B.mjs +18 -0
  77. package/dist/fetch-_SeGZao9.d.mts +57 -0
  78. package/dist/fetch-stream-AOByI7Ki.mjs +81 -0
  79. package/dist/fetch-stream-Bjf0hoZb.d.mts +49 -0
  80. package/dist/gen-BBiIZw6g.mjs +2 -0
  81. package/dist/{gen-B_wPnVTK.mjs → gen-CFOEEc-t.mjs} +13 -11
  82. package/dist/{generate-RTK8_kK1.mjs → generate-C0VY6RVf.mjs} +2 -2
  83. package/dist/{github-cmd-C-z_xRrQ.mjs → github-cmd-jYjha2LO.mjs} +6 -4
  84. package/dist/{handler-D1hLsObx.d.mts → handler-BXJTXd02.d.mts} +6 -1
  85. package/dist/handler-DghKr6dU.mjs +150 -0
  86. package/dist/head-D_QRR5Yd.mjs +112 -0
  87. package/dist/head-client-DzmJGN4C.mjs +90 -0
  88. package/dist/{headers-BAHwgHdW.mjs → headers-B_HBMgi0.mjs} +2 -2
  89. package/dist/{help-CwOX-zmI.mjs → help-C46mnlUS.mjs} +17 -12
  90. package/dist/help-CS_nAsWu.mjs +2 -0
  91. package/dist/index.d.mts +2 -20
  92. package/dist/index.mjs +116 -60
  93. package/dist/{init-BGktCXgA.mjs → init-CSXmvxKu.mjs} +49 -50
  94. package/dist/{link-D2kbqhWb.mjs → link-DxMOALXk.mjs} +7 -5
  95. package/dist/{list-CvkK_G7k.mjs → list-0wQs0oYg.mjs} +7 -5
  96. package/dist/live-CB1y5IuC.mjs +411 -0
  97. package/dist/live-CKiJilLr.d.mts +105 -0
  98. package/dist/local-d1-DzykTWY8.mjs +104 -0
  99. package/dist/{login-WIjNc77c.mjs → login-CKk5NX4d.mjs} +6 -11
  100. package/dist/login-Ch9cgWRF.mjs +2 -0
  101. package/dist/{logs-dLUFCapG.mjs → logs-hxWBSoej.mjs} +6 -4
  102. package/dist/migrate-CLty4mZR.mjs +2 -0
  103. package/dist/migrate-DcW8F2W8.mjs +285 -0
  104. package/dist/migration-handler-DM4clYj5.d.mts +51 -0
  105. package/dist/{neon-DHwd2zvC.mjs → neon-n74ta1Pr.mjs} +1 -1
  106. package/dist/{node-Ez5KW5rn.mjs → node-Cupyf7-s.mjs} +6 -6
  107. package/dist/{operator-auth-B3e08unv.mjs → operator-auth-BkVgJqv-.mjs} +2 -2
  108. package/dist/{operator-client-LUZnlnYk.mjs → operator-client-A0iex2yi.mjs} +2 -1
  109. package/dist/{operator-cmd-CKJ7xIRs.mjs → operator-cmd-BEUYhaHB.mjs} +6 -6
  110. package/dist/output-urU86XeT.mjs +146 -0
  111. package/dist/{package-json-CPoWX79C.mjs → package-json-iCbMg5XF.mjs} +1 -1
  112. package/dist/pages/client.d.mts +5 -2
  113. package/dist/pages/client.mjs +5 -3
  114. package/dist/pages/head-client.mjs +1 -89
  115. package/dist/pages/head.mjs +1 -111
  116. package/dist/pages/index.d.mts +2 -3
  117. package/dist/pages/index.mjs +7 -7
  118. package/dist/pages/islands-plugin.mjs +2 -2
  119. package/dist/pages/prefetch.d.mts +2 -30
  120. package/dist/pages/prefetch.mjs +1 -89
  121. package/dist/pages/protocol.d.mts +2 -2
  122. package/dist/pages/protocol.mjs +3 -3
  123. package/dist/pages/serialize.d.mts +2 -9
  124. package/dist/pages/serialize.mjs +1 -13
  125. package/dist/plan-BEZ8VJW0.mjs +256 -0
  126. package/dist/plan-DpuOr14e.mjs +2 -0
  127. package/dist/{platform-auth-config-CdVWRRJr.mjs → platform-auth-config-Df6yVw-e.mjs} +6 -6
  128. package/dist/{platform-auth-protection-Drl0qhrn.mjs → platform-auth-protection-Jb0yftay.mjs} +7 -5
  129. package/dist/{platform-auth-recovery-CmKEWpDo.mjs → platform-auth-recovery-DmRyIfW0.mjs} +6 -5
  130. package/dist/platform-cmd-C9Vt7m-d.mjs +2 -0
  131. package/dist/{platform-cmd-5q_k56xS.mjs → platform-cmd-DRxCOTwy.mjs} +8 -5
  132. package/dist/{platform-domain-4GiDlcqx.mjs → platform-domain-IjiXgrXJ.mjs} +4 -3
  133. package/dist/{platform-lifecycle-R9xAxvtG.mjs → platform-lifecycle-BquAaU-5.mjs} +208 -37
  134. package/dist/platform-lifecycle-CuJIZNvA.mjs +2 -0
  135. package/dist/{platform-management-BfWsXHEW.mjs → platform-management-CCQKGsq4.mjs} +8 -5
  136. package/dist/platform-management-Cgyed0WY.mjs +2 -0
  137. package/dist/{platform-recovery-CbK-I1FB.mjs → platform-recovery-DS8ih1SW.mjs} +3 -3
  138. package/dist/platform-registry-BJbgZLS1.mjs +431 -0
  139. package/dist/{plugin-inference-BDRfZngg.mjs → plugin-inference-DsvtJLll.mjs} +4 -4
  140. package/dist/prefetch-Bsc_Pb6c.mjs +90 -0
  141. package/dist/prefetch-Ce6la4EI.d.mts +31 -0
  142. package/dist/{prepare-blNRQvQl.mjs → prepare-CaUxODOU.mjs} +3 -2
  143. package/dist/prepare-D4CkM3_v.mjs +2 -0
  144. package/dist/{prepare-CtDJjoOj.mjs → prepare-pcWcxSCh.mjs} +13 -11
  145. package/dist/prerender-render-Cf_WDE9W.mjs +111 -0
  146. package/dist/prerender-render.mjs +1 -110
  147. package/dist/{preset-lAy0B0BQ.mjs → preset-Dowh9tTt.mjs} +16 -118
  148. package/dist/project-BEBFDFLz.mjs +2 -0
  149. package/dist/project-CWNIPoXc.mjs +209 -0
  150. package/dist/{project-cmd-CTdmnzvc.mjs → project-cmd-2lN--YAX.mjs} +18 -16
  151. package/dist/{project-paths-SK8nMHPp.mjs → project-paths-CKQ-Q5JS.mjs} +47 -14
  152. package/dist/project-slug-23TpquG4.mjs +8 -0
  153. package/dist/project-slug-DofjTFd-.mjs +2 -0
  154. package/dist/{project-team-CGxsQe3_.mjs → project-team-Dapn9HZn.mjs} +6 -4
  155. package/dist/{project-token-Cirx7uwZ.mjs → project-token-C90v9SJK.mjs} +6 -4
  156. package/dist/{project-tsconfig-Ql2XsSQp.mjs → project-tsconfig-CwfqUnVp.mjs} +2 -2
  157. package/dist/{protocol-C-pqYJjE.d.mts → protocol-ZH3jP4a7.d.mts} +1 -1
  158. package/dist/providers-BNKRacMr.d.mts +7 -0
  159. package/dist/provision-CNgEBkVA.mjs +3 -0
  160. package/dist/{provision-CSJOjjQk.mjs → provision-Cck2m3jJ.mjs} +11 -25
  161. package/dist/queues-BWKt1Xo4.d.mts +7 -0
  162. package/dist/{requests-4Nq59hOr.mjs → requests-CzX46I0i.mjs} +5 -3
  163. package/dist/resolve-project-BTotl8Nn.mjs +2 -0
  164. package/dist/{resolve-project--Vxawf7z.mjs → resolve-project-Xvis70DG.mjs} +2 -8
  165. package/dist/response-Tn7rU0MV.mjs +30 -0
  166. package/dist/{rollback-Dr7u0Ljx.mjs → rollback-BEeyc73H.mjs} +6 -4
  167. package/dist/{rolldown-runtime-rQ84J-ij.mjs → rolldown-runtime-DXIUcv95.mjs} +1 -10
  168. package/dist/route-types-Id82-veQ.mjs +280 -0
  169. package/dist/{local-d1-D2I6Ox5F.mjs → runner-BGVsGgkb.mjs} +6 -114
  170. package/dist/runner-CQs_cDSG.mjs +2 -0
  171. package/dist/runner-mysql-1o47achK.mjs +2 -0
  172. package/dist/{runner-mysql-7BPUNGmL.mjs → runner-mysql-BhwMk2Bm.mjs} +2 -9
  173. package/dist/{runner-pg-BkEza-dX.mjs → runner-pg-CJ_JeGF6.mjs} +2 -9
  174. package/dist/runner-pg-D7z01mQS.mjs +2 -0
  175. package/dist/runtime/ai.mjs +1 -1
  176. package/dist/runtime/auth-client-react.d.mts +2 -6
  177. package/dist/runtime/auth-client-react.mjs +1 -5
  178. package/dist/runtime/auth-client-solid.d.mts +2 -6
  179. package/dist/runtime/auth-client-solid.mjs +1 -5
  180. package/dist/runtime/auth-client-svelte.d.mts +2 -6
  181. package/dist/runtime/auth-client-svelte.mjs +1 -5
  182. package/dist/runtime/auth-client-vue.d.mts +2 -6
  183. package/dist/runtime/auth-client-vue.mjs +1 -5
  184. package/dist/runtime/auth-client.d.mts +2 -6
  185. package/dist/runtime/auth-client.mjs +1 -5
  186. package/dist/runtime/auth.mjs +1 -21
  187. package/dist/runtime/better-auth-mysql.d.mts +1 -1
  188. package/dist/runtime/better-auth-mysql.mjs +1 -1
  189. package/dist/runtime/better-auth-pg.d.mts +1 -1
  190. package/dist/runtime/better-auth-pg.mjs +1 -1
  191. package/dist/runtime/better-auth.d.mts +1 -1
  192. package/dist/runtime/better-auth.mjs +1 -1
  193. package/dist/runtime/client-react.d.mts +3 -3
  194. package/dist/runtime/client-react.mjs +3 -3
  195. package/dist/runtime/client-solid.d.mts +3 -3
  196. package/dist/runtime/client-solid.mjs +3 -3
  197. package/dist/runtime/client-svelte.d.mts +3 -3
  198. package/dist/runtime/client-svelte.mjs +3 -3
  199. package/dist/runtime/client-vue.d.mts +3 -3
  200. package/dist/runtime/client-vue.mjs +3 -3
  201. package/dist/runtime/client.d.mts +3 -3
  202. package/dist/runtime/client.mjs +3 -3
  203. package/dist/runtime/db.mjs +1 -1
  204. package/dist/runtime/durable.mjs +1 -1
  205. package/dist/runtime/email/testing.mjs +1 -1
  206. package/dist/runtime/env-helpers.mjs +1 -135
  207. package/dist/runtime/env-public-client.mjs +1 -1
  208. package/dist/runtime/env-public.mjs +2 -2
  209. package/dist/runtime/env.mjs +1 -77
  210. package/dist/runtime/fetch-stream.d.mts +2 -49
  211. package/dist/runtime/fetch-stream.mjs +2 -80
  212. package/dist/runtime/fetch.d.mts +2 -57
  213. package/dist/runtime/fetch.mjs +2 -17
  214. package/dist/runtime/handler.d.mts +1 -1
  215. package/dist/runtime/handler.mjs +1 -149
  216. package/dist/runtime/kv.mjs +1 -1
  217. package/dist/runtime/live-client.d.mts +1 -1
  218. package/dist/runtime/live-server.mjs +2 -2
  219. package/dist/runtime/live.d.mts +2 -104
  220. package/dist/runtime/live.mjs +1 -410
  221. package/dist/runtime/migration-handler-mysql.d.mts +1 -1
  222. package/dist/runtime/migration-handler-pg.d.mts +1 -1
  223. package/dist/runtime/migration-handler.d.mts +2 -50
  224. package/dist/runtime/queues.d.mts +2 -6
  225. package/dist/runtime/queues.mjs +1 -1
  226. package/dist/runtime/response.mjs +1 -29
  227. package/dist/runtime/sandbox.mjs +1 -1
  228. package/dist/runtime/sse.mjs +1 -171
  229. package/dist/runtime/storage.mjs +1 -1
  230. package/dist/runtime/validator.d.mts +1 -1
  231. package/dist/runtime/validator.mjs +1 -71
  232. package/dist/runtime/ws-server.d.mts +2 -2
  233. package/dist/runtime/ws-server.mjs +2 -2
  234. package/dist/runtime/ws.d.mts +2 -121
  235. package/dist/{scan-CpK-57ug.mjs → scan-DJbooZm2.mjs} +3 -3
  236. package/dist/{scan-BMH4rzlv.mjs → scan-DdDvRCU1.mjs} +8 -26
  237. package/dist/{secret-AcPi-FoA.mjs → secret-wnTel5Yw.mjs} +8 -6
  238. package/dist/serialize-BPvnNQuA.mjs +14 -0
  239. package/dist/serialize-CfSwWfF2.d.mts +10 -0
  240. package/dist/{skills-C0RvGjeE.mjs → skills-B-690E7h.mjs} +3 -2
  241. package/dist/sse-BaC1jXko.mjs +172 -0
  242. package/dist/{subcommand-prompt-Bmyn5Rlc.mjs → subcommand-prompt-Gj3VzLIh.mjs} +2 -1
  243. package/dist/sveltekit.d.mts +2 -1
  244. package/dist/sveltekit.mjs +3 -2
  245. package/dist/validate-DqJ33oHj.mjs +2 -0
  246. package/dist/validate-qNhV00PD.mjs +180 -0
  247. package/dist/validator-BTOu0fB0.mjs +72 -0
  248. package/dist/{wrangler--imS8n0d.mjs → wrangler-D01qs6VB.mjs} +259 -71
  249. package/dist/ws-BwcqizuH.d.mts +122 -0
  250. package/dist/{yarn-pnp-DxSInkzL.mjs → yarn-pnp-CVEc3gE7.mjs} +1 -1
  251. package/package.json +19 -8
  252. package/skills/void/SKILL.md +6 -4
  253. package/skills/void/docs/guide/ai.md +3 -3
  254. package/skills/void/docs/guide/app-types.md +12 -11
  255. package/skills/void/docs/guide/auth.md +2 -2
  256. package/skills/void/docs/guide/database/d1.md +1 -1
  257. package/skills/void/docs/guide/database/mysql.md +1 -1
  258. package/skills/void/docs/guide/database/postgresql.md +3 -3
  259. package/skills/void/docs/guide/deployment.md +2 -2
  260. package/skills/void/docs/guide/durable-state.md +2 -2
  261. package/skills/void/docs/guide/edge/headers.md +3 -3
  262. package/skills/void/docs/guide/edge/prerendering.md +1 -1
  263. package/skills/void/docs/guide/edge/redirects.md +4 -4
  264. package/skills/void/docs/guide/edge/revalidation.md +6 -6
  265. package/skills/void/docs/guide/edge/rewrites.md +28 -27
  266. package/skills/void/docs/guide/edge/static-assets.md +1 -1
  267. package/skills/void/docs/guide/email.md +15 -15
  268. package/skills/void/docs/guide/env-migration.md +1 -1
  269. package/skills/void/docs/guide/index.md +1 -1
  270. package/skills/void/docs/guide/pages-routing/head.md +1 -1
  271. package/skills/void/docs/guide/platform/administration/access.md +13 -5
  272. package/skills/void/docs/guide/platform/administration/projects.md +3 -1
  273. package/skills/void/docs/guide/platform/installation/ci.md +3 -0
  274. package/skills/void/docs/guide/platform/installation/credentials.md +15 -5
  275. package/skills/void/docs/guide/platform/installation/prerequisites.md +2 -0
  276. package/skills/void/docs/guide/platform/installation/setup.md +1 -1
  277. package/skills/void/docs/guide/remote-dev.md +2 -2
  278. package/skills/void/docs/guide/sandboxes.md +1 -1
  279. package/skills/void/docs/guide/ssg.md +1 -1
  280. package/skills/void/docs/guide/websockets.md +1 -1
  281. package/skills/void/docs/integrations/cloudflare.md +86 -84
  282. package/skills/void/docs/integrations/frameworks/analog.md +14 -9
  283. package/skills/void/docs/integrations/frameworks/astro.md +14 -10
  284. package/skills/void/docs/integrations/frameworks/nuxt.md +14 -9
  285. package/skills/void/docs/integrations/frameworks/overview.md +35 -29
  286. package/skills/void/docs/integrations/frameworks/react-router.md +1 -1
  287. package/skills/void/docs/integrations/frameworks/sveltekit.md +33 -30
  288. package/skills/void/docs/integrations/frameworks/tanstack-start.md +1 -1
  289. package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -5
  290. package/skills/void/docs/reference/api.md +21 -4
  291. package/skills/void/docs/reference/cli.md +32 -23
  292. package/skills/void/docs/reference/config.md +56 -33
  293. package/skills/void/docs/reference/structure.md +2 -2
  294. package/dist/validate-tBBN_dXH.mjs +0 -505
@@ -1,51 +1,63 @@
1
- import { n as __exportAll, r as __toESM, t as __commonJSMin } from "./rolldown-runtime-rQ84J-ij.mjs";
2
- import { c as relative, i as extname, l as resolve, n as dirname, o as join, s as normalize, t as basename } from "./dist-BrsS7cai.mjs";
3
- import { A as outro, B as ensureCloudflaredToken, D as log$1, E as intro, H as ensurePlatformProxyAccess, I as isCancel, M as select, c as import_picocolors$1, d as formatCloudflareUserMessage, ft as require_picocolors, i as createSpinner, k as note, r as cliTitle, w as confirm } from "./output-B0cfNSx5.mjs";
4
- import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-SK8nMHPp.mjs";
5
- import { a as scanQueuesSync, i as scanWebSocketRoutesSync, o as scanJobsSync, r as scanRoutes, s as findVoidAuthConfig } from "./scan-BMH4rzlv.mjs";
1
+ import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-DXIUcv95.mjs";
2
+ import { a as join, l as relative, n as dirname, o as normalize, r as extname, t as basename, u as resolve } from "./dist-4WkAWhWx.mjs";
3
+ import { c as import_picocolors$1, d as require_picocolors, i as createSpinner, r as cliTitle } from "./output-urU86XeT.mjs";
4
+ import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-CKQ-Q5JS.mjs";
5
+ import { t as findVoidAuthConfig } from "./config-uP7ZDtVZ.mjs";
6
6
  import { i as trustedCloudflareWorkerAccessHeaders, r as scopedAccessCredentials, t as cfAccessHeaders } from "./cf-access-DRsQRe6k.mjs";
7
- import { E as writeProjectConfig, S as readProjectConfig, d as isStagingMode, l as getToken, o as getApiUrl, s as getProxyUrl, u as getTokenSource, w as writeDeploymentPlatform, x as readDeploymentPlatform, y as attachSelectedPlatform } from "./auth-DPl6kck4.mjs";
8
- import { A as writeWranglerPublishedTrafficSnapshot, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, M as isSandboxEnabled, N as requiresSandboxPlatformImage, P as resolveSandboxConfig, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, f as findBindingNameOwner, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, k as writeProvisionedWranglerConfig, l as ensureWranglerCompat, o as acknowledgeWranglerManagedQueueRemovals, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler--imS8n0d.mjs";
9
- import { c as getDatabaseDialect, f as readConfig, l as isNodeTarget, p as resolveBindingNames } from "./config-uNGuFsI2.mjs";
7
+ import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl, u as isStagingMode } from "./auth-B9_D6ygs.mjs";
8
+ import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-rAZxzMkL.mjs";
9
+ import { d as writeProjectConfig, i as readDeploymentPlatform, l as writeDeploymentPlatform, o as readProjectConfig, t as attachSelectedPlatform } from "./project-CWNIPoXc.mjs";
10
+ import { d as isNodeTarget, h as resolveBindingNames, m as readConfig, u as getDatabaseDialect } from "./config-Dxr6cTXn.mjs";
11
+ import { A as writeWranglerPublishedTrafficSnapshot, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, L as materializeCloudflareConfig, M as isSandboxEnabled, N as requiresSandboxPlatformImage, P as resolveSandboxConfig, R as persistCloudflareConfig, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, V as stashCloudflareDeployPointer, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, f as findBindingNameOwner, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, k as writeProvisionedWranglerConfig, l as ensureWranglerCompat, o as acknowledgeWranglerManagedQueueRemovals, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler-D01qs6VB.mjs";
10
12
  import { i as voidWarn, r as voidLog } from "./log-ChfPKsVd.mjs";
11
- import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-BAHwgHdW.mjs";
12
- import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework } from "./plugin-inference-BDRfZngg.mjs";
13
- import { o as validateSsrEntry } from "./entry-DU3oDoQ3.mjs";
14
- import { a as buildMigrationPlanBundle, c as collectMigrations, r as validateMigrations, t as assertJournalCoherence } from "./validate-tBBN_dXH.mjs";
13
+ import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-B_HBMgi0.mjs";
14
+ import { a as scanQueuesSync, i as scanWebSocketRoutesSync, o as scanJobsSync, r as scanRoutes } from "./scan-DdDvRCU1.mjs";
15
+ import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework } from "./plugin-inference-DsvtJLll.mjs";
16
+ import { o as validateSsrEntry } from "./entry-DdRFGK0y.mjs";
17
+ import { t as collectMigrations } from "./collect-DXHNWHcT.mjs";
18
+ import { r as buildMigrationPlanBundle } from "./plan-BEZ8VJW0.mjs";
15
19
  import { r as scanWranglerDotenvKeys } from "./dotenv-VQxupEUv.mjs";
16
- import { t as discoverSchema } from "./discover-xvfrgJeo.mjs";
17
- import { t as findEnvFile } from "./env-types-BNPhro-M.mjs";
18
- import { a as deriveSelfHostEnvContextFromVars, c as fetchRemoteSecretNames, d as readEmittedWorkerVars, f as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as formatEnvReport, n as SelfHostFirstDeployError, o as dischargeSelfHostEnvContext, p as validateProdEnv, r as SelfHostSchemaError, t as SelfHostEnvValidationError, u as listSelfHostSecretNames } from "./env-validation-CF6KvTRf.mjs";
19
- import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-DBKmK4vc.mjs";
20
- import { n as writeDrizzleConfig } from "./config-NOG_U1aK.mjs";
21
- import { t as runMySqlMigrations } from "./runner-mysql-7BPUNGmL.mjs";
22
- import { t as runPgMigrations } from "./runner-pg-BkEza-dX.mjs";
20
+ import { t as discoverSchema } from "./discover-C4O6YxVS.mjs";
21
+ import { t as findEnvFile } from "./env-types-CWDtqHgw.mjs";
22
+ import { d as formatEnvReport, f as listSelfHostSecretNames, g as validateProdEnv, h as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as dischargeSelfHostEnvContext, n as SelfHostFirstDeployError, p as readEmittedWorkerVars, r as SelfHostSchemaError, s as deriveSelfHostEnvContextFromVars, t as SelfHostEnvValidationError, u as fetchRemoteSecretNames, v as readGeneratedWranglerConfigFile } from "./env-validation-BsFEXps5.mjs";
23
+ import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-DX_v-Q-v.mjs";
24
+ import { E as confirm, I as select, N as note, O as intro, P as outro, W as isCancel, j as log$1 } from "./dist-Dn6nn2IU.mjs";
25
+ import { t as writeDrizzleConfig } from "./config-BSe70f4T.mjs";
26
+ import { i as runMySqlMigrations } from "./runner-mysql-BhwMk2Bm.mjs";
27
+ import { i as runPgMigrations } from "./runner-pg-CJ_JeGF6.mjs";
23
28
  import { n as openMigrationValidationDatabase, t as SqliteMigrationError } from "./sqlite-validation-BzKMWnO4.mjs";
24
- import { t as scanPages } from "./scan-CpK-57ug.mjs";
25
- import { renderPrerenderPaths } from "./prerender-render.mjs";
26
- import { a as scanEmailHandlersSync, r as hasEmailHandlers } from "./email-Ce6SQq-i.mjs";
27
- import { a as isExpiredTokenError, i as isCliOutdatedError, n as PlatformClient, o as parsePlatformErrorBody, s as platformErrorMessage, t as PlatformApiError } from "./client-BQBrZoCX.mjs";
28
- import { a as resolveProjectCommand, i as hasBackendFiles, n as detectPreset, o as resolveWranglerArgv, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-lAy0B0BQ.mjs";
29
- import { i as cloudflareKeyringNeedsTerminal, s as ensureCloudflareAuthentication, t as CloudflareAuthenticationError } from "./cloudflare-auth-6M5llVPC.mjs";
30
- import { n as createCloudflareEmptyDomainPublisher } from "./cloudflare-operations-BzWnlC1_.mjs";
31
- import { i as promptProjectSetupAction, n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-D0oXA090.mjs";
32
- import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project--Vxawf7z.mjs";
29
+ import { i as validateMigrations, t as assertJournalCoherence } from "./validate-qNhV00PD.mjs";
30
+ import { t as scanPages } from "./scan-DJbooZm2.mjs";
31
+ import { t as renderPrerenderPaths } from "./prerender-render-Cf_WDE9W.mjs";
32
+ import { a as scanEmailHandlersSync, r as hasEmailHandlers } from "./email-C5kaZXzJ.mjs";
33
+ import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-CTdlo6Rt.mjs";
34
+ import { n as getPackageDir } from "./agents-gni4eqBu.mjs";
35
+ import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-PdAJ-F0t.mjs";
36
+ import { a as resolveProjectCommand, i as hasBackendFiles, n as detectPreset, o as resolveWranglerArgv, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-Dowh9tTt.mjs";
37
+ import { o as ensureCloudflareAuthentication, r as cloudflareAuthNeedsTerminal, t as CloudflareAuthenticationError } from "./cloudflare-auth-BCmTc1X_.mjs";
38
+ import { n as writeVoidProjectConfig } from "./config-write-y3CBI_ux.mjs";
39
+ import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-DcW8F2W8.mjs";
40
+ import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-CPEdHYhM.mjs";
41
+ import { t as formatCloudflareUserMessage } from "./cloudflare-user-output-Q-k0QoNQ.mjs";
42
+ import { a as promptProjectSetupAction, i as promptProjectSelection, r as promptAndCreateProject } from "./create-project-C9lQhRzj.mjs";
43
+ import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-Xvis70DG.mjs";
33
44
  import { t as collectGitDeployMetadata } from "./git-metadata-D-gurjzG.mjs";
34
- import { n as promptForLoginToken } from "./login-WIjNc77c.mjs";
45
+ import { t as promptForLoginToken } from "./login-CKk5NX4d.mjs";
35
46
  import { createRequire } from "node:module";
36
- import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
37
- import { fileURLToPath, pathToFileURL } from "node:url";
47
+ import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
48
+ import { fileURLToPath } from "node:url";
38
49
  import { createDeployArtifact, createDeployUploadPayload } from "@void/deploy-core";
39
50
  import { createHash, randomBytes } from "node:crypto";
40
- import { homedir } from "node:os";
51
+ import { homedir, tmpdir } from "node:os";
41
52
  import { execFile, execSync, spawnSync } from "node:child_process";
42
53
  import { applyEdits, modify, parse } from "jsonc-parser";
54
+ import { isDeepStrictEqual } from "node:util";
43
55
  import { build } from "vite";
44
56
  import { Minimatch } from "minimatch";
45
- import { isDeepStrictEqual } from "node:util";
46
- import { activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, createCloudflareMetadataRunner, encodeCloudflareVersionMessage, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseRootWranglerConfig, parseRootWranglerConfig as parseRootWranglerConfig$1, readBindingFieldPresence, readCloudflareTriggerConfig, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig } from "@void/deploy-cloudflare";
47
- import { hash } from "blake3-jit";
57
+ import { activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, encodeCloudflareVersionMessage, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseRootWranglerConfig, parseRootWranglerConfig as parseRootWranglerConfig$1, readBindingFieldPresence, readCloudflareTriggerConfig, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig } from "@void/deploy-cloudflare";
58
+ import { getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
48
59
  import ignore from "ignore";
60
+ import { hash } from "blake3-jit";
49
61
  //#region src/asset-routing.ts
50
62
  function isApiRoutePattern(pattern) {
51
63
  return pattern === "/api" || pattern.startsWith("/api/");
@@ -96,7 +108,7 @@ function resolveAssetRoutingPolicy(inputs) {
96
108
  //#region src/cli/email-cloudflare.ts
97
109
  /** The `send_email` binding name Void provisions and the runtime reads. */
98
110
  const SEND_EMAIL_BINDING = "SEND_EMAIL";
99
- /** The root-config `vars` key carrying `void.json` `email.from` into the worker. */
111
+ /** The root-config `vars` key carrying `void.config.ts` `email.from` into the worker. */
100
112
  const EMAIL_FROM_VAR = "__VOID_EMAIL_FROM";
101
113
  /** Cloudflare's public API base — the same one `wrangler` targets by default. */
102
114
  const CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4";
@@ -133,17 +145,17 @@ function findEmailConfigConflicts(config) {
133
145
  try {
134
146
  owner = findBindingNameOwner(config, field, name);
135
147
  } catch (err) {
136
- conflicts.add(`wrangler.jsonc: ${err instanceof Error ? err.message : String(err)}`);
148
+ conflicts.add(`Cloudflare config: ${err instanceof Error ? err.message : String(err)}`);
137
149
  return;
138
150
  }
139
- if (owner !== void 0) conflicts.add(`wrangler.jsonc already uses ${name} as a ${owner} binding; rename it (Void writes ${name} into ${field})`);
151
+ if (owner !== void 0) conflicts.add(`Cloudflare config already uses ${name} as a ${owner} binding; rename it in void.config.ts (Void writes ${name} into ${field})`);
140
152
  };
141
153
  check("send_email", SEND_EMAIL_BINDING);
142
154
  check("vars", EMAIL_FROM_VAR);
143
155
  return [...conflicts];
144
156
  }
145
157
  /**
146
- * Host part of `email.from`, lowercased; `null` when it is not `local@host`. `void.json`
158
+ * Host part of `email.from`, lowercased; `null` when it is not `local@host`. `void.config.ts`
147
159
  * also accepts the display-name form (`Acme <noreply@mail.acme.com>`, see `config.ts`),
148
160
  * so the address inside `<…>` is read when present.
149
161
  *
@@ -663,7 +675,7 @@ async function preflightEmail(inputs) {
663
675
  state: "foreign",
664
676
  foreignName: names[0]
665
677
  };
666
- block("all", `wrangler.jsonc already has a send_email binding named ${JSON.stringify(names[0])}; rename it to ${SEND_EMAIL_BINDING} (a second binding would be silent)`);
678
+ block("all", `Cloudflare config already has a send_email binding named ${JSON.stringify(names[0])}; rename it to ${SEND_EMAIL_BINDING} in void.config.ts (a second binding would be silent)`);
667
679
  }
668
680
  if (inputs.existingAddresses !== void 0 && inputs.existingAddresses !== null) {
669
681
  const existing = Array.isArray(inputs.existingAddresses) ? inputs.existingAddresses.map((a) => typeof a === "string" ? a.toLowerCase() : String(a)) : ["(not an array)"];
@@ -674,7 +686,7 @@ async function preflightEmail(inputs) {
674
686
  state: "foreign",
675
687
  foreign: unknown
676
688
  };
677
- block("all", `wrangler.jsonc addresses holds entries Void did not derive (${unknown.join(", ")}); remove ${unknown.map((a) => JSON.stringify(a)).join(", ")} from addresses, or manage addresses by hand and unset email.from — skipping email setup this deploy`);
689
+ block("all", `Cloudflare addresses holds entries Void did not derive (${unknown.join(", ")}); remove ${unknown.map((a) => JSON.stringify(a)).join(", ")} from cloudflare.addresses in void.config.ts, or manage addresses by hand and unset email.from — skipping email setup this deploy`);
678
690
  } else {
679
691
  pre.addressesOwnership = {
680
692
  state: "mine",
@@ -710,7 +722,7 @@ function renderEmailChecklist(pre) {
710
722
  const row = (label, value, note = "") => {
711
723
  lines.push(` ${pad(label, 10)}${note ? `${pad(value, 23)}${note}` : value}`);
712
724
  };
713
- row("domain", pre.domain, "(void.json email.from)");
725
+ row("domain", pre.domain, "(void.config.ts email.from)");
714
726
  const session = [pre.session.accountName ? `account ${pre.session.accountName} (${shortId(pre.accountId)})` : `account ${shortId(pre.accountId)}`, pre.session.authType && pre.session.authType !== "OAuth Token" ? `session ${pre.session.email ? `${pre.session.email} ` : ""}(${pre.session.authType})` : pre.session.email ? `session ${pre.session.email}` : null].filter(Boolean).join(" · ");
715
727
  row("zone", pre.zone.state === "found" ? apex : `${apex} ${pre.zone.state}`, session);
716
728
  if (pre.mode === "subdomain") row("apex MX", pre.apexMx.exchanges[0] ?? (pre.apexMx.state === "unknown" ? "unknown" : "none"), "left alone — mail lives on the subdomain");
@@ -745,7 +757,7 @@ function renderEmailChecklist(pre) {
745
757
  if (pre.binding.state !== "present") parts.push(`send_email: [{ name: "${SEND_EMAIL_BINDING}" }]`);
746
758
  if (pre.addressesStale) parts.push(pre.addresses.length > 0 ? `addresses: ${JSON.stringify(pre.addresses)}` : "addresses: (removed)");
747
759
  if (pre.sender.state !== "ready") parts.push(`vars.${EMAIL_FROM_VAR}: ${JSON.stringify(pre.from)}`);
748
- if (parts.length > 0) change("wrangler.jsonc", parts.join(", "));
760
+ if (parts.length > 0) change("Cloudflare config", parts.join(", "));
749
761
  for (const address of pre.rules.absent) change("routing rule (created on deploy)", `${address} → ${pre.workerName}`);
750
762
  for (const foreign of pre.rules.foreign) warn(foreign.address, `already routed to ${foreign.owner}; left alone, not in addresses`);
751
763
  for (const refused of pre.derived.refused) warn(refused.handler, refused.reason);
@@ -930,7 +942,7 @@ async function applyEmailSetup(pre, inputs) {
930
942
  result.patch.addresses = null;
931
943
  if (result.addressesWithheld && pre.addresses.length > 0) lines.push(` ! config addresses withheld this run (${bearerFailed ? "session-bearer step failed" : "routing not ready"}); no routing rule is created for ${pre.addresses.join(", ")}`);
932
944
  }
933
- if (result.patch.sendEmail || result.patch.addresses !== void 0) lines.push(" ✔ config wrangler.jsonc updated");
945
+ if (result.patch.sendEmail || result.patch.addresses !== void 0) lines.push(" ✔ config void.lock.json updated");
934
946
  result.inboundReady = result.routingReady && result.subaddressingReady && !result.addressesWithheld;
935
947
  return result;
936
948
  }
@@ -1643,9 +1655,7 @@ async function createCloudflarePrerenderRunner(options) {
1643
1655
  voidStaging,
1644
1656
  remoteMode
1645
1657
  });
1646
- const wranglerUrl = import.meta.resolve("wrangler/package.json");
1647
- const miniflarePath = createRequire(wranglerUrl).resolve("miniflare");
1648
- const { Miniflare, convertV4MiniflareOptions } = await import(pathToFileURL(miniflarePath).href);
1658
+ const { Miniflare, convertV4MiniflareOptions } = await import("miniflare");
1649
1659
  const mfOptions = {
1650
1660
  modules: collectPrerenderWorkerModules(workerDir, workerMain),
1651
1661
  modulesRoot: workerDir,
@@ -1845,6 +1855,405 @@ async function prerenderPagesNode(options) {
1845
1855
  return result;
1846
1856
  }
1847
1857
  //#endregion
1858
+ //#region src/cli/cf-version-runner.ts
1859
+ function failed(message) {
1860
+ return {
1861
+ status: 1,
1862
+ stdout: "",
1863
+ stderr: message
1864
+ };
1865
+ }
1866
+ function flag(args, name) {
1867
+ const index = args.indexOf(name);
1868
+ return index < 0 ? void 0 : args[index + 1];
1869
+ }
1870
+ function parseJson(value) {
1871
+ try {
1872
+ return JSON.parse(value);
1873
+ } catch {
1874
+ return null;
1875
+ }
1876
+ }
1877
+ function record(value) {
1878
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1879
+ }
1880
+ function safePositional(value) {
1881
+ return typeof value === "string" && value.length > 0 && !value.startsWith("-") && ![...value].some((character) => {
1882
+ const code = character.charCodeAt(0);
1883
+ return code < 32 || code === 127;
1884
+ });
1885
+ }
1886
+ /** Prevent cf's prebuilt uploader from creating a resource as a side effect. */
1887
+ function createCfResourceVerifier(options) {
1888
+ return async (directory) => {
1889
+ const worker = parseJson(readFileSync(getWorkerConfigPath(directory), "utf8"));
1890
+ if (!record(worker) || worker.env !== void 0 && !record(worker.env)) return failed("The Cloudflare Worker bindings were not readable.");
1891
+ for (const [bindingName, value] of Object.entries(worker.env ?? {})) {
1892
+ if (!record(value)) return failed(`Cloudflare binding ${bindingName} was not readable.`);
1893
+ const identifier = (field) => safePositional(value[field]) ? value[field] : null;
1894
+ if (value.type === "kv" || value.type === "d1" || value.type === "flagship") {
1895
+ if (!identifier("id")) return failed(`Cloudflare binding ${bindingName} has no ID; refusing automatic provisioning.`);
1896
+ continue;
1897
+ }
1898
+ if (value.type === "queue") {
1899
+ const name = identifier("name");
1900
+ if (!name) return failed(`Cloudflare Queue binding ${bindingName} has no name.`);
1901
+ if (!options.verifyCompatibilityRunner()) return failed("The Cloudflare resource verifier changed during deployment.");
1902
+ const found = await Promise.resolve(options.runWrangler([
1903
+ "queues",
1904
+ "info",
1905
+ name,
1906
+ "-c",
1907
+ options.configPath,
1908
+ "--env="
1909
+ ], { capture: true }));
1910
+ if (found.status !== 0 || found.signal || found.error || found.stdout.trim() !== `Queue Name: ${name}`) return failed(`Cloudflare Queue ${name} is unavailable; refusing automatic provisioning.`);
1911
+ continue;
1912
+ }
1913
+ const resource = value.type === "r2" ? {
1914
+ kind: "R2 bucket",
1915
+ field: "name",
1916
+ command: [
1917
+ "r2",
1918
+ "buckets",
1919
+ "get"
1920
+ ],
1921
+ response: "name"
1922
+ } : value.type === "dispatch-namespace" ? {
1923
+ kind: "dispatch namespace",
1924
+ field: "namespace",
1925
+ command: [
1926
+ "workers-for-platforms",
1927
+ "dispatch-namespaces",
1928
+ "get"
1929
+ ],
1930
+ response: "namespace_name"
1931
+ } : value.type === "ai-search-namespace" ? {
1932
+ kind: "AI Search namespace",
1933
+ field: "namespace",
1934
+ command: [
1935
+ "ai-search",
1936
+ "namespace",
1937
+ "get"
1938
+ ],
1939
+ response: "name"
1940
+ } : value.type === "agent-memory" ? {
1941
+ kind: "Agent Memory namespace",
1942
+ field: "namespace",
1943
+ command: ["agent-memory", "get-namespace"],
1944
+ response: "name"
1945
+ } : null;
1946
+ if (!resource) continue;
1947
+ const name = identifier(resource.field);
1948
+ if (!name) return failed(`Cloudflare ${resource.kind} binding ${bindingName} has no name.`);
1949
+ const jurisdiction = value.type === "r2" ? value.jurisdiction : void 0;
1950
+ if (jurisdiction !== void 0 && !safePositional(jurisdiction)) return failed(`Cloudflare R2 binding ${bindingName} has an invalid jurisdiction.`);
1951
+ const result = options.runCf([
1952
+ ...resource.command,
1953
+ name,
1954
+ ...jurisdiction ? ["--cf-r2-jurisdiction", jurisdiction] : []
1955
+ ], {
1956
+ cwd: directory,
1957
+ capture: true
1958
+ });
1959
+ const body = parseJson(result.stdout);
1960
+ if (result.status !== 0 || result.signal || result.error || !record(body) || body[resource.response] !== name) return failed(`Cloudflare ${resource.kind} ${name} is unavailable; refusing automatic provisioning.`);
1961
+ }
1962
+ return {
1963
+ status: 0,
1964
+ stdout: "",
1965
+ stderr: ""
1966
+ };
1967
+ };
1968
+ }
1969
+ /** Run the pinned package-local cf binary with Void's existing Cloudflare session. */
1970
+ function createCfCommand(options) {
1971
+ const cf = join(dirname(fileURLToPath(import.meta.resolve("cf/package.json"))), "bin", "cf");
1972
+ return (args, run) => {
1973
+ if (!options.verifyUploader()) return failed("The Cloudflare uploader changed during deployment.");
1974
+ const env = {
1975
+ ...options.env(options.accountId, options.apiBaseUrl),
1976
+ CF_DELEGATION: "1"
1977
+ };
1978
+ if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) env.NODE_USE_ENV_PROXY = "1";
1979
+ if (options.token) env.CLOUDFLARE_API_TOKEN = options.token;
1980
+ const result = spawnSync(process.execPath, [cf, ...args], {
1981
+ cwd: run.cwd,
1982
+ env,
1983
+ shell: false,
1984
+ windowsHide: true,
1985
+ encoding: "utf8",
1986
+ maxBuffer: 268435456,
1987
+ stdio: run.capture ? [
1988
+ "ignore",
1989
+ "pipe",
1990
+ "pipe"
1991
+ ] : "inherit"
1992
+ });
1993
+ return {
1994
+ status: typeof result.status === "number" ? result.status : 1,
1995
+ stdout: result.stdout ?? "",
1996
+ stderr: (result.stderr ?? "").replace(/\[(\d{4,})\]/g, "[code: $1]"),
1997
+ signal: result.signal ?? null,
1998
+ error: result.error?.message ?? null
1999
+ };
2000
+ };
2001
+ }
2002
+ /**
2003
+ * Adapt the stable activation protocol to cf's prebuilt and API commands.
2004
+ * The protocol keeps the existing preview, inheritance, traffic and rollback checks.
2005
+ */
2006
+ function createCfVersionRunner(options) {
2007
+ const { output, workerName, runCf } = options;
2008
+ const run = (args, capture, cwd = output.directory) => runCf(args, {
2009
+ cwd,
2010
+ capture
2011
+ });
2012
+ const verifyResources = async (directory) => {
2013
+ try {
2014
+ return await options.verifyResources(directory);
2015
+ } catch {
2016
+ return failed("Cloudflare resources could not be verified before upload.");
2017
+ }
2018
+ };
2019
+ return async (args, command) => {
2020
+ if (args[0] === "deployments" && args[1] === "status") {
2021
+ const result = run([
2022
+ "workers",
2023
+ "deployments",
2024
+ "list",
2025
+ "--worker",
2026
+ workerName
2027
+ ], true);
2028
+ if (result.status !== 0) return result;
2029
+ const body = parseJson(result.stdout);
2030
+ const deployments = record(body) ? body.deployments : void 0;
2031
+ if (Array.isArray(deployments) && deployments.length === 0) return failed("The Cloudflare Worker has no deployments.");
2032
+ if (!Array.isArray(deployments) || !record(deployments[0])) return failed("The Cloudflare Worker deployment was not readable.");
2033
+ return {
2034
+ ...result,
2035
+ stdout: JSON.stringify(deployments[0])
2036
+ };
2037
+ }
2038
+ if (args[0] === "versions" && args[1] === "list") {
2039
+ const pageSize = 10;
2040
+ const readPage = (page) => {
2041
+ const result = run([
2042
+ "workers",
2043
+ "versions",
2044
+ "list",
2045
+ "--worker-id",
2046
+ workerName,
2047
+ "--per-page",
2048
+ String(pageSize),
2049
+ "--page",
2050
+ String(page)
2051
+ ], true);
2052
+ const body = parseJson(result.stdout);
2053
+ return {
2054
+ result,
2055
+ versions: Array.isArray(body) && body.length <= pageSize && body.every((item) => record(item) && typeof item.id === "string" && Number.isSafeInteger(item.number)) && new Set(body.map((item) => item.number)).size === body.length ? body : null
2056
+ };
2057
+ };
2058
+ const first = readPage(1);
2059
+ if (first.result.status !== 0) return first.result;
2060
+ if (!first.versions) return failed("The Cloudflare Worker version list was not readable.");
2061
+ const versions = [...first.versions];
2062
+ if (versions.length === pageSize) {
2063
+ const second = readPage(2);
2064
+ if (second.result.status !== 0 || !second.versions) return failed("The Cloudflare Worker version history was not readable.");
2065
+ if (second.versions.length > 0) {
2066
+ const firstNumbers = versions.map((item) => item.number);
2067
+ const secondNumbers = second.versions.map((item) => item.number);
2068
+ if (Math.min(...secondNumbers) > Math.max(...firstNumbers)) {
2069
+ versions.push(...second.versions);
2070
+ let last = Math.max(...secondNumbers);
2071
+ for (let page = 3; page <= 1e3 && second.versions.length === pageSize; page++) {
2072
+ const next = readPage(page);
2073
+ if (next.result.status !== 0 || !next.versions) return failed("The Cloudflare Worker version history was not readable.");
2074
+ if (next.versions.length === 0) break;
2075
+ const numbers = next.versions.map((item) => item.number);
2076
+ if (Math.min(...numbers) <= last) return failed("The Cloudflare Worker version history changed during inspection.");
2077
+ versions.push(...next.versions);
2078
+ last = Math.max(...numbers);
2079
+ if (next.versions.length < pageSize) break;
2080
+ if (page === 1e3) return failed("The Cloudflare Worker version history is too large to verify.");
2081
+ }
2082
+ } else if (Math.max(...secondNumbers) >= Math.min(...firstNumbers)) return failed("The Cloudflare Worker version history changed during inspection.");
2083
+ }
2084
+ }
2085
+ return {
2086
+ ...first.result,
2087
+ stdout: JSON.stringify(versions.sort((a, b) => a.number - b.number).slice(-10))
2088
+ };
2089
+ }
2090
+ if (args[0] === "versions" && args[1] === "view" && args[2]) {
2091
+ const result = run([
2092
+ "workers",
2093
+ "versions",
2094
+ "get",
2095
+ args[2],
2096
+ "--worker-id",
2097
+ workerName
2098
+ ], true);
2099
+ if (result.status !== 0) return result;
2100
+ const version = parseJson(result.stdout);
2101
+ if (!record(version) || version.id !== args[2] || !Array.isArray(version.bindings)) return failed("The Cloudflare Worker version was not readable.");
2102
+ return {
2103
+ ...result,
2104
+ stdout: JSON.stringify({
2105
+ ...version,
2106
+ resources: { bindings: version.bindings }
2107
+ })
2108
+ };
2109
+ }
2110
+ if (args[0] === "versions" && args[1] === "upload") {
2111
+ if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare version upload target changed.");
2112
+ const verified = await verifyResources(output.directory);
2113
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2114
+ return run([
2115
+ "workers",
2116
+ "versions",
2117
+ "create",
2118
+ "--prebuilt",
2119
+ ...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
2120
+ ...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : [],
2121
+ ...flag(args, "--preview-alias") ? ["--preview-alias", flag(args, "--preview-alias")] : []
2122
+ ], command.capture);
2123
+ }
2124
+ if (args[0] === "versions" && args[1] === "deploy") {
2125
+ if (flag(args, "--name") !== workerName) return failed("The Cloudflare deployment target changed.");
2126
+ const flagsStart = args.findIndex((item, index) => index >= 2 && item.startsWith("-"));
2127
+ const versions = args.slice(2, flagsStart < 0 ? void 0 : flagsStart);
2128
+ if (!versions.every((item) => /^[0-9a-f-]{36}@\d+(?:\.\d+)?$/i.test(item))) return failed("The Cloudflare deployment versions were invalid.");
2129
+ const parsed = versions.map((item) => {
2130
+ const [version_id, percentage] = item.split("@");
2131
+ return {
2132
+ version_id,
2133
+ percentage: Number(percentage)
2134
+ };
2135
+ });
2136
+ if (parsed.length === 0 || new Set(parsed.map((item) => item.version_id)).size !== parsed.length || parsed.some((item) => item.percentage < 0 || item.percentage > 100) || Math.abs(parsed.reduce((sum, item) => sum + item.percentage, 0) - 100) > .001) return failed("The Cloudflare deployment percentages were invalid.");
2137
+ return run([
2138
+ "workers",
2139
+ "deployments",
2140
+ "create",
2141
+ "--worker",
2142
+ workerName,
2143
+ "--strategy",
2144
+ "percentage",
2145
+ "--versions",
2146
+ JSON.stringify(parsed),
2147
+ ...flag(args, "--message") ? ["--body", JSON.stringify({
2148
+ strategy: "percentage",
2149
+ versions: parsed,
2150
+ annotations: { "workers/message": flag(args, "--message") }
2151
+ })] : []
2152
+ ], command.capture);
2153
+ }
2154
+ if (args[0] === "deploy") {
2155
+ if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare bootstrap target changed.");
2156
+ const verified = await verifyResources(output.directory);
2157
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2158
+ return run([
2159
+ "deploy",
2160
+ "--prebuilt",
2161
+ ...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
2162
+ ...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : []
2163
+ ], command.capture);
2164
+ }
2165
+ if (args[0] === "triggers" && args[1] === "deploy") {
2166
+ const configPath = flag(args, "-c");
2167
+ if (!configPath || flag(args, "--name") !== workerName) return failed("The Cloudflare trigger target changed.");
2168
+ const raw = parseJson(readFileSync(configPath, "utf8"));
2169
+ if (!record(raw) || raw.name !== workerName) return failed("The Cloudflare trigger snapshot was not readable.");
2170
+ const directory = mkdtempSync(join(tmpdir(), "void-cf-triggers-"));
2171
+ try {
2172
+ cpSync(join(output.directory, ".cloudflare"), join(directory, ".cloudflare"), { recursive: true });
2173
+ const workerPath = getWorkerConfigPath(directory);
2174
+ const worker = parseJson(readFileSync(workerPath, "utf8"));
2175
+ if (!record(worker)) return failed("The private Cloudflare Worker config was not readable.");
2176
+ const migrated = migrateBuiltWranglerConfig({
2177
+ ...raw,
2178
+ compatibility_date: worker.compatibilityDate
2179
+ }).worker;
2180
+ if (!migrated) return failed("The Cloudflare trigger snapshot was not convertible.");
2181
+ const next = migrated.triggers ?? [];
2182
+ const previous = Array.isArray(worker.triggers) ? worker.triggers : [];
2183
+ const preserveRoutes = raw.routes === void 0 && raw.route === void 0;
2184
+ const preserveEmail = raw.addresses === void 0;
2185
+ worker.triggers = [
2186
+ ...next,
2187
+ ...preserveRoutes ? previous.filter((trigger) => record(trigger) && trigger.type === "fetch") : [],
2188
+ ...preserveEmail ? previous.filter((trigger) => record(trigger) && trigger.type === "email") : []
2189
+ ];
2190
+ for (const field of ["env", "exports"]) {
2191
+ const previous = record(worker[field]) ? worker[field] : {};
2192
+ worker[field] = {
2193
+ ...Object.fromEntries(Object.entries(previous).filter(([, value]) => !record(value) || value.type !== "workflow")),
2194
+ ...migrated[field]
2195
+ };
2196
+ }
2197
+ if (!preserveRoutes) worker.domains = migrated.domains ?? [];
2198
+ if (typeof raw.workers_dev === "boolean") worker.workersDev = raw.workers_dev;
2199
+ if (typeof raw.preview_urls === "boolean") worker.previewUrls = raw.preview_urls;
2200
+ writeFileSync(workerPath, JSON.stringify(worker), { mode: 384 });
2201
+ await readBuildOutput(directory);
2202
+ const verified = await verifyResources(directory);
2203
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2204
+ return run([
2205
+ "workers",
2206
+ "triggers",
2207
+ "deploy",
2208
+ "--prebuilt"
2209
+ ], command.capture, directory);
2210
+ } finally {
2211
+ rmSync(directory, {
2212
+ recursive: true,
2213
+ force: true
2214
+ });
2215
+ }
2216
+ }
2217
+ if (args[0] === "queues" && args[1] === "consumer" && args[2] === "remove") {
2218
+ const queueName = args[3];
2219
+ if (!queueName || args[4] !== workerName) return failed("The Cloudflare Queue consumer target changed.");
2220
+ const queues = run(["queues", "list"], true);
2221
+ if (queues.status !== 0) return queues;
2222
+ const allQueues = parseJson(queues.stdout);
2223
+ if (!Array.isArray(allQueues)) return failed("The Cloudflare Queue list was not readable.");
2224
+ const queue = allQueues.find((item) => record(item) && item.queue_name === queueName);
2225
+ if (!record(queue) || typeof queue.queue_id !== "string") return failed(`Cloudflare Queue ${queueName} was not found.`);
2226
+ const consumers = run([
2227
+ "queues",
2228
+ "consumers",
2229
+ "list",
2230
+ "--queue-id",
2231
+ queue.queue_id
2232
+ ], true);
2233
+ if (consumers.status !== 0) return consumers;
2234
+ const allConsumers = parseJson(consumers.stdout);
2235
+ if (!Array.isArray(allConsumers)) return failed("The Cloudflare Queue consumers were not readable.");
2236
+ const matching = allConsumers.filter((item) => record(item) && item.script === workerName);
2237
+ if (matching.length === 0) return {
2238
+ status: 0,
2239
+ stdout: "",
2240
+ stderr: ""
2241
+ };
2242
+ if (matching.length !== 1 || !record(matching[0]) || typeof matching[0].consumer_id !== "string") return failed("The Cloudflare Queue consumer identity was ambiguous.");
2243
+ return run([
2244
+ "queues",
2245
+ "consumers",
2246
+ "delete",
2247
+ matching[0].consumer_id,
2248
+ "--queue-id",
2249
+ queue.queue_id,
2250
+ "--force"
2251
+ ], command.capture);
2252
+ }
2253
+ return failed(`Unsupported Cloudflare activation operation: ${args[0] ?? ""} ${args[1] ?? ""}`);
2254
+ };
2255
+ }
2256
+ //#endregion
1848
2257
  //#region src/cli/cloudflare-deploy/classify.ts
1849
2258
  /**
1850
2259
  * Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
@@ -1860,14 +2269,14 @@ function classifyCloudflareDeployApp(root, voidConfig, options) {
1860
2269
  if (framework) {
1861
2270
  if (!FRAMEWORK_PRESETS[framework.name]) return unsupported(`deploy: --platform cloudflare has no deployment preset for framework ${framework.name}.`);
1862
2271
  }
1863
- const staticPreset = detectPreset(root, {
2272
+ const staticPreset = framework ? null : detectPreset(root, {
1864
2273
  dir: options.dir,
1865
2274
  spa: options.spa
1866
2275
  });
1867
2276
  const configuredStatic = voidConfig.inference?.appType === "static" || voidConfig.inference?.appType === "spa";
1868
2277
  if (staticPreset || configuredStatic || options.dir || options.spa) return unsupported([
1869
2278
  `deploy: --platform cloudflare could not resolve the ${staticPreset?.appType ?? (options.spa ? "spa" : "static")} output to deploy.`,
1870
- "Set inference.outputDir in void.json, pass --dir with an existing build directory,",
2279
+ "Set inference.outputDir in void.config.ts, pass --dir with an existing build directory,",
1871
2280
  "or add a supported build tool so Void can locate the generated static assets."
1872
2281
  ].join("\n"));
1873
2282
  if (!framework && !hasBackendFiles(root)) return unsupported([
@@ -1910,7 +2319,7 @@ function approvedCloudflareIsrBinding(config, rootConfig) {
1910
2319
  /** Persist the migration decision in source configuration, not a temporary link marker. */
1911
2320
  async function chooseCloudflareIsr(root, config, options) {
1912
2321
  if (config.routing?.isr !== void 0) return config.routing.isr;
1913
- if (!options.interactive) throw new Error("This migration needs an ISR caching choice. Set routing.isr to true in void.json to provision the KV cache, or false to keep rendering on each request, then rerun `void deploy`.");
2322
+ if (!options.interactive) throw new Error("This migration needs an ISR caching choice. Set routing.isr to true in void.config.ts to provision the KV cache, or false to keep rendering on each request, then rerun `void deploy`.");
1914
2323
  const enabled = await (options.confirm ?? (async (message) => {
1915
2324
  const answer = await confirm({
1916
2325
  message,
@@ -1918,18 +2327,27 @@ async function chooseCloudflareIsr(root, config, options) {
1918
2327
  });
1919
2328
  if (isCancel(answer)) throw new Error("ISR setup cancelled. Rerun `void deploy` to finish linking.");
1920
2329
  return answer === true;
1921
- }))("Enable ISR caching for this app? Yes provisions a Cloudflare KV cache; No keeps caching disabled until you change void.json.");
1922
- const path = join(root, "void.json");
1923
- const source = existsSync(path) ? readFileSync(path, "utf8") : "{}\n";
1924
- writeFileSync(path, applyEdits(source, modify(source, ["routing", "isr"], enabled, { formattingOptions: {
1925
- insertSpaces: true,
1926
- tabSize: 2
1927
- } })));
2330
+ }))("Enable ISR caching for this app? Yes provisions a Cloudflare KV cache; No keeps caching disabled until you change void.config.ts.");
2331
+ if (existsSync(join(root, "void.config.ts"))) writeVoidProjectConfig(root, {
2332
+ ...config,
2333
+ routing: {
2334
+ ...config.routing,
2335
+ isr: enabled
2336
+ }
2337
+ });
2338
+ else {
2339
+ const path = join(root, "void.json");
2340
+ const source = existsSync(path) ? readFileSync(path, "utf8") : "{}\n";
2341
+ writeFileSync(path, applyEdits(source, modify(source, ["routing", "isr"], enabled, { formattingOptions: {
2342
+ insertSpaces: true,
2343
+ tabSize: 2
2344
+ } })));
2345
+ }
1928
2346
  config.routing = {
1929
2347
  ...config.routing,
1930
2348
  isr: enabled
1931
2349
  };
1932
- log$1.info(`Saved routing.isr: ${String(enabled)} in void.json. ISR caching ${enabled ? "will be enabled in this deployment" : "stays disabled until you change this setting"}.`);
2350
+ log$1.info(`Saved routing.isr: ${String(enabled)} in void.config.ts. ISR caching ${enabled ? "will be enabled in this deployment" : "stays disabled until you change this setting"}.`);
1933
2351
  return enabled;
1934
2352
  }
1935
2353
  //#endregion
@@ -2014,22 +2432,25 @@ async function prepareExistingCloudflareDeploy(options) {
2014
2432
  workerName: config.name
2015
2433
  });
2016
2434
  writeFileSync(options.configPath, updated);
2435
+ persistCloudflareConfig(options.root);
2017
2436
  return existing;
2018
2437
  }
2019
2438
  /** Offer the existing destination before the legacy hosted-platform fallback. */
2020
2439
  async function maybeLinkCloudflareDeploy(root, options = {}, deps = {}) {
2021
2440
  if (options.platform || options.backend || options.projectSlug || process.env.VOID_PROJECT || readDeploymentPlatform(root) !== null) return null;
2022
- const files = [
2441
+ const files = [.../* @__PURE__ */ new Set([...[
2023
2442
  "wrangler.jsonc",
2024
2443
  "wrangler.json",
2025
2444
  "wrangler.toml"
2026
- ].filter((name) => existsSync(join(root, name)));
2027
- if (!files.length) return null;
2445
+ ].filter((name) => existsSync(join(root, name))), ...discoverFrameworkWranglerFiles(root)])];
2446
+ if (!files.length && !existsSync(join(root, "void.config.ts"))) return null;
2028
2447
  if (files.length > 1) throw new Error("Multiple Wrangler config files were found. Keep one root configuration before linking to Cloudflare.");
2029
- const name = files[0];
2448
+ const name = files[0] ?? ".void-wrangler.jsonc";
2030
2449
  if (name.endsWith(".toml")) throw new Error("Found wrangler.toml. Direct Cloudflare deployment currently needs a root wrangler.jsonc or wrangler.json with the same settings. Convert the config before linking.");
2031
2450
  const errors = [];
2032
- const config = parse(readFileSync(join(root, name), "utf8"), errors, { allowTrailingComma: true });
2451
+ const configPath = files.length ? join(root, name) : materializeCloudflareConfig(root);
2452
+ const config = parse(readFileSync(configPath, "utf8"), errors, { allowTrailingComma: true });
2453
+ if (!files.length && (!config || typeof config.name !== "string" || !config.name.trim())) return null;
2033
2454
  if (errors.length || !config || typeof config !== "object" || Array.isArray(config) || typeof config.name !== "string" || !config.name.trim()) throw new Error(`Set the existing Worker's name in a valid ${name} before linking to Cloudflare.`);
2034
2455
  if (!(deps.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY))) throw new Error(`Found ${name} without a deployment destination. Run void deploy interactively to link the existing Worker, or use void deploy --platform cloudflare with Cloudflare credentials in CI.`);
2035
2456
  log$1.info(`Found ${basename(name)} for Worker "${config.name}".`);
@@ -2084,6 +2505,44 @@ function readCloudflareLocalState(root) {
2084
2505
  }
2085
2506
  }
2086
2507
  //#endregion
2508
+ //#region src/cli/installed-void.ts
2509
+ /** A global CLI still builds with the project's installed Vite plugin. */
2510
+ function assertInstalledVoidMatchesCli(root) {
2511
+ const projectManifest = join(root, "package.json");
2512
+ if (!existsSync(projectManifest)) return;
2513
+ const project = JSON.parse(readFileSync(projectManifest, "utf8"));
2514
+ if (![
2515
+ "dependencies",
2516
+ "devDependencies",
2517
+ "optionalDependencies"
2518
+ ].some((key) => {
2519
+ const dependencies = project[key];
2520
+ return typeof dependencies === "object" && dependencies !== null && "void" in dependencies;
2521
+ })) return;
2522
+ const cliPackageDir = getPackageDir();
2523
+ const cli = JSON.parse(readFileSync(join(cliPackageDir, "package.json"), "utf8"));
2524
+ let installedVersion;
2525
+ let installedPackageDir;
2526
+ try {
2527
+ const entry = createRequire(projectManifest).resolve("void");
2528
+ let directory = dirname(entry);
2529
+ for (let depth = 0; depth < 8; depth++) {
2530
+ const manifest = join(directory, "package.json");
2531
+ if (existsSync(manifest)) {
2532
+ const installed = JSON.parse(readFileSync(manifest, "utf8"));
2533
+ if (installed.name === "void") {
2534
+ installedVersion = installed.version;
2535
+ installedPackageDir = directory;
2536
+ break;
2537
+ }
2538
+ }
2539
+ directory = dirname(directory);
2540
+ }
2541
+ } catch {}
2542
+ if (installedVersion !== cli.version) throw new Error(`deploy: this CLI is void@${cli.version}, but the project's installed Vite plugin is ${installedVersion ? `void@${installedVersion}` : "missing"}. Install the same Void version in the project (or link this development checkout) before deploying. The build imports the project package; mixing versions can rewrite legacy config and produce an unsafe Cloudflare deploy target.`);
2543
+ if (installedPackageDir && existsSync(join(cliPackageDir, "src", "index.ts")) && realpathSync(installedPackageDir) !== realpathSync(cliPackageDir)) throw new Error("deploy: this development CLI and the project Vite plugin come from different Void builds, even though their package versions match. Link the same development checkout into the project before deploying.");
2544
+ }
2545
+ //#endregion
2087
2546
  //#region src/cli/deploy-errors.ts
2088
2547
  const BODY_SNIPPET_MAX = 200;
2089
2548
  function trimSnippet(body) {
@@ -3372,7 +3831,7 @@ function selectBundledEntryFilename(outFiles) {
3372
3831
  * Determine whether a wrapper is needed based on the features.
3373
3832
  */
3374
3833
  function needsWrapper(features) {
3375
- return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness;
3834
+ return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness || !!features.isr;
3376
3835
  }
3377
3836
  /**
3378
3837
  * Generate a wrapper entry in-place in the worker directory.
@@ -3424,8 +3883,8 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3424
3883
  let migrations;
3425
3884
  let migrationPlanBundle;
3426
3885
  if (features.hasMigrations) {
3427
- const { collectMigrations } = await import("./validate-tBBN_dXH.mjs").then((n) => n.l);
3428
- const { buildMigrationPlanBundle } = await import("./validate-tBBN_dXH.mjs").then((n) => n.s);
3886
+ const { collectMigrations } = await import("./collect-DAUItMDS.mjs");
3887
+ const { buildMigrationPlanBundle } = await import("./plan-DpuOr14e.mjs");
3429
3888
  const migrationsDir = readProjectPaths(root).migrationsDir;
3430
3889
  migrations = collectMigrations(migrationsDir);
3431
3890
  migrationPlanBundle = features.migrationDialect === "sqlite" ? buildMigrationPlanBundle(migrations) : void 0;
@@ -3438,6 +3897,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3438
3897
  if (!existsSync(handlerPath)) throw new Error(`Migration handler not found: ${handlerFilename_}. Run "pnpm -C packages/void build" first.`);
3439
3898
  await bundleMigrationHandler(root, workerDir, handlerPath, features.migrationDialect ?? "sqlite");
3440
3899
  }
3900
+ if (features.isr) await bundleFrameworkIsr(root, workerDir);
3441
3901
  const wrapperSource = generateWrapperSource(renamedName, handlerFilename, features, migrations, migrationPlanBundle);
3442
3902
  const stagedPath = `${mainPath}.${crypto.randomUUID()}.tmp`;
3443
3903
  try {
@@ -3448,6 +3908,33 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3448
3908
  rmSync(stagedPath, { force: true });
3449
3909
  }
3450
3910
  }
3911
+ async function bundleFrameworkIsr(root, workerDir) {
3912
+ const entry = fileURLToPath(import.meta.resolve("@void/isr/runtime"));
3913
+ const tmpDir = join(root, ".void", "isr");
3914
+ const outDir = join(tmpDir, "out");
3915
+ mkdirSync(tmpDir, { recursive: true });
3916
+ await build({
3917
+ root: tmpDir,
3918
+ logLevel: "silent",
3919
+ ssr: { noExternal: true },
3920
+ build: {
3921
+ outDir,
3922
+ emptyOutDir: true,
3923
+ minify: false,
3924
+ ssr: entry,
3925
+ target: "esnext",
3926
+ rollupOptions: {
3927
+ input: entry,
3928
+ external: [/^cloudflare:/, /^node:/],
3929
+ output: {
3930
+ entryFileNames: "__void_isr.mjs",
3931
+ chunkFileNames: "__void_isr-[hash].mjs"
3932
+ }
3933
+ }
3934
+ }
3935
+ });
3936
+ for (const file of readdirSync(outDir)) copyFileSync(join(outDir, file), join(workerDir, file));
3937
+ }
3451
3938
  async function bundleMigrationHandler(root, workerDir, handlerPath, dialect) {
3452
3939
  const tmpDir = join(root, ".void", "migration-handler");
3453
3940
  mkdirSync(tmpDir, { recursive: true });
@@ -3602,6 +4089,7 @@ function cleanupWrapper(root) {
3602
4089
  for (const directory of [
3603
4090
  "handlers",
3604
4091
  "migration-handler",
4092
+ "isr",
3605
4093
  "bundle"
3606
4094
  ]) rmSync(join(voidDir, directory), {
3607
4095
  recursive: true,
@@ -3612,6 +4100,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3612
4100
  const lines = [];
3613
4101
  lines.push(WRAPPER_MARKER);
3614
4102
  lines.push(`import original from "./${renamedEntry}";`);
4103
+ if (features.isr) {
4104
+ lines.push("import { handleFrameworkIsr } from \"./__void_isr.mjs\";");
4105
+ lines.push(`const __voidIsrDeploymentId = ${JSON.stringify(crypto.randomUUID())};`);
4106
+ lines.push(`const __voidIsrPolicy = ${JSON.stringify({
4107
+ revalidate: features.isr.revalidate,
4108
+ queryAllowlist: features.isr.queryAllowlist
4109
+ })};`);
4110
+ }
3615
4111
  if (features.crons.length > 0) lines.push(`import { handleScheduled } from "./${handlersModule}";`);
3616
4112
  if (features.queues.length > 0) lines.push(`import { handleQueue, handleQueueRelay } from "./${handlersModule}";`);
3617
4113
  if (migrations && migrations.length > 0) {
@@ -3621,10 +4117,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3621
4117
  lines.push(`const __migrationDialect = ${JSON.stringify(features.migrationDialect ?? "sqlite")};`);
3622
4118
  }
3623
4119
  lines.push("");
3624
- const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0;
4120
+ const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0 || !!features.isr;
3625
4121
  if (needsFetchWrap) {
3626
4122
  lines.push("async function wrappedFetch(request, env, ctx) {");
3627
4123
  lines.push(" const url = new URL(request.url);");
4124
+ if (features.isr) {
4125
+ lines.push(" env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId;");
4126
+ lines.push(" env.__VOID_ISR_HOST = url.hostname;");
4127
+ }
3628
4128
  if (features.readiness || features.crons.length > 0 || features.queues.length > 0 || features.hasMigrations) {
3629
4129
  lines.push(" if (request.method === \"GET\" && url.pathname === \"/__void/ready\") {");
3630
4130
  lines.push(" return Response.json({ ready: true });");
@@ -3686,6 +4186,12 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3686
4186
  lines.push(" }");
3687
4187
  lines.push(" }");
3688
4188
  }
4189
+ if (features.isr) {
4190
+ lines.push(" if (env.ISR_CACHE && request.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\") {");
4191
+ lines.push(" const cached = await handleFrameworkIsr(request, env, ctx, { ...__voidIsrPolicy, deploymentId: __voidIsrDeploymentId }, (req) => original.fetch(req, env, ctx));");
4192
+ lines.push(" if (cached) return cached;");
4193
+ lines.push(" }");
4194
+ }
3689
4195
  lines.push(" return original.fetch(request, env, ctx);");
3690
4196
  lines.push("}");
3691
4197
  lines.push("");
@@ -3693,8 +4199,8 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3693
4199
  lines.push("export default {");
3694
4200
  if (needsFetchWrap) lines.push(" fetch: wrappedFetch,");
3695
4201
  else lines.push(" fetch: original.fetch,");
3696
- if (features.crons.length > 0) lines.push(" scheduled: handleScheduled,");
3697
- if (features.queues.length > 0) lines.push(" queue: handleQueue,");
4202
+ if (features.crons.length > 0) lines.push(features.isr ? " scheduled(controller, env, ctx) { env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId; return handleScheduled(controller, env, ctx); }," : " scheduled: handleScheduled,");
4203
+ if (features.queues.length > 0) lines.push(features.isr ? " queue(batch, env, ctx) { env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId; return handleQueue(batch, env, ctx); }," : " queue: handleQueue,");
3698
4204
  lines.push("};");
3699
4205
  return lines.join("\n");
3700
4206
  }
@@ -3782,66 +4288,6 @@ export async function handleQueueRelay(payload, env, ctx) {
3782
4288
  }
3783
4289
  //#endregion
3784
4290
  //#region src/cli/deploy.ts
3785
- var deploy_exports = /* @__PURE__ */ __exportAll({
3786
- CloudflareAuthSecretError: () => CloudflareAuthSecretError,
3787
- DEPLOY_PASSTHROUGH_ASSERT_FIELDS: () => DEPLOY_PASSTHROUGH_ASSERT_FIELDS,
3788
- DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS: () => DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS,
3789
- DEPLOY_WHOLE_OBJECT_PINNED_FIELDS: () => DEPLOY_WHOLE_OBJECT_PINNED_FIELDS,
3790
- applyDeployEvent: () => applyDeployEvent,
3791
- assembleVoidManifest: () => assembleVoidManifest,
3792
- assertManagedDurableStateSupported: () => assertManagedDurableStateSupported,
3793
- assertMigrationsProduceAuthSchema: () => assertMigrationsProduceAuthSchema,
3794
- assertNoConfigOverrideInProjectDotenv: () => assertNoConfigOverrideInProjectDotenv,
3795
- assertRemoteMigrationsDeployable: () => assertRemoteMigrationsDeployable,
3796
- assertWranglerUploaderUnchanged: () => assertWranglerUploaderUnchanged,
3797
- checkWranglerMigrationApplySet: () => checkWranglerMigrationApplySet,
3798
- compareWranglerMigrationPaths: () => compareWranglerMigrationPaths,
3799
- computeDesiredCloudflareResources: () => computeDesiredCloudflareResources,
3800
- createDeployWranglerRunner: () => createDeployWranglerRunner,
3801
- deployChildEnv: () => deployChildEnv,
3802
- deriveWorkerName: () => deriveWorkerName,
3803
- discoverRootWranglerConfig: () => discoverRootWranglerConfig,
3804
- ensureCloudflareAuthSecret: () => ensureCloudflareAuthSecret,
3805
- ensurePreviouslyDeployedLiveBindingConfig: () => ensurePreviouslyDeployedLiveBindingConfig,
3806
- formatCloudflareActivationError: () => formatCloudflareActivationError,
3807
- formatCloudflareSandboxUnavailable: () => formatCloudflareSandboxUnavailable,
3808
- generateDeployWrapperIfNeeded: () => generateDeployWrapperIfNeeded,
3809
- hasDeploySchemaDrift: () => hasDeploySchemaDrift,
3810
- hasNonPageBackend: () => hasNonPageBackend,
3811
- hasPrerenderSources: () => hasPrerenderSources,
3812
- hashWranglerUploader: () => hashWranglerUploader,
3813
- isWranglerNonInteractiveOrCI: () => isWranglerNonInteractiveOrCI,
3814
- loadProvisionModule: () => loadProvisionModule,
3815
- parseRootWranglerConfig: () => parseRootWranglerConfig$1,
3816
- prepareCloudflareFrameworkArtifact: () => prepareCloudflareFrameworkArtifact,
3817
- promptDeployProjectConfig: () => promptDeployProjectConfig,
3818
- reconstructExpectedContainers: () => reconstructExpectedContainers,
3819
- resolveCloudflareVoidStaticPreset: () => resolveCloudflareVoidStaticPreset,
3820
- resolveDeployLiveBindingConfig: () => resolveDeployLiveBindingConfig,
3821
- resolveDeployTransport: () => resolveDeployTransport,
3822
- resolveDeployWorkerMain: () => resolveDeployWorkerMain,
3823
- resolveDeployWranglerCompat: () => resolveDeployWranglerCompat,
3824
- resolveDeploymentPlatform: () => resolveDeploymentPlatform,
3825
- resolveDistDir: () => resolveDistDir,
3826
- resolveFullDeployBuildCommand: () => resolveFullDeployBuildCommand,
3827
- resolveStaticBuildCommand: () => resolveStaticBuildCommand,
3828
- resolveStaticDeployPreset: () => resolveStaticDeployPreset,
3829
- resolveWorkerDirName: () => resolveWorkerDirName,
3830
- resolveWranglerMigrationPattern: () => resolveWranglerMigrationPattern,
3831
- runCloudflareDeploy: () => runCloudflareDeploy,
3832
- runDeploy: () => runDeploy,
3833
- runStaticDeploy: () => runStaticDeploy,
3834
- runWranglerAuthToken: () => runWranglerAuthToken,
3835
- snapshotBindingIdentities: () => snapshotBindingIdentities,
3836
- snapshotPassthroughIdentities: () => snapshotPassthroughIdentities,
3837
- snapshotPassthroughRawFields: () => snapshotPassthroughRawFields,
3838
- streamDeployEvents: () => streamDeployEvents,
3839
- validateAuthMigrationSchema: () => validateAuthMigrationSchema,
3840
- verifyGeneratedDeployConfig: () => verifyGeneratedDeployConfig,
3841
- warnIgnoredNotFoundForFramework: () => warnIgnoredNotFoundForFramework,
3842
- warnRedundantForceOn3xx: () => warnRedundantForceOn3xx,
3843
- warnUnpublishedRouting: () => warnUnpublishedRouting
3844
- });
3845
4291
  const drizzleKitBin = join(fileURLToPath(import.meta.resolve("drizzle-kit")), "..", "bin.cjs");
3846
4292
  const deployDriftCheckDir = join(".void", "deploy-drift-check");
3847
4293
  let loadedProvisionModule;
@@ -3851,7 +4297,7 @@ let loadedProvisionModule;
3851
4297
  * so a managed deploy never imports it — and thus never loads `proper-lockfile`.
3852
4298
  */
3853
4299
  async function loadProvisionModule() {
3854
- loadedProvisionModule ??= await import("./provision-CSJOjjQk.mjs").then((n) => n.a);
4300
+ loadedProvisionModule ??= await import("./provision-CNgEBkVA.mjs");
3855
4301
  return loadedProvisionModule;
3856
4302
  }
3857
4303
  /**
@@ -4438,6 +4884,34 @@ function hashWranglerUploader(root, resolveArgv = resolveWranglerArgv) {
4438
4884
  if (typeof entry !== "string" || entry.length === 0 || !existsSync(entry)) return;
4439
4885
  return hashDirectoryContents(dirname(entry));
4440
4886
  }
4887
+ /** Pin the cf uploader and prebuilt-artifact builders before project code runs. */
4888
+ function hashCfUploader() {
4889
+ try {
4890
+ const hash = createHash("sha256");
4891
+ for (const name of [
4892
+ "cf",
4893
+ "@cloudflare/config",
4894
+ "@cloudflare/build-output-utils",
4895
+ "vite"
4896
+ ]) {
4897
+ let path = dirname(fileURLToPath(import.meta.resolve(name)));
4898
+ while (!existsSync(join(path, "package.json"))) {
4899
+ const parent = dirname(path);
4900
+ if (parent === path) return;
4901
+ path = parent;
4902
+ }
4903
+ const contents = hashDirectoryContents(path);
4904
+ if (!contents) return;
4905
+ hash.update(name);
4906
+ hash.update("\0");
4907
+ hash.update(contents);
4908
+ hash.update("\0");
4909
+ }
4910
+ return hash.digest("hex");
4911
+ } catch {
4912
+ return;
4913
+ }
4914
+ }
4441
4915
  /**
4442
4916
  * sha256 over every file under `dir`, walked in a STABLE (name-sorted, depth-first) order with
4443
4917
  * each file's relative path folded into the digest, so the hash depends only on the directory's
@@ -4475,11 +4949,11 @@ function hashDirectoryContents(dir) {
4475
4949
  function assertWranglerUploaderUnchanged(before, after) {
4476
4950
  if (before === void 0 || after === void 0) return {
4477
4951
  ok: false,
4478
- reason: `could not resolve or hash the wrangler uploader to verify it across the build — refusing to run a deploy binary that cannot be verified.`
4952
+ reason: `could not resolve or hash the Cloudflare uploader to verify it across the build — refusing to run a deploy binary that cannot be verified.`
4479
4953
  };
4480
4954
  if (before !== after) return {
4481
4955
  ok: false,
4482
- reason: `the build modified the wrangler uploader (its bundle hash changed across the build) — refusing to run it with your Cloudflare credentials.`
4956
+ reason: `the build modified the Cloudflare uploader (its bundle hash changed across the build) — refusing to run it with your Cloudflare credentials.`
4483
4957
  };
4484
4958
  return { ok: true };
4485
4959
  }
@@ -4732,14 +5206,12 @@ function resolveGeneratedDeployConfigPathDefault(root) {
4732
5206
  function readGeneratedDeployConfig(root) {
4733
5207
  const redirectedPath = resolveGeneratedDeployConfigPathDefault(root);
4734
5208
  try {
4735
- const config = JSON.parse(readFileSync(redirectedPath, "utf-8"));
4736
- if (config === null || typeof config !== "object" || Array.isArray(config)) throw new Error("malformed config");
4737
5209
  return {
4738
5210
  path: redirectedPath,
4739
- config
5211
+ config: readGeneratedWranglerConfigFile(redirectedPath)
4740
5212
  };
4741
5213
  } catch {
4742
- throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON.`);
5214
+ throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON/JSONC.`);
4743
5215
  }
4744
5216
  }
4745
5217
  /** Older project plugins can repeat root flags; normalize only the generated artifact. */
@@ -4827,11 +5299,11 @@ function verifyGeneratedDeployConfig(root, expected) {
4827
5299
  };
4828
5300
  let generated;
4829
5301
  try {
4830
- generated = JSON.parse(readFileSync(redirectedPath, "utf-8"));
5302
+ generated = readGeneratedWranglerConfigFile(redirectedPath);
4831
5303
  } catch {
4832
5304
  return {
4833
5305
  ok: false,
4834
- reason: `generated wrangler config ${redirectedPath} is not valid JSON.`
5306
+ reason: `generated wrangler config ${redirectedPath} is not valid JSON/JSONC.`
4835
5307
  };
4836
5308
  }
4837
5309
  if (generated.account_id !== expected.accountId) return {
@@ -5648,16 +6120,12 @@ function createDeployWranglerRunner(root, accountId, apiBaseUrl) {
5648
6120
  const [command, ...prefix] = resolveWranglerArgv(root);
5649
6121
  return (args, opts) => {
5650
6122
  const childEnv = deployChildEnv(accountId, apiBaseUrl);
5651
- const keyringTerminal = cloudflareKeyringNeedsTerminal(args);
5652
- if (!opts.capture || keyringTerminal) childEnv.WRANGLER_LOG = "none";
6123
+ const interactiveLogin = cloudflareAuthNeedsTerminal(args);
6124
+ if (!opts.capture || interactiveLogin) childEnv.WRANGLER_LOG = "none";
5653
6125
  if (opts.env) Object.assign(childEnv, opts.env);
5654
6126
  const result = spawnSync(command, [...prefix, ...args], {
5655
6127
  cwd: root,
5656
- stdio: keyringTerminal ? [
5657
- "inherit",
5658
- "inherit",
5659
- "ignore"
5660
- ] : opts.input === void 0 ? opts.capture ? [
6128
+ stdio: interactiveLogin ? "inherit" : opts.input === void 0 ? opts.capture ? [
5661
6129
  "ignore",
5662
6130
  "pipe",
5663
6131
  "pipe"
@@ -5791,7 +6259,7 @@ async function runCloudflareEmailStep(input) {
5791
6259
  };
5792
6260
  const from = input.voidConfig.email?.from;
5793
6261
  if (!from) {
5794
- log.warn(["deploy: this app uses email, but void.json names no sender.", "Add \"email\": { \"from\": \"you@mail.acme.com\" } to void.json — deploying without email."].join("\n"));
6262
+ log.warn(["deploy: this app uses email, but void.config.ts names no sender.", "Set email.from to \"you@mail.acme.com\" in void.config.ts — deploying without email."].join("\n"));
5795
6263
  return without;
5796
6264
  }
5797
6265
  const { rootConfig } = input;
@@ -5900,7 +6368,7 @@ async function runCloudflareEmailStep(input) {
5900
6368
  };
5901
6369
  };
5902
6370
  if (pre.blockers.some((b) => b.scope === "all")) return leaveAccount(`email on ${pre.domain} cannot be set up from here.`);
5903
- if (input.nonInteractive) return leaveAccount([`email on ${pre.domain} is not ${shipsBinding ? "fully " : ""}set up, and this shell cannot ask.`, "Run `void email setup --platform cloudflare` once locally, commit wrangler.jsonc, then redeploy."].join("\n"));
6371
+ if (input.nonInteractive) return leaveAccount([`email on ${pre.domain} is not ${shipsBinding ? "fully " : ""}set up, and this shell cannot ask.`, "Run `void email setup --platform cloudflare` once locally, commit void.lock.json, then redeploy."].join("\n"));
5904
6372
  if (!await input.confirm(`Set up email on ${pre.domain}?`)) return leaveAccount("email setup skipped — run `void email setup --platform cloudflare` later.");
5905
6373
  const out = await applyEmailSetup(pre, inputs);
5906
6374
  if (out.lines.length > 0) log.message(out.lines.join("\n"));
@@ -5962,6 +6430,11 @@ async function ensureCloudflareAuthSecret(options) {
5962
6430
  };
5963
6431
  if ((await list(true)).includes(BETTER_AUTH_SECRET_NAME)) return { created: false };
5964
6432
  const secret = randomBytes(32).toString("hex");
6433
+ if (workerWasMissing) return {
6434
+ created: true,
6435
+ workerWasMissing: true,
6436
+ candidateSecret: secret
6437
+ };
5965
6438
  beforeRun();
5966
6439
  let put;
5967
6440
  try {
@@ -5979,8 +6452,8 @@ async function ensureCloudflareAuthSecret(options) {
5979
6452
  } catch {
5980
6453
  throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME}. No worker was uploaded. Run \`void secret put ${BETTER_AUTH_SECRET_NAME}\` and retry.`, "put-failed");
5981
6454
  }
5982
- if (!isCleanWranglerExit(put)) throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME} (wrangler exit ${String(put.status)}). No worker was uploaded. Run \`void secret put ${BETTER_AUTH_SECRET_NAME}\` and retry.`, "put-failed");
5983
- if (!(await list(false)).includes(BETTER_AUTH_SECRET_NAME)) throw new CloudflareAuthSecretError(`deploy: wrangler reported success but ${BETTER_AUTH_SECRET_NAME} was not present afterward. No worker was uploaded; retry once Cloudflare secret storage is available.`, "verification-failed");
6455
+ if (!isCleanWranglerExit(put)) throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME} (Cloudflare command exit ${String(put.status)}). No worker was uploaded. Run \`void secret put ${BETTER_AUTH_SECRET_NAME}\` and retry.`, "put-failed");
6456
+ if (!(await list(false)).includes(BETTER_AUTH_SECRET_NAME)) throw new CloudflareAuthSecretError(`deploy: Cloudflare reported success but ${BETTER_AUTH_SECRET_NAME} was not present afterward. No worker was uploaded; retry once Cloudflare secret storage is available.`, "verification-failed");
5984
6457
  return {
5985
6458
  created: true,
5986
6459
  ...workerWasMissing ? { workerWasMissing: true } : {}
@@ -6080,10 +6553,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6080
6553
  }
6081
6554
  const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
6082
6555
  const wranglerUploaderHashBefore = hashUploader(root);
6556
+ const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
6557
+ const cfUploaderIsPinned = () => {
6558
+ const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
6559
+ if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
6560
+ return matched;
6561
+ };
6083
6562
  const assertUploaderStillPinned = () => {
6084
6563
  const check = assertWranglerUploaderUnchanged(wranglerUploaderHashBefore, hashUploader(root));
6085
6564
  if (check.ok) return true;
6086
- log.error(["deploy: refusing to run the wrangler uploader with your Cloudflare credentials.", check.reason].filter(Boolean).join("\n"));
6565
+ log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", check.reason].filter(Boolean).join("\n"));
6087
6566
  return false;
6088
6567
  };
6089
6568
  let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
@@ -6148,10 +6627,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6148
6627
  const staleAddresses = Array.isArray(rootConfig.addresses) ? rootConfig.addresses.filter((a) => typeof a === "string") : [];
6149
6628
  const staleBinding = Array.isArray(rootConfig.send_email) && rootConfig.send_email.some((e) => e?.name === "SEND_EMAIL");
6150
6629
  if (staleAddresses.length > 0 || staleBinding) log.warn([
6151
- "deploy: this app no longer declares email handlers or imports void/email, but wrangler.jsonc still carries the email setup Void wrote:",
6630
+ "deploy: this app no longer declares email handlers or imports void/email, but the Cloudflare config still carries the email setup Void wrote:",
6152
6631
  ...staleAddresses.map((a) => ` • ${a} — still routed to worker "${workerName}", which no longer exports email(); inbound mail there will fail.`),
6153
6632
  ...staleBinding ? [` • send_email ${SEND_EMAIL_BINDING} binding`] : [],
6154
- "Deploying as-is. To detach: remove `addresses`, `send_email` and `vars.__VOID_EMAIL_FROM` from wrangler.jsonc and delete the rules in the Cloudflare dashboard (Email → Email Routing → Routing rules), or set `addresses: []` and let `void deploy --platform cloudflare` ask before deleting every Void-owned rule."
6633
+ "Deploying as-is. To detach: remove `addresses`, `send_email`, and `vars.__VOID_EMAIL_FROM` from `resolved` in void.lock.json (and any authored overrides in void.config.ts), then delete the rules in the Cloudflare dashboard (Email → Email Routing → Routing rules)."
6155
6634
  ].join("\n"));
6156
6635
  }
6157
6636
  const schemaProbeEnv = buildSchemaProbeEnv(accountId, apiBaseUrl);
@@ -6255,7 +6734,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6255
6734
  const provisionAndVerify = async () => {
6256
6735
  if (existingWorker) {
6257
6736
  const { missing } = provisionModule.checkCloudflareProvisionDrift(configPath, desired);
6258
- throw new Error(missing.length > 0 ? formatCloudflareDriftMessage(missing, reasons, "Linking cannot provision these inferred resources:", `Check the existing Worker's binding names and resource IDs in ${basename(configPath)} and inference.bindings in void.json, then rerun \`void deploy\`. Keep new resources for a later deployment.`) : "Linking cannot provision resources. Remove --provision and rerun `void deploy` to reuse the existing Worker.");
6737
+ throw new Error(missing.length > 0 ? formatCloudflareDriftMessage(missing, reasons, "Linking cannot provision these inferred resources:", `Check the existing Worker's binding names and resource IDs in void.config.ts and inference.bindings there, then rerun \`void deploy\`. Keep new resources for a later deployment.`) : "Linking cannot provision resources. Remove --provision and rerun `void deploy` to reuse the existing Worker.");
6259
6738
  }
6260
6739
  if (!assertUploaderStillPinned()) return exit(1);
6261
6740
  const provision = deps.provision ?? provisionModule.provisionCloudflareResources;
@@ -6382,7 +6861,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6382
6861
  return exit(getExitCode(err));
6383
6862
  }
6384
6863
  if (detectedFramework && frameworkPreset) try {
6385
- await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys);
6864
+ await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys, needsAI ? { binding: aiBindingName } : void 0);
6386
6865
  } catch (error) {
6387
6866
  log.error(`deploy: could not prepare ${detectedFramework.name} for Cloudflare — ${getErrorMessage(error)}`);
6388
6867
  return exit(1);
@@ -6541,7 +7020,22 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6541
7020
  d1MigrateToken = migrateTarget.token;
6542
7021
  }
6543
7022
  }
7023
+ const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
7024
+ const prepareBuildOutput = () => frameworkPreset?.cloudflareArtifact === "worker-output" ? prepareCfFrameworkBuildOutput({
7025
+ projectRoot: root,
7026
+ configPath: generatedConfigPath,
7027
+ accountId
7028
+ }) : prepareCfBuildOutput(dirname(generatedConfigPath), accountId);
7029
+ if (!deps.activateVersion && !deps.runWrangler) {
7030
+ const preflight = await prepareBuildOutput();
7031
+ if (!preflight) {
7032
+ log.error("deploy: cf could not prepare the built Worker for deployment.");
7033
+ return exit(1);
7034
+ }
7035
+ preflight.dispose();
7036
+ }
6544
7037
  let workerWasMissingBeforeSecretProvisioning = false;
7038
+ let initialAuthSecret;
6545
7039
  if (authEnabled) {
6546
7040
  const inheritance = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, {
6547
7041
  accountId,
@@ -6570,6 +7064,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6570
7064
  beforeWranglerRun: assertUploaderStillPinned
6571
7065
  });
6572
7066
  workerWasMissingBeforeSecretProvisioning ||= authSecret.workerWasMissing === true;
7067
+ initialAuthSecret = authSecret.candidateSecret;
6573
7068
  cliLog.info("cloudflare_auth_secret_ready", { created: authSecret.created });
6574
7069
  } catch (error) {
6575
7070
  if (error instanceof CloudflareAuthSecretError && error.reason === "uploader-changed") return exit(1);
@@ -6686,23 +7181,35 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6686
7181
  ].filter(Boolean).join("\n"));
6687
7182
  return exit(1);
6688
7183
  }
6689
- const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
6690
7184
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
6691
7185
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
6692
7186
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
6693
- const activationRunner = preBuildRootConfig.compliance_region ? runWrangler : createCloudflareMetadataRunner({
6694
- runWrangler,
7187
+ if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7188
+ const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareBuildOutput();
7189
+ if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
7190
+ log.error("deploy: cf could not prepare the built Worker for deployment.");
7191
+ return exit(1);
7192
+ }
7193
+ const cfCommand = cfOutput ? createCfCommand({
6695
7194
  accountId,
6696
7195
  apiBaseUrl,
7196
+ env: deployChildEnv,
7197
+ verifyUploader: cfUploaderIsPinned
7198
+ }) : null;
7199
+ const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
7200
+ output: cfOutput,
6697
7201
  workerName,
6698
- configPath: generatedConfigPath,
6699
- fetch: deps.metadataFetch,
6700
- verifyUploader: assertUploaderStillPinned,
6701
- getToken: () => runWranglerAuthToken(runWrangler, generatedConfigPath)
6702
- });
7202
+ runCf: cfCommand,
7203
+ verifyResources: createCfResourceVerifier({
7204
+ configPath: generatedConfigPath,
7205
+ runCf: cfCommand,
7206
+ runWrangler,
7207
+ verifyCompatibilityRunner: assertUploaderStillPinned
7208
+ })
7209
+ }) : runWrangler;
6703
7210
  const execution = await (deps.activateVersion ?? activateCloudflareVersion)({
6704
7211
  runWrangler: activationRunner,
6705
- verifyUploader: assertUploaderStillPinned,
7212
+ verifyUploader: cfOutput ? cfUploaderIsPinned : assertUploaderStillPinned,
6706
7213
  workerName,
6707
7214
  configPath: generatedConfigPath,
6708
7215
  preserveTriggers: existingWorker !== null,
@@ -6734,10 +7241,18 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6734
7241
  workerName,
6735
7242
  runWrangler
6736
7243
  }),
7244
+ publishEmptyCrons: createCloudflareEmptyCronPublisher({
7245
+ accountId,
7246
+ apiBaseUrl,
7247
+ configPath: generatedConfigPath,
7248
+ workerName,
7249
+ runWrangler
7250
+ }),
6737
7251
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
6738
7252
  queueConsumerCleanup,
6739
- verifyInheritedSecrets: true
6740
- });
7253
+ verifyInheritedSecrets: true,
7254
+ ...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
7255
+ }).finally(() => cfOutput?.dispose());
6741
7256
  if (!execution.ok) {
6742
7257
  await reportCloudflareActivationFailure(cliLog, needsSandbox && execution.containersUnavailable ? formatCloudflareSandboxUnavailable() : formatCloudflareActivationError(execution));
6743
7258
  return exit(1);
@@ -6765,11 +7280,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6765
7280
  */
6766
7281
  function discoverRootWranglerConfig(root) {
6767
7282
  if (existsSync(join(root, "wrangler.toml"))) throw new Error("Found wrangler.toml. Direct Cloudflare deployment needs one root wrangler.jsonc or wrangler.json with the same settings. Convert the config before deploying.");
6768
- for (const name of ["wrangler.jsonc", "wrangler.json"]) {
6769
- const candidate = join(root, name);
6770
- if (existsSync(candidate)) return candidate;
6771
- }
6772
- return join(root, "wrangler.jsonc");
7283
+ return materializeCloudflareConfig(root);
6773
7284
  }
6774
7285
  /** Avoid making Wrangler open a config path that Void has not created yet. */
6775
7286
  function existingWranglerConfigArgs(configPath) {
@@ -6819,6 +7330,7 @@ function formatCloudflareActivationError(result) {
6819
7330
  "deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
6820
7331
  "For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token.",
6821
7332
  "For a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
7333
+ "If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
6822
7334
  `Then retry. ${formatCloudflareReadinessRestoration(result)}`
6823
7335
  ].join("\n");
6824
7336
  case "bootstrap-failed": return `deploy: Cloudflare could not bootstrap the first Worker deployment${status}.${cloudflareCode}${diagnostic}`;
@@ -6832,6 +7344,7 @@ function formatCloudflareActivationError(result) {
6832
7344
  "deploy: Cloudflare Access blocked the first Worker deployment readiness probe.",
6833
7345
  "For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token;",
6834
7346
  "for a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
7347
+ "If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
6835
7348
  "Then retry. Cloudflare requires the first deployment to be non-versioned, so the new",
6836
7349
  "Worker is already active behind Access."
6837
7350
  ].join("\n");
@@ -6857,7 +7370,7 @@ function cloudflareWorkerReadinessHeaders() {
6857
7370
  });
6858
7371
  }
6859
7372
  /** Build the trusted Wrangler pointer for a framework that emits Worker files directly. */
6860
- async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = []) {
7373
+ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = [], ai) {
6861
7374
  const workerMain = join(root, preset.workerDir, preset.workerMain);
6862
7375
  const assetsDirectory = join(root, preset.assetsDir);
6863
7376
  if (!existsSync(workerMain)) throw new Error(`framework ${framework.name} did not emit its Worker entry at ${preset.workerDir}/${preset.workerMain}`);
@@ -6865,13 +7378,18 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
6865
7378
  const paths = resolveProjectPaths(root, voidConfig);
6866
7379
  const crons = scanJobsSync(root, paths.cronsDir);
6867
7380
  const queues = scanQueuesSync(root, paths.queuesDir);
7381
+ const revalidate = collectRevalidate(voidConfig, null);
6868
7382
  await generateDeployWrapperIfNeeded(root, join(root, preset.workerDir), preset.workerMain, {
6869
7383
  auth: null,
6870
7384
  crons,
6871
7385
  queues,
6872
7386
  hasMigrations: false,
6873
7387
  migrationDialect: getDatabaseDialect(voidConfig),
6874
- readiness: true
7388
+ readiness: true,
7389
+ ...hasRevalidate(revalidate) && { isr: {
7390
+ revalidate,
7391
+ queryAllowlist: voidConfig.routing?.revalidateQueryAllowlist
7392
+ } }
6875
7393
  });
6876
7394
  if (preset.cloudflareArtifact === "vite-plugin") return;
6877
7395
  const rootConfig = parseRootWranglerConfig(configPath);
@@ -6886,12 +7404,17 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
6886
7404
  compatibilityFlags: preset.cloudflareCompatibilityFlags,
6887
7405
  crons: [...new Set(crons.flatMap((job) => job.crons))],
6888
7406
  requiredSecrets: requiredSecretNames,
7407
+ ...ai ? { ai: {
7408
+ ...ai,
7409
+ gateway: voidConfig.ai?.gateway
7410
+ } } : {},
6889
7411
  ...preset.workerDir === preset.assetsDir ? { assetsIgnore: [
6890
7412
  preset.workerMain,
6891
7413
  "_routes.json",
6892
7414
  "__original.js",
6893
7415
  "__original.mjs",
6894
7416
  "__void_handlers.mjs",
7417
+ "__void_isr*.mjs",
6895
7418
  "__void_migration_handler*.mjs"
6896
7419
  ] } : {}
6897
7420
  });
@@ -6961,9 +7484,15 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
6961
7484
  }
6962
7485
  const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
6963
7486
  const uploaderHash = hashUploader(root);
7487
+ const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
7488
+ const cfUploaderIsPinned = () => {
7489
+ const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
7490
+ if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
7491
+ return matched;
7492
+ };
6964
7493
  const uploaderIsPinned = () => {
6965
7494
  const result = assertWranglerUploaderUnchanged(uploaderHash, hashUploader(root));
6966
- if (!result.ok) log.error(["deploy: refusing to run the wrangler uploader with your Cloudflare credentials.", result.reason].filter(Boolean).join("\n"));
7495
+ if (!result.ok) log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", result.reason].filter(Boolean).join("\n"));
6967
7496
  return result.ok;
6968
7497
  };
6969
7498
  let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
@@ -7092,19 +7621,37 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7092
7621
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7093
7622
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7094
7623
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7095
- const activationRunner = rootConfig.compliance_region ? runWrangler : createCloudflareMetadataRunner({
7096
- runWrangler,
7624
+ if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7625
+ const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareCfStaticBuildOutput({
7626
+ projectRoot: root,
7627
+ configPath: staticConfigPath,
7628
+ assetsDirectory: stagedAssetsDirectory,
7629
+ accountId
7630
+ });
7631
+ if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
7632
+ log.error("deploy: cf could not prepare the static Worker for deployment.");
7633
+ return exit(1);
7634
+ }
7635
+ const cfCommand = cfOutput ? createCfCommand({
7097
7636
  accountId,
7098
7637
  apiBaseUrl,
7638
+ env: deployChildEnv,
7639
+ verifyUploader: cfUploaderIsPinned
7640
+ }) : null;
7641
+ const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
7642
+ output: cfOutput,
7099
7643
  workerName,
7100
- configPath: staticConfigPath,
7101
- fetch: deps.metadataFetch,
7102
- verifyUploader: uploaderIsPinned,
7103
- getToken: () => runWranglerAuthToken(runWrangler, staticConfigPath)
7104
- });
7644
+ runCf: cfCommand,
7645
+ verifyResources: createCfResourceVerifier({
7646
+ configPath: staticConfigPath,
7647
+ runCf: cfCommand,
7648
+ runWrangler,
7649
+ verifyCompatibilityRunner: uploaderIsPinned
7650
+ })
7651
+ }) : runWrangler;
7105
7652
  const execution = await (deps.activateVersion ?? activateCloudflareVersion)({
7106
7653
  runWrangler: activationRunner,
7107
- verifyUploader: uploaderIsPinned,
7654
+ verifyUploader: cfOutput ? cfUploaderIsPinned : uploaderIsPinned,
7108
7655
  configPath: staticConfigPath,
7109
7656
  preserveTriggers: existingWorker !== null,
7110
7657
  expectedPreviousVersionId: existingWorker?.versionId,
@@ -7136,9 +7683,16 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7136
7683
  workerName,
7137
7684
  runWrangler
7138
7685
  }),
7686
+ publishEmptyCrons: createCloudflareEmptyCronPublisher({
7687
+ accountId,
7688
+ apiBaseUrl,
7689
+ configPath: staticConfigPath,
7690
+ workerName,
7691
+ runWrangler
7692
+ }),
7139
7693
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
7140
7694
  queueConsumerCleanup
7141
- });
7695
+ }).finally(() => cfOutput?.dispose());
7142
7696
  if (!execution.ok) {
7143
7697
  await reportCloudflareActivationFailure(cliLog, formatCloudflareActivationError(execution));
7144
7698
  return exit(1);
@@ -7189,6 +7743,8 @@ const deployTargets = {
7189
7743
  },
7190
7744
  async deploy(root, options, cliLog) {
7191
7745
  if (options.projectSlug !== void 0) throw new Error("deploy: --project is not supported with platform cloudflare — this platform deploys to your own Cloudflare account and no Void project is involved.");
7746
+ assertInstalledVoidMatchesCli(root);
7747
+ if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
7192
7748
  return runCloudflareDeploy(root, options, cliLog);
7193
7749
  }
7194
7750
  },
@@ -7239,7 +7795,11 @@ async function runDeployInner(root, options, cliLog) {
7239
7795
  const targetLabel = platform === "cloudflare" ? "Cloudflare" : "Void";
7240
7796
  log.info(`Deployment target: ${targetLabel}`);
7241
7797
  cliLog.info("deploy_target", { target: platform });
7242
- return deployTargets[platform].deploy(root, options ?? {}, cliLog);
7798
+ try {
7799
+ return await deployTargets[platform].deploy(root, options ?? {}, cliLog);
7800
+ } finally {
7801
+ if (existsSync(join(root, "void.config.ts"))) stashCloudflareDeployPointer(root);
7802
+ }
7243
7803
  }
7244
7804
  async function runManagedDeploy(root, options, cliLog) {
7245
7805
  let reauthenticated = false;
@@ -7301,6 +7861,7 @@ async function runManagedDeploy(root, options, cliLog) {
7301
7861
  projectId: config.projectId,
7302
7862
  slug: config.slug
7303
7863
  });
7864
+ if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
7304
7865
  const voidConfig = readConfig(root);
7305
7866
  cliLog.info("config_resolved", {
7306
7867
  target: voidConfig.target,
@@ -7418,7 +7979,7 @@ function resolveFullDeployBuildCommand(root, buildOverride) {
7418
7979
  * (`router/compile.ts`) emits a `paths.push(...)` for:
7419
7980
  * 1. `scan.pages.pages` — static patterns + dynamic pages' `getPrerenderPaths()`
7420
7981
  * 2. the custom SSR entry's top-level `getPrerenderPaths()` (`ssr` argument)
7421
- * 3. `options.explicitPrerenderPaths` — void.json `routing.prerender`
7982
+ * 3. `options.explicitPrerenderPaths` — void.config.ts `routing.prerender`
7422
7983
  * With none of them present the collector is a generated function whose body
7423
7984
  * returns `[...new Set([])]`, so skipping is result-identical.
7424
7985
  *
@@ -7831,7 +8392,7 @@ function warnRedundantForceOn3xx(count) {
7831
8392
  */
7832
8393
  function warnIgnoredNotFoundForFramework(notFound, frameworkName) {
7833
8394
  if (notFound === void 0) return;
7834
- log.warn(`"routing.notFound" in void.json is ignored for ${frameworkName} deploys (not_found_handling is pinned to "none" — the framework's own worker owns unmatched HTML).`);
8395
+ log.warn(`"routing.notFound" in void.config.ts is ignored for ${frameworkName} deploys (not_found_handling is pinned to "none" — the framework's own worker owns unmatched HTML).`);
7835
8396
  }
7836
8397
  /**
7837
8398
  * Class B/C framework deploy: build with framework CLI, package with preset output paths.
@@ -7911,7 +8472,7 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
7911
8472
  } catch {}
7912
8473
  if (resources) {
7913
8474
  if (!resources.some((resource) => resource.type === "hyperdrive")) {
7914
- const { text: promptText, isCancel: isCancelPrompt } = await import("./output-B0cfNSx5.mjs").then((n) => n.T);
8475
+ const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
7915
8476
  const connectionString = await promptText({
7916
8477
  message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
7917
8478
  placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
@@ -7953,8 +8514,8 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
7953
8514
  log.info("Wrapper generated");
7954
8515
  }
7955
8516
  const wranglerCompat = resolveDeployWranglerCompat(root, voidConfig, workerDir, { dialect });
7956
- const revalidate = voidConfig.routing?.revalidate;
7957
- const prerender = voidConfig.routing?.prerender;
8517
+ const revalidate = collectRevalidate(voidConfig, null);
8518
+ const prerender = voidConfig.routing?.isr === false ? void 0 : voidConfig.routing?.prerender;
7958
8519
  const schedules = rawJobs.flatMap((job) => job.crons.map((cron) => ({
7959
8520
  name: job.name,
7960
8521
  cron
@@ -8157,7 +8718,7 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
8157
8718
  } catch {}
8158
8719
  if (resources) {
8159
8720
  if (!resources.some((resource) => resource.type === "hyperdrive")) {
8160
- const { text: promptText, isCancel: isCancelPrompt } = await import("./output-B0cfNSx5.mjs").then((n) => n.T);
8721
+ const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
8161
8722
  const connectionString = await promptText({
8162
8723
  message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
8163
8724
  placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
@@ -8604,4 +9165,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
8604
9165
  throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
8605
9166
  }
8606
9167
  //#endregion
8607
- export { renderAddressMap as C, resolveAssetRoutingPolicy as D, hasDocumentRoutes as E, preflightEmail as S, hasApiRoutes as T, scanDurableObjectModules as _, isWranglerNonInteractiveOrCI as a, createNodeEmailDns as b, resolveDistDir as c, generateQueueResolverSource as d, prerenderPages as f, hasRevalidate as g, collectRevalidate as h, discoverRootWranglerConfig as i, resolveWorkerDirName as l, collectPages as m, deploy_exports as n, loadProvisionModule as o, prerenderPagesNode as p, deriveWorkerName as r, resolveDeployTransport as s, createDeployWranglerRunner as t, runWranglerAuthToken as u, SEND_EMAIL_BINDING as v, renderEmailChecklist as w, findEmailConfigConflicts as x, applyEmailSetup as y };
9168
+ export { streamDeployEvents as $, parseRootWranglerConfig$1 as A, resolveDistDir as B, generateDeployWrapperIfNeeded as C, resolveAssetRoutingPolicy as Ct, hashWranglerUploader as D, hasPrerenderSources as E, resolveDeployLiveBindingConfig as F, resolveWranglerMigrationPattern as G, resolveStaticBuildCommand as H, resolveDeployTransport as I, runStaticDeploy as J, runCloudflareDeploy as K, resolveDeployWorkerMain as L, promptDeployProjectConfig as M, reconstructExpectedContainers as N, isWranglerNonInteractiveOrCI as O, resolveCloudflareVoidStaticPreset as P, snapshotPassthroughRawFields as Q, resolveDeployWranglerCompat as R, formatCloudflareSandboxUnavailable as S, resolveAssetConfig as St, hasNonPageBackend as T, resolveStaticDeployPreset as U, resolveFullDeployBuildCommand as V, resolveWorkerDirName as W, snapshotBindingIdentities as X, runWranglerAuthToken as Y, snapshotPassthroughIdentities as Z, deriveWorkerName as _, preflightEmail as _t, applyDeployEvent as a, generateQueueResolverSource as at, ensurePreviouslyDeployedLiveBindingConfig as b, hasApiRoutes as bt, assertMigrationsProduceAuthSchema as c, buildEnv as ct, assertWranglerUploaderUnchanged as d, hasRevalidate as dt, validateAuthMigrationSchema as et, checkWranglerMigrationApplySet as f, scanDurableObjectModules as ft, deployChildEnv as g, findEmailConfigConflicts as gt, createDeployWranglerRunner as h, createNodeEmailDns as ht, DEPLOY_WHOLE_OBJECT_PINNED_FIELDS as i, warnUnpublishedRouting as it, prepareCloudflareFrameworkArtifact as j, loadProvisionModule as k, assertNoConfigOverrideInProjectDotenv as l, collectPages as lt, computeDesiredCloudflareResources as m, applyEmailSetup as mt, DEPLOY_PASSTHROUGH_ASSERT_FIELDS as n, warnIgnoredNotFoundForFramework as nt, assembleVoidManifest as o, prerenderPages as ot, compareWranglerMigrationPaths as p, SEND_EMAIL_BINDING as pt, runDeploy as q, DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS as r, warnRedundantForceOn3xx as rt, assertManagedDurableStateSupported as s, prerenderPagesNode as st, CloudflareAuthSecretError as t, verifyGeneratedDeployConfig as tt, assertRemoteMigrationsDeployable as u, collectRevalidate as ut, discoverRootWranglerConfig as v, renderAddressMap as vt, hasDeploySchemaDrift as w, formatCloudflareActivationError as x, hasDocumentRoutes as xt, ensureCloudflareAuthSecret as y, renderEmailChecklist as yt, resolveDeploymentPlatform as z };