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,11 +1,14 @@
1
- import { r as __toESM } from "./rolldown-runtime-rQ84J-ij.mjs";
2
- import { o as join } from "./dist-BrsS7cai.mjs";
3
- import { $ as promoteInstallationSecrets, A as outro, D as log, E as intro, F as CANCEL_SYMBOL, G as assertPlatformInstallationSlugAvailable, I as isCancel, J as listInstallationManifests, L as settings, M as select, N as symbol, O as multiselect, P as text$1, Q as platformWorkerSecretUpdateIntentState, R as u$1, V as ensurePlatformAccessToken, W as acquirePlatformLifecycleLock, X as normalizePlatformApiUrl, at as savePlatformConnection, c as import_picocolors$1, ct as writePendingInstallationSecrets, et as readInstallationRecoverySecrets, ft as require_picocolors, h as S_BAR_END, i as createSpinner, it as resolveInstallationManifest, j as password, k as note, m as S_BAR, n as cliCommandName, q as latestPlatformWorkerCutoverGeneration, r as cliTitle, st as writeInstallationManifest, tt as readPendingInstallationSecrets, v as S_PASSWORD_MASK, w as confirm } from "./output-B0cfNSx5.mjs";
1
+ import { n as __toESM } from "./rolldown-runtime-DXIUcv95.mjs";
2
+ import { a as join } from "./dist-4WkAWhWx.mjs";
3
+ import { c as import_picocolors$1, d as require_picocolors, i as createSpinner, n as cliCommandName, r as cliTitle } from "./output-urU86XeT.mjs";
4
4
  import { t as cfAccessHeaders } from "./cf-access-DRsQRe6k.mjs";
5
- import { f as openBrowser } from "./auth-DPl6kck4.mjs";
6
- import { o as resolveWranglerArgv } from "./preset-lAy0B0BQ.mjs";
7
- import { l as runCloudflareAuthCommand, n as announceCloudflareLogin } from "./cloudflare-auth-6M5llVPC.mjs";
8
- import { n as createDefaultRunWrangler, o as resolvePinnedApiBaseUrl } from "./provision-CSJOjjQk.mjs";
5
+ import { d as openBrowser } from "./auth-B9_D6ygs.mjs";
6
+ import { a as listInstallationManifests, d as readInstallationRecoverySecrets, f as readPendingInstallationSecrets, g as savePlatformConnection, h as resolveInstallationManifest, i as latestPlatformWorkerCutoverGeneration, l as platformWorkerSecretUpdateIntentState, n as assertPlatformInstallationSlugAvailable, s as normalizePlatformApiUrl, t as acquirePlatformLifecycleLock, u as promoteInstallationSecrets, v as writeInstallationManifest, y as writePendingInstallationSecrets } from "./platform-registry-BJbgZLS1.mjs";
7
+ import { n as ensurePlatformAccessToken } from "./cf-access-rAZxzMkL.mjs";
8
+ import { B as text$1, E as confirm, F as password, G as settings, I as select, K as u$1, M as multiselect, N as note, O as intro, P as outro, R as symbol, U as CANCEL_SYMBOL, W as isCancel, g as S_PASSWORD_MASK, i as S_BAR_END, j as log, r as S_BAR } from "./dist-Dn6nn2IU.mjs";
9
+ import { o as resolveWranglerArgv } from "./preset-Dowh9tTt.mjs";
10
+ import { c as runCloudflareAuthCommand, n as announceCloudflareLogin } from "./cloudflare-auth-BCmTc1X_.mjs";
11
+ import { g as resolvePinnedApiBaseUrl, o as createDefaultRunWrangler } from "./provision-Cck2m3jJ.mjs";
9
12
  import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
10
13
  import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
11
14
  import { tmpdir } from "node:os";
