void 0.20.3 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) 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-g_ymMkUe.mjs} +5 -5
  17. package/dist/{auth-link-ElDTgF7j.mjs → auth-link-DFvxIyZi.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-wJAv808h.mjs} +6 -4
  21. package/dist/{cache-D98YTqeE.mjs → cache-Be0Fu5Ka.mjs} +6 -4
  22. package/dist/{cancel-deploy-CPbEQLMG.mjs → cancel-deploy-BgmyOwhe.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 +944 -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-LnvW4HKx.mjs} +8 -6
  49. package/dist/{create-project-D0oXA090.mjs → create-project-BZBl_gQ0.mjs} +8 -23
  50. package/dist/create-project-JV9-6ICF.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-Mzv88E1C.mjs} +48 -44
  54. package/dist/{delete-BZ4-WaGm.mjs → delete-Ri6JemSU.mjs} +6 -4
  55. package/dist/deploy-DAH2-m_-.mjs +2 -0
  56. package/dist/{deploy-BAhhcg5q.mjs → deploy-DEsMVrCY.mjs} +796 -198
  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-BA37Ye7T.mjs} +7 -5
  65. package/dist/{route-types-Da-DpyUp.mjs → drizzle-Beb2Am5S.mjs} +1 -280
  66. package/dist/{email-Bj7Cvdwp.mjs → email-C5NsxrQG.mjs} +14 -12
  67. package/dist/{email-Ce6SQq-i.mjs → email-C5kaZXzJ.mjs} +2 -2
  68. package/dist/{entry-DU3oDoQ3.mjs → entry-DdRFGK0y.mjs} +2 -2
  69. package/dist/{env-DBKmK4vc.mjs → env-DX_v-Q-v.mjs} +1 -1
  70. package/dist/{env-DP_EErve.mjs → env-U_ohASB0.mjs} +9 -7
  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-B87rlalt.mjs +2 -0
  81. package/dist/{gen-B_wPnVTK.mjs → gen-pg-Ojg8Y.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-DsrkweIl.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-B403BLBB.mjs +2 -0
  90. package/dist/{help-CwOX-zmI.mjs → help-sBhFH6pi.mjs} +17 -12
  91. package/dist/index.d.mts +2 -20
  92. package/dist/index.mjs +116 -60
  93. package/dist/{init-BGktCXgA.mjs → init-C--Yyj1b.mjs} +49 -50
  94. package/dist/{link-D2kbqhWb.mjs → link-BC-mNG9-.mjs} +7 -5
  95. package/dist/{list-CvkK_G7k.mjs → list-DHU1Wj6c.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-BwiopVdg.mjs +2 -0
  100. package/dist/{login-WIjNc77c.mjs → login-jKe_0QZL.mjs} +6 -11
  101. package/dist/{logs-dLUFCapG.mjs → logs-BG11f5PR.mjs} +6 -4
  102. package/dist/migrate-BV8qHiCb.mjs +285 -0
  103. package/dist/migrate-BXY3B3m7.mjs +2 -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-BwAS2XZt.mjs} +6 -6
  110. package/dist/output-CCH48AMM.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-C-hv-_Ok.mjs} +6 -6
  128. package/dist/{platform-auth-protection-Drl0qhrn.mjs → platform-auth-protection-DjTE5Hj-.mjs} +7 -5
  129. package/dist/{platform-auth-recovery-CmKEWpDo.mjs → platform-auth-recovery-Cr0r8TEb.mjs} +6 -5
  130. package/dist/{platform-cmd-5q_k56xS.mjs → platform-cmd-0tEh2ZtA.mjs} +8 -5
  131. package/dist/platform-cmd-DE6dw45v.mjs +2 -0
  132. package/dist/{platform-domain-4GiDlcqx.mjs → platform-domain-B_7x6Iqx.mjs} +4 -3
  133. package/dist/platform-lifecycle-Dhx9Pnub.mjs +2 -0
  134. package/dist/{platform-lifecycle-R9xAxvtG.mjs → platform-lifecycle-Di0LbhPM.mjs} +208 -37
  135. package/dist/platform-management-B9LUtMt9.mjs +2 -0
  136. package/dist/{platform-management-BfWsXHEW.mjs → platform-management-eaiaU3uM.mjs} +8 -5
  137. package/dist/{platform-recovery-CbK-I1FB.mjs → platform-recovery-BxfA8E5C.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-D4CkM3_v.mjs +2 -0
  143. package/dist/{prepare-blNRQvQl.mjs → prepare-_T-Haxrr.mjs} +3 -2
  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-DrnRJdep.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-CzRbO_kA.mjs} +6 -4
  155. package/dist/{project-token-Cirx7uwZ.mjs → project-token-Bwxjf4y6.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-DwrqUQZ8.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-B4tFWmkN.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-UtrRjhEO.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-BuGYkAkC.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 +8 -15
  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 +60 -66
  268. package/skills/void/docs/guide/env-migration.md +1 -1
  269. package/skills/void/docs/guide/index.md +15 -41
  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/quickstart.md +11 -78
  278. package/skills/void/docs/guide/remote-dev.md +2 -2
  279. package/skills/void/docs/guide/sandboxes.md +1 -1
  280. package/skills/void/docs/guide/ssg.md +1 -1
  281. package/skills/void/docs/guide/websockets.md +1 -1
  282. package/skills/void/docs/index.md +17 -17
  283. package/skills/void/docs/integrations/cloudflare.md +91 -96
  284. package/skills/void/docs/integrations/frameworks/analog.md +14 -9
  285. package/skills/void/docs/integrations/frameworks/astro.md +14 -10
  286. package/skills/void/docs/integrations/frameworks/nuxt.md +14 -9
  287. package/skills/void/docs/integrations/frameworks/overview.md +35 -29
  288. package/skills/void/docs/integrations/frameworks/react-router.md +1 -1
  289. package/skills/void/docs/integrations/frameworks/sveltekit.md +33 -30
  290. package/skills/void/docs/integrations/frameworks/tanstack-start.md +1 -1
  291. package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -5
  292. package/skills/void/docs/reference/api.md +21 -4
  293. package/skills/void/docs/reference/cli.md +40 -25
  294. package/skills/void/docs/reference/config.md +58 -35
  295. package/skills/void/docs/reference/structure.md +2 -2
  296. 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-CCH48AMM.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-BV8qHiCb.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-BZBl_gQ0.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-jKe_0QZL.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";
41
- import { execFile, execSync, spawnSync } from "node:child_process";
51
+ import { homedir, tmpdir } from "node:os";
52
+ import { execFile, execSync, spawn, 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,426 @@ 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 = await 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 async (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
+ CF_QUIET: "1",
1978
+ CF_NO_OSC_PROGRESS: "1",
1979
+ CF_SEND_TELEMETRY: "false"
1980
+ };
1981
+ if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) env.NODE_USE_ENV_PROXY = "1";
1982
+ if (options.token) env.CLOUDFLARE_API_TOKEN = options.token;
1983
+ return await new Promise((resolve) => {
1984
+ const child = spawn(process.execPath, [cf, ...args], {
1985
+ cwd: run.cwd,
1986
+ env,
1987
+ shell: false,
1988
+ windowsHide: true,
1989
+ stdio: [
1990
+ "ignore",
1991
+ "pipe",
1992
+ "pipe"
1993
+ ]
1994
+ });
1995
+ const stdout = [];
1996
+ const stderr = [];
1997
+ let bytes = 0;
1998
+ let error = null;
1999
+ const collect = (chunks, chunk) => {
2000
+ bytes += chunk.length;
2001
+ if (bytes > 268435456) {
2002
+ error = "Cloudflare command output exceeded 256 MiB.";
2003
+ child.kill();
2004
+ } else chunks.push(chunk);
2005
+ };
2006
+ child.stdout.on("data", (chunk) => collect(stdout, chunk));
2007
+ child.stderr.on("data", (chunk) => collect(stderr, chunk));
2008
+ child.on("error", (cause) => {
2009
+ error = cause.message;
2010
+ });
2011
+ child.on("close", (status, signal) => {
2012
+ resolve({
2013
+ status: typeof status === "number" ? status : 1,
2014
+ stdout: Buffer.concat(stdout).toString("utf8"),
2015
+ stderr: Buffer.concat(stderr).toString("utf8").replace(/\[(\d{4,})\]/g, "[code: $1]"),
2016
+ signal,
2017
+ error
2018
+ });
2019
+ });
2020
+ });
2021
+ };
2022
+ }
2023
+ /**
2024
+ * Adapt the stable activation protocol to cf's prebuilt and API commands.
2025
+ * The protocol keeps the existing preview, inheritance, traffic and rollback checks.
2026
+ */
2027
+ function createCfVersionRunner(options) {
2028
+ const { output, workerName, runCf } = options;
2029
+ const run = async (args, capture, cwd = output.directory) => await runCf(args, {
2030
+ cwd,
2031
+ capture
2032
+ });
2033
+ const verifyResources = async (directory) => {
2034
+ try {
2035
+ return await options.verifyResources(directory);
2036
+ } catch {
2037
+ return failed("Cloudflare resources could not be verified before upload.");
2038
+ }
2039
+ };
2040
+ return async (args, command) => {
2041
+ if (args[0] === "deployments" && args[1] === "status") {
2042
+ const result = await run([
2043
+ "workers",
2044
+ "deployments",
2045
+ "list",
2046
+ "--worker",
2047
+ workerName
2048
+ ], true);
2049
+ if (result.status !== 0) return result;
2050
+ const body = parseJson(result.stdout);
2051
+ const deployments = record(body) ? body.deployments : void 0;
2052
+ if (Array.isArray(deployments) && deployments.length === 0) return failed("The Cloudflare Worker has no deployments.");
2053
+ if (!Array.isArray(deployments) || !record(deployments[0])) return failed("The Cloudflare Worker deployment was not readable.");
2054
+ return {
2055
+ ...result,
2056
+ stdout: JSON.stringify(deployments[0])
2057
+ };
2058
+ }
2059
+ if (args[0] === "versions" && args[1] === "list") {
2060
+ const pageSize = 10;
2061
+ const readPage = async (page) => {
2062
+ const result = await run([
2063
+ "workers",
2064
+ "versions",
2065
+ "list",
2066
+ "--worker-id",
2067
+ workerName,
2068
+ "--per-page",
2069
+ String(pageSize),
2070
+ "--page",
2071
+ String(page)
2072
+ ], true);
2073
+ const body = parseJson(result.stdout);
2074
+ return {
2075
+ result,
2076
+ 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
2077
+ };
2078
+ };
2079
+ const first = await readPage(1);
2080
+ if (first.result.status !== 0) return first.result;
2081
+ if (!first.versions) return failed("The Cloudflare Worker version list was not readable.");
2082
+ const versions = [...first.versions];
2083
+ if (versions.length === pageSize) {
2084
+ const second = await readPage(2);
2085
+ if (second.result.status !== 0 || !second.versions) return failed("The Cloudflare Worker version history was not readable.");
2086
+ if (second.versions.length > 0) {
2087
+ const firstNumbers = versions.map((item) => item.number);
2088
+ const secondNumbers = second.versions.map((item) => item.number);
2089
+ if (Math.min(...secondNumbers) > Math.max(...firstNumbers)) {
2090
+ versions.push(...second.versions);
2091
+ let last = Math.max(...secondNumbers);
2092
+ for (let page = 3; page <= 1e3 && second.versions.length === pageSize; page++) {
2093
+ const next = await readPage(page);
2094
+ if (next.result.status !== 0 || !next.versions) return failed("The Cloudflare Worker version history was not readable.");
2095
+ if (next.versions.length === 0) break;
2096
+ const numbers = next.versions.map((item) => item.number);
2097
+ if (Math.min(...numbers) <= last) return failed("The Cloudflare Worker version history changed during inspection.");
2098
+ versions.push(...next.versions);
2099
+ last = Math.max(...numbers);
2100
+ if (next.versions.length < pageSize) break;
2101
+ if (page === 1e3) return failed("The Cloudflare Worker version history is too large to verify.");
2102
+ }
2103
+ } else if (Math.max(...secondNumbers) >= Math.min(...firstNumbers)) return failed("The Cloudflare Worker version history changed during inspection.");
2104
+ }
2105
+ }
2106
+ return {
2107
+ ...first.result,
2108
+ stdout: JSON.stringify(versions.sort((a, b) => a.number - b.number).slice(-10))
2109
+ };
2110
+ }
2111
+ if (args[0] === "versions" && args[1] === "view" && args[2]) {
2112
+ const result = await run([
2113
+ "workers",
2114
+ "versions",
2115
+ "get",
2116
+ args[2],
2117
+ "--worker-id",
2118
+ workerName
2119
+ ], true);
2120
+ if (result.status !== 0) return result;
2121
+ const version = parseJson(result.stdout);
2122
+ if (!record(version) || version.id !== args[2] || !Array.isArray(version.bindings)) return failed("The Cloudflare Worker version was not readable.");
2123
+ return {
2124
+ ...result,
2125
+ stdout: JSON.stringify({
2126
+ ...version,
2127
+ resources: { bindings: version.bindings }
2128
+ })
2129
+ };
2130
+ }
2131
+ if (args[0] === "versions" && args[1] === "upload") {
2132
+ if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare version upload target changed.");
2133
+ const verified = await verifyResources(output.directory);
2134
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2135
+ return run([
2136
+ "workers",
2137
+ "versions",
2138
+ "create",
2139
+ "--prebuilt",
2140
+ ...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
2141
+ ...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : [],
2142
+ ...flag(args, "--preview-alias") ? ["--preview-alias", flag(args, "--preview-alias")] : []
2143
+ ], command.capture);
2144
+ }
2145
+ if (args[0] === "versions" && args[1] === "deploy") {
2146
+ if (flag(args, "--name") !== workerName) return failed("The Cloudflare deployment target changed.");
2147
+ const flagsStart = args.findIndex((item, index) => index >= 2 && item.startsWith("-"));
2148
+ const versions = args.slice(2, flagsStart < 0 ? void 0 : flagsStart);
2149
+ if (!versions.every((item) => /^[0-9a-f-]{36}@\d+(?:\.\d+)?$/i.test(item))) return failed("The Cloudflare deployment versions were invalid.");
2150
+ const parsed = versions.map((item) => {
2151
+ const [version_id, percentage] = item.split("@");
2152
+ return {
2153
+ version_id,
2154
+ percentage: Number(percentage)
2155
+ };
2156
+ });
2157
+ 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.");
2158
+ return run([
2159
+ "workers",
2160
+ "deployments",
2161
+ "create",
2162
+ "--worker",
2163
+ workerName,
2164
+ "--strategy",
2165
+ "percentage",
2166
+ "--versions",
2167
+ JSON.stringify(parsed),
2168
+ ...flag(args, "--message") ? ["--body", JSON.stringify({
2169
+ strategy: "percentage",
2170
+ versions: parsed,
2171
+ annotations: { "workers/message": flag(args, "--message") }
2172
+ })] : []
2173
+ ], command.capture);
2174
+ }
2175
+ if (args[0] === "deploy") {
2176
+ if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare bootstrap target changed.");
2177
+ const verified = await verifyResources(output.directory);
2178
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2179
+ return run([
2180
+ "deploy",
2181
+ "--prebuilt",
2182
+ ...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
2183
+ ...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : []
2184
+ ], command.capture);
2185
+ }
2186
+ if (args[0] === "triggers" && args[1] === "deploy") {
2187
+ const configPath = flag(args, "-c");
2188
+ if (!configPath || flag(args, "--name") !== workerName) return failed("The Cloudflare trigger target changed.");
2189
+ const raw = parseJson(readFileSync(configPath, "utf8"));
2190
+ if (!record(raw) || raw.name !== workerName) return failed("The Cloudflare trigger snapshot was not readable.");
2191
+ const directory = mkdtempSync(join(tmpdir(), "void-cf-triggers-"));
2192
+ try {
2193
+ cpSync(join(output.directory, ".cloudflare"), join(directory, ".cloudflare"), { recursive: true });
2194
+ const workerPath = getWorkerConfigPath(directory);
2195
+ const worker = parseJson(readFileSync(workerPath, "utf8"));
2196
+ if (!record(worker)) return failed("The private Cloudflare Worker config was not readable.");
2197
+ const migrated = migrateBuiltWranglerConfig({
2198
+ ...raw,
2199
+ compatibility_date: worker.compatibilityDate
2200
+ }).worker;
2201
+ if (!migrated) return failed("The Cloudflare trigger snapshot was not convertible.");
2202
+ const next = migrated.triggers ?? [];
2203
+ const previous = Array.isArray(worker.triggers) ? worker.triggers : [];
2204
+ const preserveRoutes = raw.routes === void 0 && raw.route === void 0;
2205
+ const preserveEmail = raw.addresses === void 0;
2206
+ worker.triggers = [
2207
+ ...next,
2208
+ ...preserveRoutes ? previous.filter((trigger) => record(trigger) && trigger.type === "fetch") : [],
2209
+ ...preserveEmail ? previous.filter((trigger) => record(trigger) && trigger.type === "email") : []
2210
+ ];
2211
+ for (const field of ["env", "exports"]) {
2212
+ const previous = record(worker[field]) ? worker[field] : {};
2213
+ worker[field] = {
2214
+ ...Object.fromEntries(Object.entries(previous).filter(([, value]) => !record(value) || value.type !== "workflow")),
2215
+ ...migrated[field]
2216
+ };
2217
+ }
2218
+ if (!preserveRoutes) worker.domains = migrated.domains ?? [];
2219
+ if (typeof raw.workers_dev === "boolean") worker.workersDev = raw.workers_dev;
2220
+ if (typeof raw.preview_urls === "boolean") worker.previewUrls = raw.preview_urls;
2221
+ writeFileSync(workerPath, JSON.stringify(worker), { mode: 384 });
2222
+ await readBuildOutput(directory);
2223
+ const verified = await verifyResources(directory);
2224
+ if (verified.status !== 0 || verified.signal || verified.error) return verified;
2225
+ return await run([
2226
+ "workers",
2227
+ "triggers",
2228
+ "deploy",
2229
+ "--prebuilt"
2230
+ ], command.capture, directory);
2231
+ } finally {
2232
+ rmSync(directory, {
2233
+ recursive: true,
2234
+ force: true
2235
+ });
2236
+ }
2237
+ }
2238
+ if (args[0] === "queues" && args[1] === "consumer" && args[2] === "remove") {
2239
+ const queueName = args[3];
2240
+ if (!queueName || args[4] !== workerName) return failed("The Cloudflare Queue consumer target changed.");
2241
+ const queues = await run(["queues", "list"], true);
2242
+ if (queues.status !== 0) return queues;
2243
+ const allQueues = parseJson(queues.stdout);
2244
+ if (!Array.isArray(allQueues)) return failed("The Cloudflare Queue list was not readable.");
2245
+ const queue = allQueues.find((item) => record(item) && item.queue_name === queueName);
2246
+ if (!record(queue) || typeof queue.queue_id !== "string") return failed(`Cloudflare Queue ${queueName} was not found.`);
2247
+ const consumers = await run([
2248
+ "queues",
2249
+ "consumers",
2250
+ "list",
2251
+ "--queue-id",
2252
+ queue.queue_id
2253
+ ], true);
2254
+ if (consumers.status !== 0) return consumers;
2255
+ const allConsumers = parseJson(consumers.stdout);
2256
+ if (!Array.isArray(allConsumers)) return failed("The Cloudflare Queue consumers were not readable.");
2257
+ const matching = allConsumers.filter((item) => record(item) && item.script === workerName);
2258
+ if (matching.length === 0) return {
2259
+ status: 0,
2260
+ stdout: "",
2261
+ stderr: ""
2262
+ };
2263
+ if (matching.length !== 1 || !record(matching[0]) || typeof matching[0].consumer_id !== "string") return failed("The Cloudflare Queue consumer identity was ambiguous.");
2264
+ return run([
2265
+ "queues",
2266
+ "consumers",
2267
+ "delete",
2268
+ matching[0].consumer_id,
2269
+ "--queue-id",
2270
+ queue.queue_id,
2271
+ "--force"
2272
+ ], command.capture);
2273
+ }
2274
+ return failed(`Unsupported Cloudflare activation operation: ${args[0] ?? ""} ${args[1] ?? ""}`);
2275
+ };
2276
+ }
2277
+ //#endregion
1848
2278
  //#region src/cli/cloudflare-deploy/classify.ts
