void 0.20.2 → 0.21.0

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