@@ -16,7 +19,7 @@ import { encodeCloudflareVersionMessage, parseCloudflareVersionMessage, readClou
16
19
  import { readFile } from "node:fs/promises";
17
20
  import { createServer, request } from "node:http";
18
21
  import { request as request$1 } from "node:https";
19
- import { platformDatabaseSchemaDigest, resolvePlatformRuntime } from "@void/platform/installer";
22
+ import { PLATFORM_ADMIN_ASSETS_DIRECTORY, platformDatabaseSchemaDigest, resolvePlatformRuntime } from "@void/platform/installer";
20
23
  //#region src/cli/platform-cloudflare.ts
21
24
  var PlatformCloudflareApiError = class extends Error {
22
25
  status;
@@ -1408,7 +1411,7 @@ async function resolvePlatformCloudflareCredentialWithInput(readInput, dependenc
1408
1411
  credential: result.credential
1409
1412
  };
1410
1413
  announceCloudflareLogin();
1411
- const login = await runWrangler(["login", "--use-keyring"], true);
1414
+ const login = await runWrangler(["login"], false);
1412
1415
  assertNotCancelled();
1413
1416
  if (login.status !== 0) throw new Error("platform: Cloudflare browser login did not complete.");
1414
1417
  const credential = await readWranglerOAuthCredential(runWrangler);
@@ -1430,11 +1433,6 @@ async function readExistingCredential(dependencies, runWrangler) {
1430
1433
  token: environmentToken
1431
1434
  };
1432
1435
  if (!(dependencies.interactive ?? process.stdin.isTTY === true)) throw new Error("platform: Cloudflare authentication is required. Run `void cloudflare login` interactively, or set CLOUDFLARE_API_TOKEN in CI.");
1433
- if ((await runWrangler([
1434
- "auth",
1435
- "keyring",
1436
- "enable"
1437
- ], true)).status !== 0) throw new Error("platform: Could not enable secure Cloudflare credential storage. Refusing to use a plaintext OAuth credential.");
1438
1436
  return await readWranglerOAuthCredential(runWrangler);
1439
1437
  }
1440
1438
  async function readWranglerOAuthCredential(runWrangler = (args) => runCloudflareAuthCommand(process.cwd(), args)) {
@@ -1501,7 +1499,7 @@ async function verifyInstalledPlatformAccessProtection(input) {
1501
1499
  }
1502
1500
  const existingWorkers = input.plan.actions.filter((action) => action.kind === "worker" && action.action === "update").map((action) => action.name);
1503
1501
  if (existingWorkers.length) {
1504
- const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-Bhtvp0B_.mjs");
1502
+ const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-Jb0yftay.mjs");
1505
1503
  await verifyProtectionWorkerOrigins({
1506
1504
  request: input.client.request.bind(input.client),
1507
1505
  listWorkerDomains: input.client.listWorkerDomains.bind(input.client),
@@ -1554,13 +1552,36 @@ async function initializeInstalledPlatformAuthentication(apiUrl, installationId,
1554
1552
  }
1555
1553
  //#endregion
1556
1554
  //#region src/cli/platform-auth-database.ts
1555
+ /** Read the database name from an owner URL without applying Hyperdrive origin restrictions. */
1556
+ function platformDatabaseNameFromOwnerUrl(databaseUrl) {
1557
+ let url;
1558
+ try {
1559
+ url = new URL(databaseUrl);
1560
+ } catch {
1561
+ throw new Error("platform: DATABASE_URL must be a PostgreSQL connection string.");
1562
+ }
1563
+ if (url.protocol !== "postgres:" && url.protocol !== "postgresql:" || !url.hostname) throw new Error("platform: DATABASE_URL must use postgres:// or postgresql://.");
1564
+ const database = decodeURIComponent(url.pathname.replace(/^\//, ""));
1565
+ if (!database) throw new Error("platform: DATABASE_URL must include a database.");
1566
+ return database;
1567
+ }
1568
+ /** Pin an externally managed Hyperdrive without treating the owner URL as its runtime origin. */
1569
+ function verifyExternalPlatformHyperdrive(input) {
1570
+ const { config, expected } = input;
1571
+ const database = platformDatabaseNameFromOwnerUrl(input.databaseUrl);
1572
+ const hash = hyperdriveOriginConfigHash(config.origin);
1573
+ if (config.id !== expected.id || config.name !== expected.name || config.origin.host !== expected.host.toLowerCase() || config.origin.user !== expected.user || config.origin.database !== database || input.recordedHash && input.recordedHash !== hash) throw new Error("platform: The Terraform-managed Hyperdrive does not match the expected database origin.");
1574
+ if (config.cachingDisabled !== true) throw new Error("platform: Disable SQL result caching on the Terraform-managed Hyperdrive before installing.");
1575
+ return hash;
1576
+ }
1557
1577
  /** Authentication requires fresh reads; mutate only the installation-owned configuration. */
1558
1578
  async function verifyPlatformAuthenticationDatabase(client, accountId, resource, databaseUrl) {
1559
1579
  if (resource.kind !== "hyperdrive" || resource.key !== "hyperdrive" || resource.state !== "ready") throw new Error("platform: Authentication database verification requires the platform Hyperdrive resource.");
1560
- const expected = hyperdriveOriginFromConnectionString(databaseUrl);
1580
+ const expectedDatabase = resource.ownership === "adopted" ? platformDatabaseNameFromOwnerUrl(databaseUrl) : void 0;
1581
+ const expectedOrigin = resource.ownership !== "adopted" ? hyperdriveOriginFromConnectionString(databaseUrl) : void 0;
1561
1582
  const read = async () => {
1562
1583
  const current = await client.getHyperdriveConfig(accountId, resource.id);
1563
- if (current.id !== resource.id || current.name !== resource.name || !hyperdriveOriginMatches(current.origin, expected)) throw new Error("platform: Hyperdrive does not match this installation’s pinned database. No authentication configuration was activated.");
1584
+ if (current.id !== resource.id || current.name !== resource.name || (resource.ownership === "adopted" ? current.origin.database !== expectedDatabase || hyperdriveOriginConfigHash(current.origin) !== resource.configHash : expectedOrigin === void 0 || !hyperdriveOriginMatches(current.origin, expectedOrigin))) throw new Error("platform: Hyperdrive does not match this installation’s pinned database. No authentication configuration was activated.");
1564
1585
  return current;
1565
1586
  };
1566
1587
  if ((await read()).cachingDisabled === true) return;
@@ -1599,6 +1620,7 @@ async function createPlatformInstallPlan(client, input, existing, options) {
1599
1620
  const enableEmail = options?.includeEmailGateway !== false && !!emailSharedZoneId && !!normalizedEmailSenderDomain;
1600
1621
  const capabilities = {
1601
1622
  ...existing?.deployment.capabilities,
1623
+ ...options?.enableSandbox ? { sandbox: true } : {},
1602
1624
  ...input.authentication ? {
1603
1625
  githubOAuth: input.authentication.providers.includes("github"),
1604
1626
  googleOAuth: input.authentication.providers.includes("google")
@@ -1629,13 +1651,20 @@ async function createPlatformInstallPlan(client, input, existing, options) {
1629
1651
  });
1630
1652
  const { emailSharedZoneId: configuredEmailZone, emailSenderDomain: configuredSenderDomain, ...deploymentWithoutEmailZone } = deployment;
1631
1653
  const { emailSharedZoneId: recordedEmailZone, emailSenderDomain: recordedSenderDomain, ...existingWithoutEmailZone } = existing?.deployment ?? deployment;
1632
- const comparableExistingWithoutEmailZone = existing && deployment.capabilities.email && !existing.deployment.capabilities.email ? {
1654
+ const existingWithSandbox = existing && options?.enableSandbox ? {
1633
1655
  ...existingWithoutEmailZone,
1634
1656
  capabilities: {
1635
1657
  ...existingWithoutEmailZone.capabilities,
1636
- email: true
1658
+ sandbox: true
1637
1659
  }
1638
1660
  } : existingWithoutEmailZone;
1661
+ const comparableExistingWithoutEmailZone = existing && deployment.capabilities.email && !existing.deployment.capabilities.email ? {
1662
+ ...existingWithSandbox,
1663
+ capabilities: {
1664
+ ...existingWithSandbox.capabilities,
1665
+ email: true
1666
+ }
1667
+ } : existingWithSandbox;
1639
1668
  if (existing && (JSON.stringify(comparableExistingWithoutEmailZone) !== JSON.stringify(deploymentWithoutEmailZone) || recordedEmailZone !== void 0 && recordedEmailZone !== configuredEmailZone || recordedSenderDomain !== void 0 && recordedSenderDomain !== configuredSenderDomain)) throw new Error(`platform: --resume inputs do not match installation ${existing.id}. Use its recorded configuration.`);
1640
1669
  const names = deployment.resources;
1641
1670
  const wildcardHostname = `*.${deployment.application.baseDomain}`;
@@ -1750,7 +1779,21 @@ async function createPlatformInstallPlan(client, input, existing, options) {
1750
1779
  addNamedPlan(actions, existing, "usage-queue", "queue", names.usageQueue, usageQueues, "reuse", options, remoteOwnership);
1751
1780
  addNamedPlan(actions, existing, "cron-queue", "queue", names.cronQueue, cronQueues, "reuse", options, remoteOwnership);
1752
1781
  addNamedPlan(actions, existing, "dispatch-namespace", "dispatch-namespace", names.dispatchNamespace, dispatchNamespaces.filter((resource) => resource.name === names.dispatchNamespace), "reuse", options, remoteOwnership);
1753
- addNamedPlan(actions, existing, "hyperdrive", "hyperdrive", names.hyperdrive, hyperdrives.filter((resource) => resource.name === names.hyperdrive), "reuse", options, remoteOwnership);
1782
+ const recordedHyperdrive = existing?.resources.find((resource) => resource.key === "hyperdrive");
1783
+ const externalHyperdriveId = input.externalHyperdrive?.id || (recordedHyperdrive?.ownership === "adopted" ? recordedHyperdrive.id : "");
1784
+ if (externalHyperdriveId) {
1785
+ if (recordedHyperdrive && (recordedHyperdrive.ownership !== "adopted" || recordedHyperdrive.id !== externalHyperdriveId)) throw new Error("platform: The Terraform-managed Hyperdrive differs from this installation.");
1786
+ const remote = hyperdrives.find((resource) => resource.id === externalHyperdriveId);
1787
+ if (!remote || remote.name !== names.hyperdrive) throw new Error(`platform: Terraform-managed Hyperdrive ${JSON.stringify(externalHyperdriveId)} must exist with the name ${JSON.stringify(names.hyperdrive)}.`);
1788
+ actions.push({
1789
+ action: recordedHyperdrive ? "reuse" : "adopt",
1790
+ id: remote.id,
1791
+ key: "hyperdrive",
1792
+ kind: "hyperdrive",
1793
+ name: remote.name,
1794
+ reason: recordedHyperdrive ? "Reuse the recorded Terraform-managed Hyperdrive." : "Use the Terraform-managed Hyperdrive without taking ownership."
1795
+ });
1796
+ } else addNamedPlan(actions, existing, "hyperdrive", "hyperdrive", names.hyperdrive, hyperdrives.filter((resource) => resource.name === names.hyperdrive), "reuse", options, remoteOwnership);
1754
1797
  for (const [key, name] of [
1755
1798
  ["api-worker", names.apiWorker],
1756
1799
  ["proxy-worker", names.proxyWorker],
@@ -1770,13 +1813,16 @@ async function createPlatformInstallPlan(client, input, existing, options) {
1770
1813
  ...deployment,
1771
1814
  resources: resolvedResources
1772
1815
  });
1816
+ const apiUrl = resolvedDeployment.controlPlane.apiHostname ? `https://${deployment.controlPlane.apiHostname}` : `https://${resolvedDeployment.resources.apiWorker}.${workersSubdomain}.workers.dev`;
1817
+ const proxyUrl = resolvedDeployment.controlPlane.proxyHostname ? `https://${deployment.controlPlane.proxyHostname}` : `https://${resolvedDeployment.resources.proxyWorker}.${workersSubdomain}.workers.dev`;
1773
1818
  return {
1774
1819
  account,
1775
1820
  actions,
1776
- apiUrl: resolvedDeployment.controlPlane.apiHostname ? `https://${deployment.controlPlane.apiHostname}` : `https://${resolvedDeployment.resources.apiWorker}.${workersSubdomain}.workers.dev`,
1821
+ apiUrl,
1777
1822
  deployment: resolvedDeployment,
1823
+ ...input.externalHyperdrive ? { externalHyperdrive: input.externalHyperdrive } : {},
1778
1824
  installationId,
1779
- proxyUrl: resolvedDeployment.controlPlane.proxyHostname ? `https://${deployment.controlPlane.proxyHostname}` : `https://${resolvedDeployment.resources.proxyWorker}.${workersSubdomain}.workers.dev`,
1825
+ proxyUrl,
1780
1826
  workersSubdomain,
1781
1827
  zone
1782
1828
  };
@@ -1789,11 +1835,13 @@ async function revalidatePlatformInstallAction(client, original, manifest, actio
1789
1835
  controlPlaneDomain: deployment.controlPlane.apiHostname ?? "",
1790
1836
  dedicatedZone: deployment.application.dedicatedZone,
1791
1837
  displayName: deployment.displayName,
1838
+ ...original.externalHyperdrive ? { externalHyperdrive: original.externalHyperdrive } : {},
1792
1839
  installationSlug: deployment.installationSlug,
1793
1840
  zoneName: deployment.application.zoneName
1794
1841
  }, manifest, {
1795
1842
  ...options,
1796
- includeEmailGateway: original.actions.some((entry) => entry.key === "email-gateway-worker")
1843
+ includeEmailGateway: original.actions.some((entry) => entry.key === "email-gateway-worker"),
1844
+ enableSandbox: original.deployment.capabilities.sandbox
1797
1845
  })).actions.find((entry) => entry.key === action.key);
1798
1846
  if (!current || current.kind !== action.kind || current.name !== action.name || current.action !== action.action) throw new Error(`platform: Cloudflare changed after the installation plan was approved for ${action.kind} ${JSON.stringify(action.name)}. Review a new plan before retrying.`);
1799
1847
  if (action.kind === "worker" && action.action === "update") {
@@ -2405,6 +2453,25 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2405
2453
  if (plan.deployment.authentication.configurable && runtime.authenticationProtocolVersion !== 1) throw new Error("platform: This runtime does not support configurable authentication. Upgrade Void or use a compatible runtime.");
2406
2454
  if (plan.deployment.application.workersDev && runtime.applicationRoutingVersion !== 1) throw new Error("platform: This runtime does not support workers.dev application routing. Use a current platform runtime.");
2407
2455
  verifyRuntimeArtifacts(runtimeDirectory, runtime);
2456
+ const hyperdriveAction = plan.actions.find((action) => action.key === "hyperdrive");
2457
+ const recordedHyperdrive = existing?.resources.find((resource) => resource.key === "hyperdrive");
2458
+ let externalHyperdriveOriginHash;
2459
+ if (hyperdriveAction && (hyperdriveAction.action === "adopt" || recordedHyperdrive?.ownership === "adopted")) {
2460
+ if (!hyperdriveAction.id) throw new Error("platform: The Terraform-managed Hyperdrive has no ID.");
2461
+ if (!plan.externalHyperdrive && !recordedHyperdrive) throw new Error("platform: The Terraform-managed Hyperdrive origin must be specified.");
2462
+ const live = await dependencies.client.getHyperdriveConfig(plan.account.id, hyperdriveAction.id);
2463
+ externalHyperdriveOriginHash = verifyExternalPlatformHyperdrive({
2464
+ config: live,
2465
+ databaseUrl: secrets.databaseUrl,
2466
+ expected: {
2467
+ id: hyperdriveAction.id,
2468
+ name: hyperdriveAction.name,
2469
+ host: plan.externalHyperdrive?.host ?? live.origin.host,
2470
+ user: plan.externalHyperdrive?.user ?? live.origin.user ?? ""
2471
+ },
2472
+ ...recordedHyperdrive ? { recordedHash: recordedHyperdrive.configHash } : {}
2473
+ });
2474
+ }
2408
2475
  const runtimeProvenance = {
2409
2476
  manifestSha256: resolvedRuntime.manifestSha256,
2410
2477
  source: resolvedRuntime.source,
@@ -2692,14 +2759,14 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2692
2759
  manifest = recordAdoptionIntent(manifest, action, action.id, now());
2693
2760
  writeInstallationManifest(manifest);
2694
2761
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2695
- manifest = recordResource(manifest, action, action.id, "adopted", now(), secrets.databaseUrl);
2762
+ manifest = recordResource(manifest, action, action.id, "adopted", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2696
2763
  writeInstallationManifest(manifest);
2697
2764
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2698
2765
  continue;
2699
2766
  }
2700
2767
  if (action.action === "reuse") {
2701
2768
  if (action.id && (action.kind === "hyperdrive" || !manifest.resources.some((resource) => resource.key === action.key))) {
2702
- manifest = recordResource(manifest, action, action.id, void 0, now(), secrets.databaseUrl);
2769
+ manifest = recordResource(manifest, action, action.id, void 0, now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2703
2770
  writeInstallationManifest(manifest);
2704
2771
  await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2705
2772
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
@@ -2710,7 +2777,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2710
2777
  writeInstallationManifest(manifest);
2711
2778
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2712
2779
  const resource = await createResource(dependencies.client, plan, action, secrets.databaseUrl, zoneId);
2713
- manifest = recordResource(manifest, action, resource.id, "created", now(), secrets.databaseUrl, resource.fingerprint);
2780
+ manifest = recordResource(manifest, action, resource.id, "created", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : resource.fingerprint);
2714
2781
  writeInstallationManifest(manifest);
2715
2782
  await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2716
2783
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
@@ -2771,7 +2838,8 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2771
2838
  const targetSandboxDrainProtocol = runtime.safetyProtocols?.sandboxDrain ?? 0;
2772
2839
  const prepareSandboxDrain = dependencies.prepareSandboxDrain ?? releaseDatabaseLock.prepareSandboxDrain;
2773
2840
  if (targetSandboxDrainProtocol >= 1 && !prepareSandboxDrain) throw new Error("platform: The PostgreSQL lifecycle lock cannot establish the sandbox-drain safety checkpoint.");
2774
- const sandboxDrainPreparation = targetSandboxDrainProtocol >= 1 ? await prepareSandboxDrain(targetSandboxDrainProtocol >= 2 ? 2 : 0) : null;
2841
+ const sandboxDrainPreparation = targetSandboxDrainProtocol >= 1 ? await prepareSandboxDrain(targetSandboxDrainProtocol >= 3 ? 3 : targetSandboxDrainProtocol >= 2 ? 2 : 0) : null;
2842
+ if (sandboxDrainPreparation && sandboxDrainPreparation.admissionProtocol < targetSandboxDrainProtocol) throw new Error("platform: The database did not arm the Sandbox admission protocol required by this runtime.");
2775
2843
  const sandboxDrainRoutingKvId = requireId(Object.fromEntries(manifest.resources.map((resource) => [resource.key, resource.id])), "routing-kv");
2776
2844
  const writeSandboxDrainMirror = async (preparation) => {
2777
2845
  await dependencies.client.putKvValue(plan.account.id, sandboxDrainRoutingKvId, PLATFORM_SANDBOX_DRAIN_KEY, preparation.mirrorValue);
@@ -2848,7 +2916,8 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2848
2916
  routingKv: requireId(ids, "routing-kv"),
2849
2917
  zone: zoneId
2850
2918
  },
2851
- runtimeEntrypoints: entrypoints
2919
+ runtimeEntrypoints: entrypoints,
2920
+ ...runtime.assets ? { runtimeApiAssetsDirectory: join(runtimeDirectory, PLATFORM_ADMIN_ASSETS_DIRECTORY) } : {}
2852
2921
  };
2853
2922
  const requiresStagedCommit = !preserveDisabled && requiresTrafficGuard;
2854
2923
  const enabledConfigs = createPlatformWorkerConfigs({
@@ -3074,7 +3143,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
3074
3143
  await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
3075
3144
  }
3076
3145
  dependencies.onProgress?.("Verifying platform health");
3077
- const emailGatewayUrl = hasEmailGatewayArtifact ? `https://${plan.deployment.resources.emailGatewayWorker}.${plan.workersSubdomain}.workers.dev` : void 0;
3146
+ const emailGatewayUrl = hasEmailGatewayArtifact && plan.deployment.capabilities.email ? `https://${plan.deployment.resources.emailGatewayWorker}.${plan.workersSubdomain}.workers.dev` : void 0;
3078
3147
  if (plan.deployment.authentication.accessProtection) {
3079
3148
  ensurePlatformAccessToken(plan.apiUrl, false, true);
3080
3149
  ensurePlatformAccessToken(plan.proxyUrl, false, true);
@@ -3084,7 +3153,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
3084
3153
  workers: [
3085
3154
  plan.deployment.resources.apiWorker,
3086
3155
  plan.deployment.resources.proxyWorker,
3087
- ...hasEmailGatewayArtifact ? [plan.deployment.resources.emailGatewayWorker] : [],
3156
+ ...emailGatewayUrl ? [plan.deployment.resources.emailGatewayWorker] : [],
3088
3157
  plan.deployment.resources.dispatchWorker
3089
3158
  ],
3090
3159
  resumeCommand: dependencies.healthCheckResumeCommand,
@@ -3343,7 +3412,7 @@ async function createResource(client, plan, action, databaseUrl, zoneId) {
3343
3412
  function recordResource(manifest, action, id, ownership, now, databaseUrl, resourceFingerprint) {
3344
3413
  const previous = manifest.resources.find((resource) => resource.key === action.key);
3345
3414
  return recordInstallationResource(manifest, {
3346
- configHash: action.kind === "dns-record" ? dnsRecordConfigHash(action.name, "AAAA", "100::", true) : action.kind === "hyperdrive" && databaseUrl ? hyperdriveOriginConfigHash(hyperdriveOriginFromConnectionString(databaseUrl)) : action.kind === "r2-bucket" && resourceFingerprint ? r2BucketConfigHash(action.name, resourceFingerprint) : hash(JSON.stringify({
3415
+ configHash: action.kind === "dns-record" ? dnsRecordConfigHash(action.name, "AAAA", "100::", true) : action.kind === "hyperdrive" && resourceFingerprint ? resourceFingerprint : action.kind === "hyperdrive" && databaseUrl ? hyperdriveOriginConfigHash(hyperdriveOriginFromConnectionString(databaseUrl)) : action.kind === "r2-bucket" && resourceFingerprint ? r2BucketConfigHash(action.name, resourceFingerprint) : hash(JSON.stringify({
3347
3416
  kind: action.kind,
3348
3417
  name: action.name
3349
3418
  })),
@@ -3583,7 +3652,7 @@ function assertRequiredPlatformSecrets(plan, manifest, secrets, authenticationWi
3583
3652
  const requireSecret = (value, name) => {
3584
3653
  if (!value) missing.add(name);
3585
3654
  };
3586
- if (plan.deployment.authentication.configurable && !manifest.steps.some((step) => step.key.startsWith("authentication-initialized:v1:"))) {
3655
+ if (plan.deployment.authentication.configurable && !manifest.steps.some((step) => step.key.startsWith("authentication-initialized:v1:")) && !(manifest.deployment.authentication.configurable && manifest.steps.some((step) => step.key === "bootstrap-access:v1"))) {
3587
3656
  if (!authenticationWillBePrepared) requireSecret(secrets.authenticationSetupJson ?? "", "authentication setup configuration");
3588
3657
  requireSecret(secrets.authSetupToken ?? "", "installation authentication setup authority");
3589
3658
  requireSecret(secrets.authBootstrapCode ?? "", "administrator setup code");
@@ -3836,14 +3905,14 @@ async function preparePlatformSandboxDrainConnection(client, requiredAdmissionPr
3836
3905
  AND table_name = 'sandbox_drain_checkpoints'
3837
3906
  AND column_name = 'admission_protocol'
3838
3907
  ) AS "present"`)).rows[0]?.present === true;
3839
- if (requiredAdmissionProtocol === 2 && !hasAdmissionColumn) throw new Error("platform: The runtime database does not include the sandbox deployment admission barrier.");
3908
+ if (requiredAdmissionProtocol >= 2 && !hasAdmissionColumn) throw new Error("platform: The runtime database does not include the sandbox deployment admission barrier.");
3840
3909
  const readCheckpoint = () => client.query(`SELECT ${hasAdmissionColumn ? "\"admission_protocol\"" : "0 AS \"admission_protocol\""}, "generation", "state", "phase", "cursor", "started_at", "updated_at", "completed_at"
3841
3910
  FROM "sandbox_drain_checkpoints"
3842
3911
  WHERE "singleton" = true`);
3843
3912
  const classify = (row) => {
3844
3913
  if (!row) return null;
3845
3914
  const cursor = row.cursor;
3846
- if (!row.generation || row.admission_protocol !== 0 && row.admission_protocol !== 2 || !row.started_at || !row.updated_at || row.state !== "draining" && row.state !== "complete" || row.phase !== "deployments" && row.phase !== "resources" || !cursor || cursor.pass !== "1" && cursor.pass !== "2" || row.state === "complete" && (!row.completed_at || row.phase !== "resources" || cursor.pass !== "2") || row.state === "draining" && row.completed_at !== null) throw new Error("platform: The authoritative sandbox-drain database checkpoint is invalid. Traffic remains disabled.");
3915
+ if (!row.generation || row.admission_protocol !== 0 && row.admission_protocol !== 2 && row.admission_protocol !== 3 || !row.started_at || !row.updated_at || row.state !== "draining" && row.state !== "complete" || row.phase !== "deployments" && row.phase !== "resources" || !cursor || cursor.pass !== "1" && cursor.pass !== "2" || row.state === "complete" && (!row.completed_at || row.phase !== "resources" || cursor.pass !== "2") || row.state === "draining" && row.completed_at !== null) throw new Error("platform: The authoritative sandbox-drain database checkpoint is invalid. Traffic remains disabled.");
3847
3916
  return {
3848
3917
  admissionProtocol: row.admission_protocol,
3849
3918
  generation: row.generation,
@@ -3860,7 +3929,23 @@ async function preparePlatformSandboxDrainConnection(client, requiredAdmissionPr
3860
3929
  };
3861
3930
  const existingState = classify((await readCheckpoint()).rows[0]);
3862
3931
  if (existingState && (requiredAdmissionProtocol === 0 || existingState.admissionProtocol >= requiredAdmissionProtocol)) return existingState;
3863
- if (requiredAdmissionProtocol === 2) {
3932
+ if (requiredAdmissionProtocol >= 2) {
3933
+ if (existingState && existingState.admissionProtocol >= 2) {
3934
+ await client.query("BEGIN");
3935
+ try {
3936
+ await client.query("LOCK TABLE \"deployments\" IN SHARE MODE");
3937
+ await client.query(`UPDATE "sandbox_drain_checkpoints"
3938
+ SET "admission_protocol" = GREATEST("admission_protocol", $1), "updated_at" = now()
3939
+ WHERE "singleton" = true`, [requiredAdmissionProtocol]);
3940
+ const advanced = classify((await readCheckpoint()).rows[0]);
3941
+ if (!advanced || advanced.admissionProtocol < requiredAdmissionProtocol) throw new Error("platform: The Sandbox controller admission barrier could not be armed.");
3942
+ await client.query("COMMIT");
3943
+ return advanced;
3944
+ } catch (error) {
3945
+ await client.query("ROLLBACK").catch(() => void 0);
3946
+ throw error;
3947
+ }
3948
+ }
3864
3949
  const generation = randomUUID();
3865
3950
  await client.query("BEGIN");
3866
3951
  try {
@@ -3893,8 +3978,10 @@ async function preparePlatformSandboxDrainConnection(client, requiredAdmissionPr
3893
3978
  WHERE "singleton" = true
3894
3979
  AND "admission_protocol" = 2
3895
3980
  AND "generation" = $1`, [generation]);
3981
+ if (requiredAdmissionProtocol >= 3) await client.query(`UPDATE "sandbox_drain_checkpoints" SET "admission_protocol" = $1
3982
+ WHERE "singleton" = true`, [requiredAdmissionProtocol]);
3896
3983
  const armed = classify((await readCheckpoint()).rows[0]);
3897
- if (!armed || armed.admissionProtocol !== 2) throw new Error("platform: The sandbox deployment admission barrier could not be armed.");
3984
+ if (!armed || armed.admissionProtocol < requiredAdmissionProtocol) throw new Error("platform: The sandbox deployment admission barrier could not be armed.");
3898
3985
  await client.query("COMMIT");
3899
3986
  return armed;
3900
3987
  } catch (error) {
@@ -3937,12 +4024,17 @@ async function readRequiredPlatformSafetyProtocols(client) {
3937
4024
  AND table_name = 'sandbox_drain_checkpoints'
3938
4025
  AND column_name = 'admission_protocol'
3939
4026
  ) AS "present"`)).rows[0]?.present === true) {
3940
- if ((await client.query(`SELECT EXISTS(
4027
+ const admission = await client.query(`SELECT EXISTS(
3941
4028
  SELECT 1
3942
4029
  FROM "sandbox_drain_checkpoints"
3943
4030
  WHERE "singleton" = true
3944
4031
  AND "admission_protocol" >= 2
3945
- ) AS "required"`)).rows[0]?.required === true) return { sandboxDrain: 2 };
4032
+ ) AS "required", (SELECT "admission_protocol" FROM "sandbox_drain_checkpoints"
4033
+ WHERE "singleton" = true) AS "protocol"`);
4034
+ if (admission.rows[0]?.required === true) {
4035
+ if (admission.rows[0].protocol != null && admission.rows[0].protocol > 3) throw new Error("platform: The database requires a newer Sandbox controller protocol.");
4036
+ return { sandboxDrain: admission.rows[0].protocol === 3 ? 3 : 2 };
4037
+ }
3946
4038
  }
3947
4039
  return { sandboxDrain: (await client.query(`SELECT EXISTS(
3948
4040
  SELECT 1
@@ -4598,15 +4690,15 @@ function readTriggerConfigFromObject(config) {
4598
4690
  }
4599
4691
  }
4600
4692
  function verifyRuntimeArtifacts(runtimeDirectory, manifest) {
4601
- for (const artifact of Object.values(manifest.artifacts)) {
4693
+ for (const artifact of [...Object.values(manifest.artifacts), ...manifest.assets ? [manifest.assets.adminClient, ...manifest.assets.adminStyle ? [manifest.assets.adminStyle] : []] : []]) {
4602
4694
  const path = join(runtimeDirectory, artifact.path);
4603
4695
  let contents;
4604
4696
  try {
4605
4697
  contents = readFileSync(path);
4606
4698
  } catch (error) {
4607
- throw new Error(`platform: Runtime Worker artifact is missing: ${errorMessage(error)}`);
4699
+ throw new Error(`platform: Runtime artifact is missing: ${errorMessage(error)}`);
4608
4700
  }
4609
- if (contents.byteLength !== artifact.size || hash(contents) !== artifact.sha256) throw new Error(`platform: Runtime Worker artifact failed integrity verification: ${path}.`);
4701
+ if (contents.byteLength !== artifact.size || hash(contents) !== artifact.sha256) throw new Error(`platform: Runtime artifact failed integrity verification: ${path}.`);
4610
4702
  }
4611
4703
  verifyPlatformDatabaseArtifacts(runtimeDirectory, manifest.database);
4612
4704
  }
@@ -4817,7 +4909,7 @@ var PlatformAccessBlockedError = class extends Error {
4817
4909
  "Void’s own authentication stays enabled. Keep account-wide Default-Deny on.",
4818
4910
  "",
4819
4911
  "For platforms that must remain Access-protected:",
4820
- "https://void.cloud/guide/self-hosted-platform#cloudflare-access"
4912
+ "https://void.cloud/guide/platform/installation/maintenance#cloudflare-access"
4821
4913
  ].join("\n"));
4822
4914
  }
4823
4915
  };
@@ -5199,9 +5291,9 @@ function platformSetupLink(page, hyperlinks = supportsSetupLinks()) {
5199
5291
  return hyperlinks ? "\x1B]8;;" + page.url + "\x1B\\" + page.title + "\x1B]8;;\x1B\\" : page.title + ": " + page.url;
5200
5292
  }
5201
5293
  function platformSetupFieldHelp(key) {
5202
- const docs = (section, title) => platformSetupLink({
5294
+ const docs = (page, section, title) => platformSetupLink({
5203
5295
  title,
5204
- url: "https://void.cloud/guide/self-hosted-platform#" + section
5296
+ url: `https://void.cloud/guide/platform/installation/${page}#${section}`
5205
5297
  });
5206
5298
  switch (key) {
5207
5299
  case "databaseUrl": return {
@@ -5209,10 +5301,10 @@ function platformSetupFieldHelp(key) {
5209
5301
  description: "Stores platform users, projects, and deployments; use an empty hosted database, e.g. " + platformSetupLink({
5210
5302
  title: "Neon",
5211
5303
  url: "https://neon.com/"
5212
- }) + ". " + docs("platform-database", "Database setup")
5304
+ }) + ". " + docs("prerequisites", "platform-database", "Database setup")
5213
5305
  };
5214
- case "jwtSecret": return { description: "Signs platform login tokens. Run openssl rand -base64 32; save the key in your password manager. " + docs("signing-and-encryption-keys", "Key setup") };
5215
- case "projectSecretKey": return { description: "Encrypts app secrets. Run openssl rand -base64 32 separately; save this key for recovery. " + docs("signing-and-encryption-keys", "Key setup") };
5306
+ case "jwtSecret": return { description: "Signs platform login tokens. Run openssl rand -base64 32; save the key in your password manager. " + docs("credentials", "signing-and-encryption-keys", "Key setup") };
5307
+ case "projectSecretKey": return { description: "Encrypts app secrets. Run openssl rand -base64 32 separately; save this key for recovery. " + docs("credentials", "signing-and-encryption-keys", "Key setup") };
5216
5308
  default: return;
5217
5309
  }
5218
5310
  }
@@ -5352,6 +5444,39 @@ function formatPlatformSetupPlan(plan) {
5352
5444
  ...plan.deployment.authentication.accessProtection ? ["Cloudflare Access protection: configure API and proxy origins and admitted installer/CI credentials."] : []
5353
5445
  ].join("\n");
5354
5446
  }
5447
+ function formatPlatformInstallCommand(options) {
5448
+ const quote = (value) => {
5449
+ if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(value)) return value;
5450
+ return process.platform === "win32" ? `'${value.replaceAll("'", "''")}'` : `'${value.replaceAll("'", "'\\''")}'`;
5451
+ };
5452
+ const parts = [
5453
+ options.commandName,
5454
+ "platform",
5455
+ "install"
5456
+ ];
5457
+ const flag = (name, value) => {
5458
+ if (value) parts.push(name, quote(value));
5459
+ };
5460
+ if (options.resumeId) {
5461
+ parts.push("--resume");
5462
+ flag("--name", options.resumeId);
5463
+ } else {
5464
+ flag("--name", options.installationSlug);
5465
+ flag("--account", options.accountId);
5466
+ flag("--display-name", options.displayName);
5467
+ if (options.workersDev) parts.push("--workers-dev");
5468
+ else {
5469
+ flag("--application-domain", options.applicationDomain);
5470
+ flag("--zone", options.zoneName);
5471
+ if (options.dedicatedZone) parts.push("--dedicated-zone");
5472
+ }
5473
+ flag("--control-plane-domain", options.controlPlaneDomain);
5474
+ }
5475
+ flag("--auth-config", options.authConfig ?? "");
5476
+ flag("--runtime", options.runtime);
5477
+ if (options.yes) parts.push("--yes");
5478
+ return parts.join(" ");
5479
+ }
5355
5480
  function openPlatformSetupPage(page, dependencies = {}) {
5356
5481
  log.info(page.title + "\n" + page.instructions);
5357
5482
  console.log(platformSetupLink({
@@ -5407,14 +5532,14 @@ function resolvePlatformInstallDatabaseUrl(checkpoint, manifest = null) {
5407
5532
  }
5408
5533
  async function runPlatformLifecycleCommand(args) {
5409
5534
  if (args.subcommand === "domain") {
5410
- const { runPlatformDomainCommand } = await import("./platform-domain-C74PULqV.mjs");
5535
+ const { runPlatformDomainCommand } = await import("./platform-domain-IjiXgrXJ.mjs");
5411
5536
  await runPlatformDomainCommand(args);
5412
5537
  return;
5413
5538
  }
5414
5539
  if (args.subcommand === "discover") {
5415
5540
  const client = new PlatformCloudflareClient((await resolvePlatformCloudflareCredential()).token);
5416
5541
  const accountId = await selectAccount(await readAccounts(client), args.account);
5417
- const { recoverPlatformInstallations } = await import("./platform-recovery-ewqLefp1.mjs");
5542
+ const { recoverPlatformInstallations } = await import("./platform-recovery-DS8ih1SW.mjs");
5418
5543
  const recovered = await recoverPlatformInstallations(client, accountId, void 0, args.selector);
5419
5544
  if (recovered.length === 0) {
5420
5545
  log.info(`No recoverable Void platform installations were found in ${accountId}.`);
@@ -5424,7 +5549,7 @@ async function runPlatformLifecycleCommand(args) {
5424
5549
  return;
5425
5550
  }
5426
5551
  if (args.subcommand !== "install") {
5427
- const { runInstalledPlatformCommand } = await import("./platform-management-COogu_Se.mjs");
5552
+ const { runInstalledPlatformCommand } = await import("./platform-management-Cgyed0WY.mjs");
5428
5553
  await runInstalledPlatformCommand(args);
5429
5554
  return;
5430
5555
  }
@@ -5566,6 +5691,68 @@ async function runPlatformLifecycleCommand(args) {
5566
5691
  }
5567
5692
  const checkpoint = existing ? readPendingInstallationSecrets(existing) : null;
5568
5693
  const databaseUrl = resolvePlatformInstallDatabaseUrl(checkpoint, existing);
5694
+ const externalHyperdriveId = process.env.VOID_PLATFORM_HYPERDRIVE_ID?.trim() || "";
5695
+ const externalHyperdriveHost = process.env.VOID_PLATFORM_HYPERDRIVE_ORIGIN_HOST?.trim() || "";
5696
+ const externalHyperdriveUser = process.env.VOID_PLATFORM_HYPERDRIVE_ORIGIN_USER?.trim() || "";
5697
+ if ([
5698
+ externalHyperdriveId,
5699
+ externalHyperdriveHost,
5700
+ externalHyperdriveUser
5701
+ ].some(Boolean) && ![
5702
+ externalHyperdriveId,
5703
+ externalHyperdriveHost,
5704
+ externalHyperdriveUser
5705
+ ].every(Boolean)) throw new Error("platform: VOID_PLATFORM_HYPERDRIVE_ID, VOID_PLATFORM_HYPERDRIVE_ORIGIN_HOST, and VOID_PLATFORM_HYPERDRIVE_ORIGIN_USER must be set together.");
5706
+ let externalHyperdrive = externalHyperdriveId ? {
5707
+ id: externalHyperdriveId,
5708
+ host: externalHyperdriveHost,
5709
+ user: externalHyperdriveUser
5710
+ } : void 0;
5711
+ if (!externalHyperdrive && process.stdin.isTTY && (!existing || isPlatformSetupDraft(existing)) && !existing?.resources.some((resource) => resource.key === "hyperdrive")) {
5712
+ const expectedName = existing?.deployment.resources.hyperdrive ?? createPlatformResourceNames(installationSlug).hyperdrive;
5713
+ const matches = (await client.listHyperdriveConfigs(accountId)).filter((resource) => resource.name === expectedName);
5714
+ if (matches.length > 1) throw new Error(`platform: More than one Hyperdrive named ${expectedName} exists.`);
5715
+ const live = matches[0] ? await client.getHyperdriveConfig(accountId, matches[0].id) : null;
5716
+ if (live) {
5717
+ if (live.id !== matches[0].id || live.name !== expectedName || !live.origin.user) throw new Error(`platform: Could not verify the database user for existing Hyperdrive ${expectedName}.`);
5718
+ note(`Database: ${live.origin.database}\nHost: ${live.origin.host}\nPort: ${live.origin.port}\nUser: ${live.origin.user}\nSQL result caching: ${live.cachingDisabled ? "disabled" : "enabled"}`, `Existing Hyperdrive ${expectedName}`);
5719
+ const choice = await select({
5720
+ message: "How should Void set up Hyperdrive?",
5721
+ options: [{
5722
+ value: "existing",
5723
+ label: `Use existing Hyperdrive ${expectedName}`
5724
+ }, {
5725
+ value: "cancel",
5726
+ label: "Cancel installation"
5727
+ }]
5728
+ });
5729
+ if (isCancel(choice) || choice === "cancel") throw new Error("platform: Cancelled.");
5730
+ if (!live.cachingDisabled) throw new Error(`platform: Disable SQL result caching on existing Hyperdrive ${expectedName} before installing.`);
5731
+ externalHyperdrive = {
5732
+ id: live.id,
5733
+ host: live.origin.host,
5734
+ user: live.origin.user
5735
+ };
5736
+ } else {
5737
+ const choice = await select({
5738
+ message: "How should Void set up Hyperdrive?",
5739
+ options: [{
5740
+ value: "create",
5741
+ label: "Let Void create Hyperdrive",
5742
+ hint: "recommended"
5743
+ }, {
5744
+ value: "existing",
5745
+ label: "Use a separately managed Hyperdrive"
5746
+ }]
5747
+ });
5748
+ if (isCancel(choice)) throw new Error("platform: Cancelled.");
5749
+ if (choice === "existing") {
5750
+ note(`Create a Hyperdrive in account ${accountId} named ${expectedName}. Point it at the same dedicated PostgreSQL database you will give Void, use a runtime database user, and disable SQL result caching. If your organization manages Hyperdrive, ask its administrator to create it. Then rerun this command.\nSetup: https://developers.cloudflare.com/hyperdrive/get-started/`, "Set up Hyperdrive first");
5751
+ outro("No Cloudflare or local installation state was changed.");
5752
+ return;
5753
+ }
5754
+ }
5755
+ }
5569
5756
  let authoritativeProvisionIntents = false;
5570
5757
  if (existing && !isPlatformSetupDraft(existing)) {
5571
5758
  if (!databaseUrl) throw new Error("platform: DATABASE_URL is required to verify an interrupted installation before resuming it.");
@@ -5574,7 +5761,7 @@ async function runPlatformLifecycleCommand(args) {
5574
5761
  progress?.stop("Read the saved installation.");
5575
5762
  progress = void 0;
5576
5763
  if (authoritative) {
5577
- const { selectAuthoritativePlatformManifest } = await import("./platform-management-COogu_Se.mjs");
5764
+ const { selectAuthoritativePlatformManifest } = await import("./platform-management-Cgyed0WY.mjs");
5578
5765
  const selected = selectAuthoritativePlatformManifest(existing, authoritative);
5579
5766
  authoritativeProvisionIntents = true;
5580
5767
  if (!args.plan && JSON.stringify(selected) !== JSON.stringify(existing)) writeInstallationManifest(selected);
@@ -5590,6 +5777,7 @@ async function runPlatformLifecycleCommand(args) {
5590
5777
  controlPlaneDomain,
5591
5778
  dedicatedZone,
5592
5779
  displayName,
5780
+ ...externalHyperdrive ? { externalHyperdrive } : {},
5593
5781
  ...process.env.VOID_EMAIL_SHARED_ZONE_ID ? { emailSharedZoneId: process.env.VOID_EMAIL_SHARED_ZONE_ID } : {},
5594
5782
  ...process.env.VOID_EMAIL_SENDER_DOMAIN ? { emailSenderDomain: process.env.VOID_EMAIL_SENDER_DOMAIN } : {},
5595
5783
  installationSlug,
@@ -5599,12 +5787,29 @@ async function runPlatformLifecycleCommand(args) {
5599
5787
  let plan = await createPlatformInstallPlan(client, planInput, existing, {
5600
5788
  authoritativeProvisionIntents,
5601
5789
  allowUnverifiedAiGateway: true,
5602
- includeEmailGateway: runtime.manifest.artifacts.emailGateway !== void 0
5790
+ includeEmailGateway: runtime.manifest.artifacts.emailGateway !== void 0,
5791
+ enableSandbox: runtime.manifest.safetyProtocols.sandboxDrain >= 3
5603
5792
  });
5604
5793
  note(formatPlatformInstallPlan(plan), args.plan ? "Read-only installation plan" : "Installation plan");
5605
5794
  note(formatPlatformRuntime(runtime), "Platform runtime");
5606
5795
  if (args.plan) {
5607
5796
  console.log(formatPlatformSetupPlan(plan));
5797
+ console.log(`\n${existing ? "To resume this installation later:" : "To install with these settings later:"}\n${formatPlatformInstallCommand({
5798
+ commandName: cliCommandName(),
5799
+ accountId,
5800
+ installationSlug,
5801
+ displayName,
5802
+ applicationDomain,
5803
+ zoneName,
5804
+ controlPlaneDomain,
5805
+ dedicatedZone,
5806
+ workersDev,
5807
+ authConfig: args.authConfig,
5808
+ runtime: args.runtime,
5809
+ ...existing ? { resumeId: existing.id } : {},
5810
+ yes: args.yes || process.stdin.isTTY !== true
5811
+ })}\n`);
5812
+ if (!existing && !args.authConfig && process.stdin.isTTY) console.log("Choose the same login methods when prompted.\n");
5608
5813
  outro("No Cloudflare or local installation state was changed.");
5609
5814
  return;
5610
5815
  }
@@ -5780,11 +5985,12 @@ async function runPlatformLifecycleCommand(args) {
5780
5985
  replanWorkers: async (manifest) => (await createPlatformInstallPlan(client, planInput, manifest, {
5781
5986
  authoritativeProvisionIntents: true,
5782
5987
  repairMissing: true,
5783
- includeEmailGateway: runtime.manifest.artifacts.emailGateway !== void 0
5988
+ includeEmailGateway: runtime.manifest.artifacts.emailGateway !== void 0,
5989
+ enableSandbox: runtime.manifest.safetyProtocols.sandboxDrain >= 3
5784
5990
  })).actions.filter((action) => action.kind === "worker"),
5785
5991
  revalidateBeforeWorkerDeploy: (manifest, action) => revalidatePlatformInstallAction(client, plan, manifest, action),
5786
5992
  verifyExistingOwnership: async (manifest, databaseCheckpointExists) => {
5787
- const { verifyPlatformInstallationOwnership } = await import("./platform-management-COogu_Se.mjs");
5993
+ const { verifyPlatformInstallationOwnership } = await import("./platform-management-Cgyed0WY.mjs");
5788
5994
  const retainedReplacementKeys = new Set(plan.actions.filter((action) => {
5789
5995
  const previous = manifest.resources.find((resource) => resource.key === action.key);
5790
5996
  return action.action === "create" && previous && previous.name !== action.name;
@@ -5849,7 +6055,8 @@ async function verifyPlatformAiGatewayPlan(client, input, existing, preview, aut
5849
6055
  try {
5850
6056
  verified = await createPlatformInstallPlan(client, input, existing, {
5851
6057
  authoritativeProvisionIntents,
5852
- includeEmailGateway: preview.actions.some((entry) => entry.key === "email-gateway-worker")
6058
+ includeEmailGateway: preview.actions.some((entry) => entry.key === "email-gateway-worker"),
6059
+ enableSandbox: preview.deployment.capabilities.sandbox
5853
6060
  });
5854
6061
  } catch (error) {
5855
6062
  if (error instanceof PlatformCloudflareApiError && (error.status === 401 || error.status === 403) && error.requestPath?.includes("/ai-gateway/")) throw new Error("platform: The runtime token could not verify AI Gateway access. Include Account → AI Gateway → Edit for this account, then retry. No platform resources were created.", { cause: error });
@@ -5923,4 +6130,4 @@ async function promptSecret(message, masked = true, validate, placeholder) {
5923
6130
  return value;
5924
6131
  }
5925
6132
  //#endregion
5926
- export { PlatformCloudflareClient as C, verifyPlatformRuntimeTokenPermissions as D, hyperdriveOriginMatches as E, preparePlatformAccessSetup as S, hyperdriveOriginFromConnectionString as T, revalidatePlatformInstallAction as _, createPlatformInstallationSecrets as a, assertNoninteractivePlatformMutationAcknowledged, checkpointPlatformAccessResources as b, platformDatabaseClientUrl as c, recordPlatformWorkerTraffic as d, trackedPlatformWorkerTraffic as f, platformProvisionIntentHash as g, platformAdoptionIntentHash as h, createPlatformHealthProbeToken as i, recordResource as l, formatPlatformInstallPlan as m, acquirePlatformDatabaseLifecycleLock as n, installPlatform as o, createPlatformInstallPlan as p, acquirePlatformDatabaseLifecycleLockConnection as r, resolvePlatformInstallDatabaseUrl, runPlatformLifecycleCommand, loadPlatformRuntime as s, REMOTE_INSTALLATION_MANIFEST_KEY as t, resolveBootstrapGitHubId as u, assertPlatformOperatorCredentialCanApplyPlan as v, hyperdriveOriginConfigHash as w, parsePlatformAccessSetupSpec as x, resolvePlatformCloudflareCredential as y };
6133
+ export { hyperdriveOriginFromConnectionString as A, assertPlatformOperatorCredentialCanApplyPlan as C, preparePlatformAccessSetup as D, parsePlatformAccessSetupSpec as E, verifyPlatformRuntimeTokenPermissions as M, PlatformCloudflareClient as O, platformDatabaseNameFromOwnerUrl as S, checkpointPlatformAccessResources as T, createPlatformInstallPlan as _, REMOTE_INSTALLATION_MANIFEST_KEY as a, platformProvisionIntentHash as b, createPlatformHealthProbeToken as c, loadPlatformRuntime as d, platformDatabaseClientUrl as f, trackedPlatformWorkerTraffic as g, recordPlatformWorkerTraffic as h, verifyPlatformAiGatewayPlan as i, hyperdriveOriginMatches as j, hyperdriveOriginConfigHash as k, createPlatformInstallationSecrets as l, resolveBootstrapGitHubId as m, resolvePlatformInstallDatabaseUrl as n, acquirePlatformDatabaseLifecycleLock as o, recordResource as p, runPlatformLifecycleCommand as r, acquirePlatformDatabaseLifecycleLockConnection as s, assertNoninteractivePlatformMutationAcknowledged as t, installPlatform as u, formatPlatformInstallPlan as v, resolvePlatformCloudflareCredential as w, revalidatePlatformInstallAction as x, platformAdoptionIntentHash as y };