1849
2279
  /**
1850
2280
  * Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
@@ -1860,14 +2290,14 @@ function classifyCloudflareDeployApp(root, voidConfig, options) {
1860
2290
  if (framework) {
1861
2291
  if (!FRAMEWORK_PRESETS[framework.name]) return unsupported(`deploy: --platform cloudflare has no deployment preset for framework ${framework.name}.`);
1862
2292
  }
1863
- const staticPreset = detectPreset(root, {
2293
+ const staticPreset = framework ? null : detectPreset(root, {
1864
2294
  dir: options.dir,
1865
2295
  spa: options.spa
1866
2296
  });
1867
2297
  const configuredStatic = voidConfig.inference?.appType === "static" || voidConfig.inference?.appType === "spa";
1868
2298
  if (staticPreset || configuredStatic || options.dir || options.spa) return unsupported([
1869
2299
  `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,",
2300
+ "Set inference.outputDir in void.config.ts, pass --dir with an existing build directory,",
1871
2301
  "or add a supported build tool so Void can locate the generated static assets."
1872
2302
  ].join("\n"));
1873
2303
  if (!framework && !hasBackendFiles(root)) return unsupported([
@@ -1910,7 +2340,7 @@ function approvedCloudflareIsrBinding(config, rootConfig) {
1910
2340
  /** Persist the migration decision in source configuration, not a temporary link marker. */
1911
2341
  async function chooseCloudflareIsr(root, config, options) {
1912
2342
  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`.");
2343
+ 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
2344
  const enabled = await (options.confirm ?? (async (message) => {
1915
2345
  const answer = await confirm({
1916
2346
  message,
@@ -1918,18 +2348,27 @@ async function chooseCloudflareIsr(root, config, options) {
1918
2348
  });
1919
2349
  if (isCancel(answer)) throw new Error("ISR setup cancelled. Rerun `void deploy` to finish linking.");
1920
2350
  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
- } })));
2351
+ }))("Enable ISR caching for this app? Yes provisions a Cloudflare KV cache; No keeps caching disabled until you change void.config.ts.");
2352
+ if (existsSync(join(root, "void.config.ts"))) writeVoidProjectConfig(root, {
2353
+ ...config,
2354
+ routing: {
2355
+ ...config.routing,
2356
+ isr: enabled
2357
+ }
2358
+ });
2359
+ else {
2360
+ const path = join(root, "void.json");
2361
+ const source = existsSync(path) ? readFileSync(path, "utf8") : "{}\n";
2362
+ writeFileSync(path, applyEdits(source, modify(source, ["routing", "isr"], enabled, { formattingOptions: {
2363
+ insertSpaces: true,
2364
+ tabSize: 2
2365
+ } })));
2366
+ }
1928
2367
  config.routing = {
1929
2368
  ...config.routing,
1930
2369
  isr: enabled
1931
2370
  };
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"}.`);
2371
+ 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
2372
  return enabled;
1934
2373
  }
1935
2374
  //#endregion
@@ -2014,22 +2453,25 @@ async function prepareExistingCloudflareDeploy(options) {
2014
2453
  workerName: config.name
2015
2454
  });
2016
2455
  writeFileSync(options.configPath, updated);
2456
+ persistCloudflareConfig(options.root);
2017
2457
  return existing;
2018
2458
  }
2019
2459
  /** Offer the existing destination before the legacy hosted-platform fallback. */
2020
2460
  async function maybeLinkCloudflareDeploy(root, options = {}, deps = {}) {
2021
2461
  if (options.platform || options.backend || options.projectSlug || process.env.VOID_PROJECT || readDeploymentPlatform(root) !== null) return null;
2022
- const files = [
2462
+ const files = [.../* @__PURE__ */ new Set([...[
2023
2463
  "wrangler.jsonc",
2024
2464
  "wrangler.json",
2025
2465
  "wrangler.toml"
2026
- ].filter((name) => existsSync(join(root, name)));
2027
- if (!files.length) return null;
2466
+ ].filter((name) => existsSync(join(root, name))), ...discoverFrameworkWranglerFiles(root)])];
2467
+ if (!files.length && !existsSync(join(root, "void.config.ts"))) return null;
2028
2468
  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];
2469
+ const name = files[0] ?? ".void-wrangler.jsonc";
2030
2470
  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
2471
  const errors = [];
2032
- const config = parse(readFileSync(join(root, name), "utf8"), errors, { allowTrailingComma: true });
2472
+ const configPath = files.length ? join(root, name) : materializeCloudflareConfig(root);
2473
+ const config = parse(readFileSync(configPath, "utf8"), errors, { allowTrailingComma: true });
2474
+ if (!files.length && (!config || typeof config.name !== "string" || !config.name.trim())) return null;
2033
2475
  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
2476
  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
2477
  log$1.info(`Found ${basename(name)} for Worker "${config.name}".`);
@@ -2084,6 +2526,44 @@ function readCloudflareLocalState(root) {
2084
2526
  }
2085
2527
  }
2086
2528
  //#endregion
2529
+ //#region src/cli/installed-void.ts
2530
+ /** A global CLI still builds with the project's installed Vite plugin. */
2531
+ function assertInstalledVoidMatchesCli(root) {
2532
+ const projectManifest = join(root, "package.json");
2533
+ if (!existsSync(projectManifest)) return;
2534
+ const project = JSON.parse(readFileSync(projectManifest, "utf8"));
2535
+ if (![
2536
+ "dependencies",
2537
+ "devDependencies",
2538
+ "optionalDependencies"
2539
+ ].some((key) => {
2540
+ const dependencies = project[key];
2541
+ return typeof dependencies === "object" && dependencies !== null && "void" in dependencies;
2542
+ })) return;
2543
+ const cliPackageDir = getPackageDir();
2544
+ const cli = JSON.parse(readFileSync(join(cliPackageDir, "package.json"), "utf8"));
2545
+ let installedVersion;
2546
+ let installedPackageDir;
2547
+ try {
2548
+ const entry = createRequire(projectManifest).resolve("void");
2549
+ let directory = dirname(entry);
2550
+ for (let depth = 0; depth < 8; depth++) {
2551
+ const manifest = join(directory, "package.json");
2552
+ if (existsSync(manifest)) {
2553
+ const installed = JSON.parse(readFileSync(manifest, "utf8"));
2554
+ if (installed.name === "void") {
2555
+ installedVersion = installed.version;
2556
+ installedPackageDir = directory;
2557
+ break;
2558
+ }
2559
+ }
2560
+ directory = dirname(directory);
2561
+ }
2562
+ } catch {}
2563
+ 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.`);
2564
+ 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.");
2565
+ }
2566
+ //#endregion
2087
2567
  //#region src/cli/deploy-errors.ts
2088
2568
  const BODY_SNIPPET_MAX = 200;
2089
2569
  function trimSnippet(body) {
@@ -3372,7 +3852,7 @@ function selectBundledEntryFilename(outFiles) {
3372
3852
  * Determine whether a wrapper is needed based on the features.
3373
3853
  */
3374
3854
  function needsWrapper(features) {
3375
- return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness;
3855
+ return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness || !!features.isr;
3376
3856
  }
3377
3857
  /**
3378
3858
  * Generate a wrapper entry in-place in the worker directory.
@@ -3424,8 +3904,8 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3424
3904
  let migrations;
3425
3905
  let migrationPlanBundle;
3426
3906
  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);
3907
+ const { collectMigrations } = await import("./collect-DAUItMDS.mjs");
3908
+ const { buildMigrationPlanBundle } = await import("./plan-DpuOr14e.mjs");
3429
3909
  const migrationsDir = readProjectPaths(root).migrationsDir;
3430
3910
  migrations = collectMigrations(migrationsDir);
3431
3911
  migrationPlanBundle = features.migrationDialect === "sqlite" ? buildMigrationPlanBundle(migrations) : void 0;
@@ -3438,6 +3918,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3438
3918
  if (!existsSync(handlerPath)) throw new Error(`Migration handler not found: ${handlerFilename_}. Run "pnpm -C packages/void build" first.`);
3439
3919
  await bundleMigrationHandler(root, workerDir, handlerPath, features.migrationDialect ?? "sqlite");
3440
3920
  }
3921
+ if (features.isr) await bundleFrameworkIsr(root, workerDir);
3441
3922
  const wrapperSource = generateWrapperSource(renamedName, handlerFilename, features, migrations, migrationPlanBundle);
3442
3923
  const stagedPath = `${mainPath}.${crypto.randomUUID()}.tmp`;
3443
3924
  try {
@@ -3448,6 +3929,33 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3448
3929
  rmSync(stagedPath, { force: true });
3449
3930
  }
3450
3931
  }
3932
+ async function bundleFrameworkIsr(root, workerDir) {
3933
+ const entry = fileURLToPath(import.meta.resolve("@void/isr/runtime"));
3934
+ const tmpDir = join(root, ".void", "isr");
3935
+ const outDir = join(tmpDir, "out");
3936
+ mkdirSync(tmpDir, { recursive: true });
3937
+ await build({
3938
+ root: tmpDir,
3939
+ logLevel: "silent",
3940
+ ssr: { noExternal: true },
3941
+ build: {
3942
+ outDir,
3943
+ emptyOutDir: true,
3944
+ minify: false,
3945
+ ssr: entry,
3946
+ target: "esnext",
3947
+ rollupOptions: {
3948
+ input: entry,
3949
+ external: [/^cloudflare:/, /^node:/],
3950
+ output: {
3951
+ entryFileNames: "__void_isr.mjs",
3952
+ chunkFileNames: "__void_isr-[hash].mjs"
3953
+ }
3954
+ }
3955
+ }
3956
+ });
3957
+ for (const file of readdirSync(outDir)) copyFileSync(join(outDir, file), join(workerDir, file));
3958
+ }
3451
3959
  async function bundleMigrationHandler(root, workerDir, handlerPath, dialect) {
3452
3960
  const tmpDir = join(root, ".void", "migration-handler");
3453
3961
  mkdirSync(tmpDir, { recursive: true });
@@ -3602,6 +4110,7 @@ function cleanupWrapper(root) {
3602
4110
  for (const directory of [
3603
4111
  "handlers",
3604
4112
  "migration-handler",
4113
+ "isr",
3605
4114
  "bundle"
3606
4115
  ]) rmSync(join(voidDir, directory), {
3607
4116
  recursive: true,
@@ -3612,6 +4121,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3612
4121
  const lines = [];
3613
4122
  lines.push(WRAPPER_MARKER);
3614
4123
  lines.push(`import original from "./${renamedEntry}";`);
4124
+ if (features.isr) {
4125
+ lines.push("import { handleFrameworkIsr } from \"./__void_isr.mjs\";");
4126
+ lines.push(`const __voidIsrDeploymentId = ${JSON.stringify(crypto.randomUUID())};`);
4127
+ lines.push(`const __voidIsrPolicy = ${JSON.stringify({
4128
+ revalidate: features.isr.revalidate,
4129
+ queryAllowlist: features.isr.queryAllowlist
4130
+ })};`);
4131
+ }
3615
4132
  if (features.crons.length > 0) lines.push(`import { handleScheduled } from "./${handlersModule}";`);
3616
4133
  if (features.queues.length > 0) lines.push(`import { handleQueue, handleQueueRelay } from "./${handlersModule}";`);
3617
4134
  if (migrations && migrations.length > 0) {
@@ -3621,10 +4138,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3621
4138
  lines.push(`const __migrationDialect = ${JSON.stringify(features.migrationDialect ?? "sqlite")};`);
3622
4139
  }
3623
4140
  lines.push("");
3624
- const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0;
4141
+ const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0 || !!features.isr;
3625
4142
  if (needsFetchWrap) {
3626
4143
  lines.push("async function wrappedFetch(request, env, ctx) {");
3627
4144
  lines.push(" const url = new URL(request.url);");
4145
+ if (features.isr) {
4146
+ lines.push(" env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId;");
4147
+ lines.push(" env.__VOID_ISR_HOST = url.hostname;");
4148
+ }
3628
4149
  if (features.readiness || features.crons.length > 0 || features.queues.length > 0 || features.hasMigrations) {
3629
4150
  lines.push(" if (request.method === \"GET\" && url.pathname === \"/__void/ready\") {");
3630
4151
  lines.push(" return Response.json({ ready: true });");
@@ -3686,6 +4207,12 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3686
4207
  lines.push(" }");
3687
4208
  lines.push(" }");
3688
4209
  }
4210
+ if (features.isr) {
4211
+ lines.push(" if (env.ISR_CACHE && request.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\") {");
4212
+ lines.push(" const cached = await handleFrameworkIsr(request, env, ctx, { ...__voidIsrPolicy, deploymentId: __voidIsrDeploymentId }, (req) => original.fetch(req, env, ctx));");
4213
+ lines.push(" if (cached) return cached;");
4214
+ lines.push(" }");
4215
+ }
3689
4216
  lines.push(" return original.fetch(request, env, ctx);");
3690
4217
  lines.push("}");
3691
4218
  lines.push("");
@@ -3693,8 +4220,8 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
3693
4220
  lines.push("export default {");
3694
4221
  if (needsFetchWrap) lines.push(" fetch: wrappedFetch,");
3695
4222
  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,");
4223
+ 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,");
4224
+ 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
4225
  lines.push("};");
3699
4226
  return lines.join("\n");
3700
4227
  }
@@ -3782,66 +4309,6 @@ export async function handleQueueRelay(payload, env, ctx) {
3782
4309
  }
3783
4310
  //#endregion
3784
4311
  //#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
4312
  const drizzleKitBin = join(fileURLToPath(import.meta.resolve("drizzle-kit")), "..", "bin.cjs");
3846
4313
  const deployDriftCheckDir = join(".void", "deploy-drift-check");
3847
4314
  let loadedProvisionModule;
@@ -3851,7 +4318,7 @@ let loadedProvisionModule;
3851
4318
  * so a managed deploy never imports it — and thus never loads `proper-lockfile`.
3852
4319
  */
3853
4320
  async function loadProvisionModule() {
3854
- loadedProvisionModule ??= await import("./provision-CSJOjjQk.mjs").then((n) => n.a);
4321
+ loadedProvisionModule ??= await import("./provision-CNgEBkVA.mjs");
3855
4322
  return loadedProvisionModule;
3856
4323
  }
3857
4324
  /**
@@ -4438,6 +4905,34 @@ function hashWranglerUploader(root, resolveArgv = resolveWranglerArgv) {
4438
4905
  if (typeof entry !== "string" || entry.length === 0 || !existsSync(entry)) return;
4439
4906
  return hashDirectoryContents(dirname(entry));
4440
4907
  }
4908
+ /** Pin the cf uploader and prebuilt-artifact builders before project code runs. */
4909
+ function hashCfUploader() {
4910
+ try {
4911
+ const hash = createHash("sha256");
4912
+ for (const name of [
4913
+ "cf",
4914
+ "@cloudflare/config",
4915
+ "@cloudflare/build-output-utils",
4916
+ "vite"
4917
+ ]) {
4918
+ let path = dirname(fileURLToPath(import.meta.resolve(name)));
4919
+ while (!existsSync(join(path, "package.json"))) {
4920
+ const parent = dirname(path);
4921
+ if (parent === path) return;
4922
+ path = parent;
4923
+ }
4924
+ const contents = hashDirectoryContents(path);
4925
+ if (!contents) return;
4926
+ hash.update(name);
4927
+ hash.update("\0");
4928
+ hash.update(contents);
4929
+ hash.update("\0");
4930
+ }
4931
+ return hash.digest("hex");
4932
+ } catch {
4933
+ return;
4934
+ }
4935
+ }
4441
4936
  /**
4442
4937
  * sha256 over every file under `dir`, walked in a STABLE (name-sorted, depth-first) order with
4443
4938
  * each file's relative path folded into the digest, so the hash depends only on the directory's
@@ -4475,11 +4970,11 @@ function hashDirectoryContents(dir) {
4475
4970
  function assertWranglerUploaderUnchanged(before, after) {
4476
4971
  if (before === void 0 || after === void 0) return {
4477
4972
  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.`
4973
+ 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
4974
  };
4480
4975
  if (before !== after) return {
4481
4976
  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.`
4977
+ reason: `the build modified the Cloudflare uploader (its bundle hash changed across the build) — refusing to run it with your Cloudflare credentials.`
4483
4978
  };
4484
4979
  return { ok: true };
4485
4980
  }
@@ -4732,14 +5227,12 @@ function resolveGeneratedDeployConfigPathDefault(root) {
4732
5227
  function readGeneratedDeployConfig(root) {
4733
5228
  const redirectedPath = resolveGeneratedDeployConfigPathDefault(root);
4734
5229
  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
5230
  return {
4738
5231
  path: redirectedPath,
4739
- config
5232
+ config: readGeneratedWranglerConfigFile(redirectedPath)
4740
5233
  };
4741
5234
  } catch {
4742
- throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON.`);
5235
+ throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON/JSONC.`);
4743
5236
  }
4744
5237
  }
4745
5238
  /** Older project plugins can repeat root flags; normalize only the generated artifact. */
@@ -4827,11 +5320,11 @@ function verifyGeneratedDeployConfig(root, expected) {
4827
5320
  };
4828
5321
  let generated;
4829
5322
  try {
4830
- generated = JSON.parse(readFileSync(redirectedPath, "utf-8"));
5323
+ generated = readGeneratedWranglerConfigFile(redirectedPath);
4831
5324
  } catch {
4832
5325
  return {
4833
5326
  ok: false,
4834
- reason: `generated wrangler config ${redirectedPath} is not valid JSON.`
5327
+ reason: `generated wrangler config ${redirectedPath} is not valid JSON/JSONC.`
4835
5328
  };
4836
5329
  }
4837
5330
  if (generated.account_id !== expected.accountId) return {
@@ -5640,31 +6133,28 @@ async function checkWranglerMigrationApplySet(configPath, config, binding, migra
5640
6133
  * child env (via {@link deployChildEnv} — reused provisioner scrub/pin: CF Access +
5641
6134
  * every transport selector incl. `CLOUDFLARE_ENV` + the deploy config-override vars
5642
6135
  * scrubbed, one account + API base pinned), so `whoami`/`migrate`/`deploy` can never
5643
- * consult a different ambient account or endpoint. `capture` pipes or inherits stdio;
5644
- * `opts.env` layers one more pin over the child env for a single spawn (`auth token` gets
6136
+ * consult a different ambient account or endpoint. Noninteractive output is captured so Void
6137
+ * controls the terminal; browser login still inherits stdio. `opts.env` layers one more pin
6138
+ * over the child env for a single spawn (`auth token` gets
5645
6139
  * `WRANGLER_WRITE_LOGS=false`, see {@link runWranglerAuthToken}).
5646
6140
  */
5647
6141
  function createDeployWranglerRunner(root, accountId, apiBaseUrl) {
5648
6142
  const [command, ...prefix] = resolveWranglerArgv(root);
5649
6143
  return (args, opts) => {
5650
6144
  const childEnv = deployChildEnv(accountId, apiBaseUrl);
5651
- const keyringTerminal = cloudflareKeyringNeedsTerminal(args);
5652
- if (!opts.capture || keyringTerminal) childEnv.WRANGLER_LOG = "none";
6145
+ const interactiveLogin = cloudflareAuthNeedsTerminal(args);
6146
+ if (!opts.capture || interactiveLogin) childEnv.WRANGLER_LOG = "none";
5653
6147
  if (opts.env) Object.assign(childEnv, opts.env);
5654
6148
  const result = spawnSync(command, [...prefix, ...args], {
5655
6149
  cwd: root,
5656
- stdio: keyringTerminal ? [
5657
- "inherit",
5658
- "inherit",
5659
- "ignore"
5660
- ] : opts.input === void 0 ? opts.capture ? [
6150
+ stdio: interactiveLogin ? "inherit" : opts.input === void 0 ? [
5661
6151
  "ignore",
5662
6152
  "pipe",
5663
6153
  "pipe"
5664
- ] : "inherit" : [
6154
+ ] : [
5665
6155
  "pipe",
5666
- opts.capture ? "pipe" : "inherit",
5667
- opts.capture ? "pipe" : "inherit"
6156
+ "pipe",
6157
+ "pipe"
5668
6158
  ],
5669
6159
  input: opts.input,
5670
6160
  encoding: "utf-8",
@@ -5791,7 +6281,7 @@ async function runCloudflareEmailStep(input) {
5791
6281
  };
5792
6282
  const from = input.voidConfig.email?.from;
5793
6283
  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"));
6284
+ 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
6285
  return without;
5796
6286
  }
5797
6287
  const { rootConfig } = input;
@@ -5900,7 +6390,7 @@ async function runCloudflareEmailStep(input) {
5900
6390
  };
5901
6391
  };
5902
6392
  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"));
6393
+ 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
6394
  if (!await input.confirm(`Set up email on ${pre.domain}?`)) return leaveAccount("email setup skipped — run `void email setup --platform cloudflare` later.");
5905
6395
  const out = await applyEmailSetup(pre, inputs);
5906
6396
  if (out.lines.length > 0) log.message(out.lines.join("\n"));
@@ -5962,6 +6452,11 @@ async function ensureCloudflareAuthSecret(options) {
5962
6452
  };
5963
6453
  if ((await list(true)).includes(BETTER_AUTH_SECRET_NAME)) return { created: false };
5964
6454
  const secret = randomBytes(32).toString("hex");
6455
+ if (workerWasMissing) return {
6456
+ created: true,
6457
+ workerWasMissing: true,
6458
+ candidateSecret: secret
6459
+ };
5965
6460
  beforeRun();
5966
6461
  let put;
5967
6462
  try {
@@ -5979,8 +6474,8 @@ async function ensureCloudflareAuthSecret(options) {
5979
6474
  } catch {
5980
6475
  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
6476
  }
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");
6477
+ 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");
6478
+ 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
6479
  return {
5985
6480
  created: true,
5986
6481
  ...workerWasMissing ? { workerWasMissing: true } : {}
@@ -6080,10 +6575,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6080
6575
  }
6081
6576
  const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
6082
6577
  const wranglerUploaderHashBefore = hashUploader(root);
6578
+ const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
6579
+ const cfUploaderIsPinned = () => {
6580
+ const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
6581
+ if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
6582
+ return matched;
6583
+ };
6083
6584
  const assertUploaderStillPinned = () => {
6084
6585
  const check = assertWranglerUploaderUnchanged(wranglerUploaderHashBefore, hashUploader(root));
6085
6586
  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"));
6587
+ log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", check.reason].filter(Boolean).join("\n"));
6087
6588
  return false;
6088
6589
  };
6089
6590
  let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
@@ -6148,10 +6649,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6148
6649
  const staleAddresses = Array.isArray(rootConfig.addresses) ? rootConfig.addresses.filter((a) => typeof a === "string") : [];
6149
6650
  const staleBinding = Array.isArray(rootConfig.send_email) && rootConfig.send_email.some((e) => e?.name === "SEND_EMAIL");
6150
6651
  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:",
6652
+ "deploy: this app no longer declares email handlers or imports void/email, but the Cloudflare config still carries the email setup Void wrote:",
6152
6653
  ...staleAddresses.map((a) => ` • ${a} — still routed to worker "${workerName}", which no longer exports email(); inbound mail there will fail.`),
6153
6654
  ...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."
6655
+ "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
6656
  ].join("\n"));
6156
6657
  }
6157
6658
  const schemaProbeEnv = buildSchemaProbeEnv(accountId, apiBaseUrl);
@@ -6255,7 +6756,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6255
6756
  const provisionAndVerify = async () => {
6256
6757
  if (existingWorker) {
6257
6758
  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.");
6759
+ 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
6760
  }
6260
6761
  if (!assertUploaderStillPinned()) return exit(1);
6261
6762
  const provision = deps.provision ?? provisionModule.provisionCloudflareResources;
@@ -6381,8 +6882,9 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6381
6882
  log.error(`deploy: build failed — ${getErrorMessage(err)}`);
6382
6883
  return exit(getExitCode(err));
6383
6884
  }
6885
+ log.step("Preparing deployment...");
6384
6886
  if (detectedFramework && frameworkPreset) try {
6385
- await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys);
6887
+ await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys, needsAI ? { binding: aiBindingName } : void 0);
6386
6888
  } catch (error) {
6387
6889
  log.error(`deploy: could not prepare ${detectedFramework.name} for Cloudflare — ${getErrorMessage(error)}`);
6388
6890
  return exit(1);
@@ -6541,7 +7043,22 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6541
7043
  d1MigrateToken = migrateTarget.token;
6542
7044
  }
6543
7045
  }
7046
+ const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
7047
+ const prepareBuildOutput = () => frameworkPreset?.cloudflareArtifact === "worker-output" ? prepareCfFrameworkBuildOutput({
7048
+ projectRoot: root,
7049
+ configPath: generatedConfigPath,
7050
+ accountId
7051
+ }) : prepareCfBuildOutput(dirname(generatedConfigPath), accountId);
7052
+ if (!deps.activateVersion && !deps.runWrangler) {
7053
+ const preflight = await prepareBuildOutput();
7054
+ if (!preflight) {
7055
+ log.error("deploy: cf could not prepare the built Worker for deployment.");
7056
+ return exit(1);
7057
+ }
7058
+ preflight.dispose();
7059
+ }
6544
7060
  let workerWasMissingBeforeSecretProvisioning = false;
7061
+ let initialAuthSecret;
6545
7062
  if (authEnabled) {
6546
7063
  const inheritance = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, {
6547
7064
  accountId,
@@ -6570,6 +7087,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6570
7087
  beforeWranglerRun: assertUploaderStillPinned
6571
7088
  });
6572
7089
  workerWasMissingBeforeSecretProvisioning ||= authSecret.workerWasMissing === true;
7090
+ initialAuthSecret = authSecret.candidateSecret;
6573
7091
  cliLog.info("cloudflare_auth_secret_ready", { created: authSecret.created });
6574
7092
  } catch (error) {
6575
7093
  if (error instanceof CloudflareAuthSecretError && error.reason === "uploader-changed") return exit(1);
@@ -6611,6 +7129,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6611
7129
  }
6612
7130
  }
6613
7131
  if (d1MigrateToken) {
7132
+ log.step("Applying D1 migrations...");
6614
7133
  if (!assertUploaderStillPinned()) return exit(1);
6615
7134
  const migrate = await Promise.resolve(runWrangler([
6616
7135
  "d1",
@@ -6686,23 +7205,35 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6686
7205
  ].filter(Boolean).join("\n"));
6687
7206
  return exit(1);
6688
7207
  }
6689
- const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
6690
7208
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
6691
7209
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
6692
7210
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
6693
- const activationRunner = preBuildRootConfig.compliance_region ? runWrangler : createCloudflareMetadataRunner({
6694
- runWrangler,
7211
+ if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7212
+ const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareBuildOutput();
7213
+ if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
7214
+ log.error("deploy: cf could not prepare the built Worker for deployment.");
7215
+ return exit(1);
7216
+ }
7217
+ const cfCommand = cfOutput ? createCfCommand({
6695
7218
  accountId,
6696
7219
  apiBaseUrl,
7220
+ env: deployChildEnv,
7221
+ verifyUploader: cfUploaderIsPinned
7222
+ }) : null;
7223
+ const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
7224
+ output: cfOutput,
6697
7225
  workerName,
6698
- configPath: generatedConfigPath,
6699
- fetch: deps.metadataFetch,
6700
- verifyUploader: assertUploaderStillPinned,
6701
- getToken: () => runWranglerAuthToken(runWrangler, generatedConfigPath)
6702
- });
6703
- const execution = await (deps.activateVersion ?? activateCloudflareVersion)({
7226
+ runCf: cfCommand,
7227
+ verifyResources: createCfResourceVerifier({
7228
+ configPath: generatedConfigPath,
7229
+ runCf: cfCommand,
7230
+ runWrangler,
7231
+ verifyCompatibilityRunner: assertUploaderStillPinned
7232
+ })
7233
+ }) : runWrangler;
7234
+ const execution = await activateCloudflareVersionWithProgress(deps.activateVersion ?? activateCloudflareVersion, {
6704
7235
  runWrangler: activationRunner,
6705
- verifyUploader: assertUploaderStillPinned,
7236
+ verifyUploader: cfOutput ? cfUploaderIsPinned : assertUploaderStillPinned,
6706
7237
  workerName,
6707
7238
  configPath: generatedConfigPath,
6708
7239
  preserveTriggers: existingWorker !== null,
@@ -6734,10 +7265,18 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6734
7265
  workerName,
6735
7266
  runWrangler
6736
7267
  }),
7268
+ publishEmptyCrons: createCloudflareEmptyCronPublisher({
7269
+ accountId,
7270
+ apiBaseUrl,
7271
+ configPath: generatedConfigPath,
7272
+ workerName,
7273
+ runWrangler
7274
+ }),
6737
7275
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
6738
7276
  queueConsumerCleanup,
6739
- verifyInheritedSecrets: true
6740
- });
7277
+ verifyInheritedSecrets: true,
7278
+ ...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
7279
+ }).finally(() => cfOutput?.dispose());
6741
7280
  if (!execution.ok) {
6742
7281
  await reportCloudflareActivationFailure(cliLog, needsSandbox && execution.containersUnavailable ? formatCloudflareSandboxUnavailable() : formatCloudflareActivationError(execution));
6743
7282
  return exit(1);
@@ -6765,11 +7304,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6765
7304
  */
6766
7305
  function discoverRootWranglerConfig(root) {
6767
7306
  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");
7307
+ return materializeCloudflareConfig(root);
6773
7308
  }
6774
7309
  /** Avoid making Wrangler open a config path that Void has not created yet. */
6775
7310
  function existingWranglerConfigArgs(configPath) {
@@ -6780,6 +7315,18 @@ async function reportCloudflareActivationFailure(cliLog, message) {
6780
7315
  await cliLog.close().catch(() => {});
6781
7316
  log.error(`${message}${cliLog.path ? `\n\nDetailed log: ${cliLog.path}` : ""}`);
6782
7317
  }
7318
+ async function activateCloudflareVersionWithProgress(activate, options) {
7319
+ const progress = createSpinner();
7320
+ progress.start("Checking the current Worker deployment...");
7321
+ try {
7322
+ return await activate({
7323
+ ...options,
7324
+ onProgress: (message) => progress.message(message)
7325
+ });
7326
+ } finally {
7327
+ progress.stop();
7328
+ }
7329
+ }
6783
7330
  function formatCloudflareActivationError(result) {
6784
7331
  const status = result.status === void 0 ? "" : ` (exit ${String(result.status)})`;
6785
7332
  const cloudflareCode = result.cloudflareErrorCode === void 0 ? "" : ` Cloudflare error code: ${String(result.cloudflareErrorCode)}.`;
@@ -6819,6 +7366,7 @@ function formatCloudflareActivationError(result) {
6819
7366
  "deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
6820
7367
  "For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token.",
6821
7368
  "For a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
7369
+ "If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
6822
7370
  `Then retry. ${formatCloudflareReadinessRestoration(result)}`
6823
7371
  ].join("\n");
6824
7372
  case "bootstrap-failed": return `deploy: Cloudflare could not bootstrap the first Worker deployment${status}.${cloudflareCode}${diagnostic}`;
@@ -6832,6 +7380,7 @@ function formatCloudflareActivationError(result) {
6832
7380
  "deploy: Cloudflare Access blocked the first Worker deployment readiness probe.",
6833
7381
  "For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token;",
6834
7382
  "for a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
7383
+ "If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
6835
7384
  "Then retry. Cloudflare requires the first deployment to be non-versioned, so the new",
6836
7385
  "Worker is already active behind Access."
6837
7386
  ].join("\n");
@@ -6857,7 +7406,7 @@ function cloudflareWorkerReadinessHeaders() {
6857
7406
  });
6858
7407
  }
6859
7408
  /** 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 = []) {
7409
+ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = [], ai) {
6861
7410
  const workerMain = join(root, preset.workerDir, preset.workerMain);
6862
7411
  const assetsDirectory = join(root, preset.assetsDir);
6863
7412
  if (!existsSync(workerMain)) throw new Error(`framework ${framework.name} did not emit its Worker entry at ${preset.workerDir}/${preset.workerMain}`);
@@ -6865,13 +7414,18 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
6865
7414
  const paths = resolveProjectPaths(root, voidConfig);
6866
7415
  const crons = scanJobsSync(root, paths.cronsDir);
6867
7416
  const queues = scanQueuesSync(root, paths.queuesDir);
7417
+ const revalidate = collectRevalidate(voidConfig, null);
6868
7418
  await generateDeployWrapperIfNeeded(root, join(root, preset.workerDir), preset.workerMain, {
6869
7419
  auth: null,
6870
7420
  crons,
6871
7421
  queues,
6872
7422
  hasMigrations: false,
6873
7423
  migrationDialect: getDatabaseDialect(voidConfig),
6874
- readiness: true
7424
+ readiness: true,
7425
+ ...hasRevalidate(revalidate) && { isr: {
7426
+ revalidate,
7427
+ queryAllowlist: voidConfig.routing?.revalidateQueryAllowlist
7428
+ } }
6875
7429
  });
6876
7430
  if (preset.cloudflareArtifact === "vite-plugin") return;
6877
7431
  const rootConfig = parseRootWranglerConfig(configPath);
@@ -6886,12 +7440,17 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
6886
7440
  compatibilityFlags: preset.cloudflareCompatibilityFlags,
6887
7441
  crons: [...new Set(crons.flatMap((job) => job.crons))],
6888
7442
  requiredSecrets: requiredSecretNames,
7443
+ ...ai ? { ai: {
7444
+ ...ai,
7445
+ gateway: voidConfig.ai?.gateway
7446
+ } } : {},
6889
7447
  ...preset.workerDir === preset.assetsDir ? { assetsIgnore: [
6890
7448
  preset.workerMain,
6891
7449
  "_routes.json",
6892
7450
  "__original.js",
6893
7451
  "__original.mjs",
6894
7452
  "__void_handlers.mjs",
7453
+ "__void_isr*.mjs",
6895
7454
  "__void_migration_handler*.mjs"
6896
7455
  ] } : {}
6897
7456
  });
@@ -6961,9 +7520,15 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
6961
7520
  }
6962
7521
  const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
6963
7522
  const uploaderHash = hashUploader(root);
7523
+ const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
7524
+ const cfUploaderIsPinned = () => {
7525
+ const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
7526
+ if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
7527
+ return matched;
7528
+ };
6964
7529
  const uploaderIsPinned = () => {
6965
7530
  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"));
7531
+ if (!result.ok) log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", result.reason].filter(Boolean).join("\n"));
6967
7532
  return result.ok;
6968
7533
  };
6969
7534
  let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
@@ -7036,6 +7601,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7036
7601
  return exit(getExitCode(error));
7037
7602
  }
7038
7603
  }
7604
+ log.step("Preparing deployment...");
7039
7605
  if (!existsSync(preset.outputDir)) {
7040
7606
  log.error(`deploy: Output directory '${preset.outputDir}' not found. Run the build first.`);
7041
7607
  return exit(1);
@@ -7092,19 +7658,37 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7092
7658
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7093
7659
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7094
7660
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7095
- const activationRunner = rootConfig.compliance_region ? runWrangler : createCloudflareMetadataRunner({
7096
- runWrangler,
7661
+ if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7662
+ const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareCfStaticBuildOutput({
7663
+ projectRoot: root,
7664
+ configPath: staticConfigPath,
7665
+ assetsDirectory: stagedAssetsDirectory,
7666
+ accountId
7667
+ });
7668
+ if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
7669
+ log.error("deploy: cf could not prepare the static Worker for deployment.");
7670
+ return exit(1);
7671
+ }
7672
+ const cfCommand = cfOutput ? createCfCommand({
7097
7673
  accountId,
7098
7674
  apiBaseUrl,
7675
+ env: deployChildEnv,
7676
+ verifyUploader: cfUploaderIsPinned
7677
+ }) : null;
7678
+ const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
7679
+ output: cfOutput,
7099
7680
  workerName,
7100
- configPath: staticConfigPath,
7101
- fetch: deps.metadataFetch,
7102
- verifyUploader: uploaderIsPinned,
7103
- getToken: () => runWranglerAuthToken(runWrangler, staticConfigPath)
7104
- });
7105
- const execution = await (deps.activateVersion ?? activateCloudflareVersion)({
7681
+ runCf: cfCommand,
7682
+ verifyResources: createCfResourceVerifier({
7683
+ configPath: staticConfigPath,
7684
+ runCf: cfCommand,
7685
+ runWrangler,
7686
+ verifyCompatibilityRunner: uploaderIsPinned
7687
+ })
7688
+ }) : runWrangler;
7689
+ const execution = await activateCloudflareVersionWithProgress(deps.activateVersion ?? activateCloudflareVersion, {
7106
7690
  runWrangler: activationRunner,
7107
- verifyUploader: uploaderIsPinned,
7691
+ verifyUploader: cfOutput ? cfUploaderIsPinned : uploaderIsPinned,
7108
7692
  configPath: staticConfigPath,
7109
7693
  preserveTriggers: existingWorker !== null,
7110
7694
  expectedPreviousVersionId: existingWorker?.versionId,
@@ -7136,9 +7720,16 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7136
7720
  workerName,
7137
7721
  runWrangler
7138
7722
  }),
7723
+ publishEmptyCrons: createCloudflareEmptyCronPublisher({
7724
+ accountId,
7725
+ apiBaseUrl,
7726
+ configPath: staticConfigPath,
7727
+ workerName,
7728
+ runWrangler
7729
+ }),
7139
7730
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
7140
7731
  queueConsumerCleanup
7141
- });
7732
+ }).finally(() => cfOutput?.dispose());
7142
7733
  if (!execution.ok) {
7143
7734
  await reportCloudflareActivationFailure(cliLog, formatCloudflareActivationError(execution));
7144
7735
  return exit(1);
@@ -7189,6 +7780,8 @@ const deployTargets = {
7189
7780
  },
7190
7781
  async deploy(root, options, cliLog) {
7191
7782
  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.");
7783
+ assertInstalledVoidMatchesCli(root);
7784
+ if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
7192
7785
  return runCloudflareDeploy(root, options, cliLog);
7193
7786
  }
7194
7787
  },
@@ -7239,7 +7832,11 @@ async function runDeployInner(root, options, cliLog) {
7239
7832
  const targetLabel = platform === "cloudflare" ? "Cloudflare" : "Void";
7240
7833
  log.info(`Deployment target: ${targetLabel}`);
7241
7834
  cliLog.info("deploy_target", { target: platform });
7242
- return deployTargets[platform].deploy(root, options ?? {}, cliLog);
7835
+ try {
7836
+ return await deployTargets[platform].deploy(root, options ?? {}, cliLog);
7837
+ } finally {
7838
+ if (existsSync(join(root, "void.config.ts"))) stashCloudflareDeployPointer(root);
7839
+ }
7243
7840
  }
7244
7841
  async function runManagedDeploy(root, options, cliLog) {
7245
7842
  let reauthenticated = false;
@@ -7301,6 +7898,7 @@ async function runManagedDeploy(root, options, cliLog) {
7301
7898
  projectId: config.projectId,
7302
7899
  slug: config.slug
7303
7900
  });
7901
+ if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
7304
7902
  const voidConfig = readConfig(root);
7305
7903
  cliLog.info("config_resolved", {
7306
7904
  target: voidConfig.target,
@@ -7418,7 +8016,7 @@ function resolveFullDeployBuildCommand(root, buildOverride) {
7418
8016
  * (`router/compile.ts`) emits a `paths.push(...)` for:
7419
8017
  * 1. `scan.pages.pages` — static patterns + dynamic pages' `getPrerenderPaths()`
7420
8018
  * 2. the custom SSR entry's top-level `getPrerenderPaths()` (`ssr` argument)
7421
- * 3. `options.explicitPrerenderPaths` — void.json `routing.prerender`
8019
+ * 3. `options.explicitPrerenderPaths` — void.config.ts `routing.prerender`
7422
8020
  * With none of them present the collector is a generated function whose body
7423
8021
  * returns `[...new Set([])]`, so skipping is result-identical.
7424
8022
  *
@@ -7831,7 +8429,7 @@ function warnRedundantForceOn3xx(count) {
7831
8429
  */
7832
8430
  function warnIgnoredNotFoundForFramework(notFound, frameworkName) {
7833
8431
  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).`);
8432
+ 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
8433
  }
7836
8434
  /**
7837
8435
  * Class B/C framework deploy: build with framework CLI, package with preset output paths.
@@ -7911,7 +8509,7 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
7911
8509
  } catch {}
7912
8510
  if (resources) {
7913
8511
  if (!resources.some((resource) => resource.type === "hyperdrive")) {
7914
- const { text: promptText, isCancel: isCancelPrompt } = await import("./output-B0cfNSx5.mjs").then((n) => n.T);
8512
+ const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
7915
8513
  const connectionString = await promptText({
7916
8514
  message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
7917
8515
  placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
@@ -7953,8 +8551,8 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
7953
8551
  log.info("Wrapper generated");
7954
8552
  }
7955
8553
  const wranglerCompat = resolveDeployWranglerCompat(root, voidConfig, workerDir, { dialect });
7956
- const revalidate = voidConfig.routing?.revalidate;
7957
- const prerender = voidConfig.routing?.prerender;
8554
+ const revalidate = collectRevalidate(voidConfig, null);
8555
+ const prerender = voidConfig.routing?.isr === false ? void 0 : voidConfig.routing?.prerender;
7958
8556
  const schedules = rawJobs.flatMap((job) => job.crons.map((cron) => ({
7959
8557
  name: job.name,
7960
8558
  cron
@@ -8157,7 +8755,7 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
8157
8755
  } catch {}
8158
8756
  if (resources) {
8159
8757
  if (!resources.some((resource) => resource.type === "hyperdrive")) {
8160
- const { text: promptText, isCancel: isCancelPrompt } = await import("./output-B0cfNSx5.mjs").then((n) => n.T);
8758
+ const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
8161
8759
  const connectionString = await promptText({
8162
8760
  message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
8163
8761
  placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
@@ -8604,4 +9202,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
8604
9202
  throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
8605
9203
  }
8606
9204
  //#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 };
9205
+ 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 };