void 0.22.0 → 0.23.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 (276) hide show
  1. package/README.md +5 -1
  2. package/dist/{account-cmd-CjyxcGkM.mjs → account-cmd-C84Ee8cO.mjs} +4 -4
  3. package/dist/{scan-ClYmX3sa.mjs → application-analysis-BVsVqc11.mjs} +135 -18
  4. package/dist/application-routing-B7QEjqSR.mjs +27 -0
  5. package/dist/{auth-CZuiVsFh.mjs → auth-CCjt0hcq.mjs} +1 -1
  6. package/dist/{auth-DLNN0D3Z.mjs → auth-CSkdO2Bb.mjs} +4 -47
  7. package/dist/{auth-link-BLO4ptzo.mjs → auth-link-CioEg6uY.mjs} +4 -4
  8. package/dist/{auth-router-ZUg9MF_U.mjs → auth-router-BsR981d4.mjs} +4 -4
  9. package/dist/{better-auth-shared-rsBGBvWJ.mjs → better-auth-shared-hy6RPh9W.mjs} +13 -2
  10. package/dist/{build-cmd-BxR5FROK.mjs → build-cmd-LzvNJORH.mjs} +17 -5
  11. package/dist/{cache-D0sWhgKI.mjs → cache-C4MvnrMH.mjs} +2 -2
  12. package/dist/{cancel-deploy-D4NUqFbi.mjs → cancel-deploy-abUxpP2n.mjs} +2 -2
  13. package/dist/{cf-build-output-BJ6yGEIS.mjs → cf-build-output-BPqOT964.mjs} +2 -1
  14. package/dist/cf-build-output-_0HNWysu.mjs +2 -0
  15. package/dist/cli/cli.mjs +80 -455
  16. package/dist/cli/{cf-compat.mjs → cloudflare-operation-process.mjs} +442 -421
  17. package/dist/cli/env-schema-probe.d.mts +2 -1
  18. package/dist/cli/env-schema-probe.mjs +3 -3
  19. package/dist/client-Cu7jWiF1.mjs +2 -0
  20. package/dist/{client-BTZ3XkrB.mjs → client-RV8NVeB8.mjs} +140 -21
  21. package/dist/{cloudflare-auth-DQkqoMYa.mjs → cloudflare-auth-Qdc7tw8F.mjs} +41 -38
  22. package/dist/{cloudflare-cmd-BKlfGHAy.mjs → cloudflare-cmd-BcrVyTmJ.mjs} +5 -5
  23. package/dist/cloudflare-config-Bktvwtpf.mjs +182 -0
  24. package/dist/{cloudflare-connect-Ctmrw579.mjs → cloudflare-connect-B8uPZ4nx.mjs} +3 -3
  25. package/dist/{cloudflare-operations-BT6OWFBk.mjs → cloudflare-operations-AiWashgg.mjs} +1 -1
  26. package/dist/{cloudflare-operations-B9tzgjmf.mjs → cloudflare-operations-fxHb-byx.mjs} +116 -172
  27. package/dist/{preset-UHj9ARyP.mjs → cloudflare-process-B-wekeR6.mjs} +93 -6
  28. package/dist/{config-VavjpDnp.d.mts → config-BMHb8RCj.d.mts} +1 -0
  29. package/dist/config-C_XRIPx2.mjs +89 -0
  30. package/dist/config-entry.d.mts +1 -1
  31. package/dist/{connect-Dg-WkW-C.mjs → connect-Bd4kJd9U.mjs} +5 -5
  32. package/dist/{create-project-DdoqwFLF.mjs → create-project-Boczwj5r.mjs} +1 -1
  33. package/dist/{create-project-l9J7pbtm.mjs → create-project-bMf6ffLZ.mjs} +2 -2
  34. package/dist/{db-gp2sCXyN.mjs → db-8uG64XLl.mjs} +21 -21
  35. package/dist/{delete-TTedbH6B.mjs → delete-NvbiyeJf.mjs} +2 -2
  36. package/dist/{deploy-CH-o2CaZ.mjs → deploy-DzAIwqNU.mjs} +908 -582
  37. package/dist/{deploy-B19L2Bra.mjs → deploy-bjXdFCtn.mjs} +1 -1
  38. package/dist/{domain-JRF59P_r.mjs → domain-y5Tvydvo.mjs} +3 -3
  39. package/dist/{email-Bo6G9LOZ.mjs → email-B3umsW75.mjs} +13 -28
  40. package/dist/{env-BYOrWQnv.mjs → env-BS6qYHDb.mjs} +4 -4
  41. package/dist/{env-public-BxU_0yTL.d.mts → env-public-BX_r8HR6.d.mts} +1 -1
  42. package/dist/{env-validation-BB4GkLxn.mjs → env-validation-BPn7vk-V.mjs} +18 -71
  43. package/dist/{env-validation-BXge7uyK.mjs → env-validation-DbTg7-ar.mjs} +1 -1
  44. package/dist/{fetch-CXDChK7B.mjs → fetch-BIZJh7vR.mjs} +2 -2
  45. package/dist/{fetch-stream-AOByI7Ki.mjs → fetch-stream-IvCYKyQL.mjs} +24 -4
  46. package/dist/{gen-sCtlCOdA.mjs → gen-B580--vC.mjs} +2 -2
  47. package/dist/gen-BVaUUumi.mjs +2 -0
  48. package/dist/{github-cmd-0-7PexDq.mjs → github-cmd-v45BdfKX.mjs} +2 -2
  49. package/dist/{handler-HEcZsaij.d.mts → handler-CZ4nAylQ.d.mts} +1 -1
  50. package/dist/help-DofyZuY7.mjs +2 -0
  51. package/dist/{help-GKtwl07I.mjs → help-daGKjXGk.mjs} +229 -747
  52. package/dist/index.d.mts +1 -1
  53. package/dist/index.mjs +288 -1502
  54. package/dist/info-B97bTX9N.mjs +113 -0
  55. package/dist/{init-FZx3Elvz.mjs → init-Bvy7zrBo.mjs} +46 -15
  56. package/dist/limits-Bq5LG8Id.d.mts +27 -0
  57. package/dist/limits-Cjuk2VPm.mjs +68 -0
  58. package/dist/{link-BrQfb_CU.mjs → link-CDqqCjFl.mjs} +3 -3
  59. package/dist/{list-D44jmIAM.mjs → list-CZj0dzKY.mjs} +3 -3
  60. package/dist/{live-CKJlvlNp.d.mts → live-Chw1eIMv.d.mts} +1 -1
  61. package/dist/{local-d1-Bg9OzEEO.mjs → local-d1-2CMnpuW_.mjs} +2 -2
  62. package/dist/login-DYt_An22.mjs +2 -0
  63. package/dist/{login-CAsAsQ-_.mjs → login-UZKFM_u7.mjs} +3 -3
  64. package/dist/{logs-BjKvFnVM.mjs → logs-CUZ6t9t3.mjs} +3 -3
  65. package/dist/migrate-8_2u55MD.mjs +2 -0
  66. package/dist/{migrate-BPITvDJN.mjs → migrate-DHul7PRV.mjs} +2 -1
  67. package/dist/{node-Dt7z256D.mjs → node-BkyRWRx8.mjs} +1 -1
  68. package/dist/operator-args-CLgKGlwU.mjs +690 -0
  69. package/dist/{operator-cmd-BK5CCiT9.mjs → operator-cmd-DBA6dl0m.mjs} +68 -22
  70. package/dist/pages/client.d.mts +34 -2
  71. package/dist/pages/client.mjs +59 -3
  72. package/dist/pages/index.d.mts +1 -1
  73. package/dist/pages/index.mjs +1 -1
  74. package/dist/pages/islands-plugin.mjs +1 -1
  75. package/dist/pages/protocol.d.mts +2 -2
  76. package/dist/pages/protocol.mjs +2 -308
  77. package/dist/{parse-filename-DioPHiR9.mjs → parse-filename-CUbj-1MP.mjs} +35 -1
  78. package/dist/plan-D1Q5rf-r.mjs +2 -0
  79. package/dist/plan-NPpwZ_kc.mjs +58 -0
  80. package/dist/platform-args-BJdRtlLq.mjs +506 -0
  81. package/dist/platform-args-D3RXyR6h.mjs +2 -0
  82. package/dist/{platform-auth-config-BlN8xTdD.mjs → platform-auth-config-B56E9YP1.mjs} +3 -3
  83. package/dist/{platform-auth-protection-7d5aV2Jg.mjs → platform-auth-protection-BDWO_aER.mjs} +2 -2
  84. package/dist/{platform-auth-recovery-Dxij8ZbR.mjs → platform-auth-recovery-1gg4CSRe.mjs} +3 -3
  85. package/dist/{platform-cmd-E0FuL212.mjs → platform-cmd-Bt-1w6pY.mjs} +1 -1
  86. package/dist/{platform-cmd-B3hwKrFK.mjs → platform-cmd-DMcQStSc.mjs} +24 -3
  87. package/dist/{platform-domain-D6Xcy9ZX.mjs → platform-domain-BNkcz0OB.mjs} +2 -2
  88. package/dist/{platform-lifecycle-k0E0xoxx.mjs → platform-lifecycle-9OyBALhH.mjs} +327 -215
  89. package/dist/{platform-lifecycle-DMh_qrry.mjs → platform-lifecycle-BE6C_jxh.mjs} +1 -1
  90. package/dist/{platform-management-Brz_BDiT.mjs → platform-management-CjwLVQwN.mjs} +6 -3
  91. package/dist/{platform-management-DOtss0BN.mjs → platform-management-CnyTdcWX.mjs} +1 -1
  92. package/dist/platform-plans-config-BNGKGr4P.mjs +359 -0
  93. package/dist/{platform-recovery-BvtcXON5.mjs → platform-recovery-D6KSpuFm.mjs} +2 -2
  94. package/dist/{plugin-inference-BMfKRSqE.mjs → plugin-inference-CXWnn79A.mjs} +174 -64
  95. package/dist/{prepare-C-6YZyyg.mjs → prepare-B5Mkic5u.mjs} +1 -1
  96. package/dist/{prepare-CRhJbVrG.mjs → prepare-DOsL0CC9.mjs} +4 -20
  97. package/dist/prepare-cgvDMtSb.mjs +2 -0
  98. package/dist/{project-cmd-BZLCqOqw.mjs → project-cmd-CNzrqvBv.mjs} +16 -16
  99. package/dist/{project-team-BvgM0WoX.mjs → project-team-DQOWPfQT.mjs} +2 -2
  100. package/dist/{project-token-l5DqK6Az.mjs → project-token-CTDYU0Cc.mjs} +2 -2
  101. package/dist/{project-zero-trust-v6Mvpp8y.mjs → project-zero-trust-BNAkW-_0.mjs} +2 -2
  102. package/dist/{protocol-BBa6cstI.d.mts → protocol-CjF_iI9X.d.mts} +2 -2
  103. package/dist/protocol-U7bfjHmA.mjs +331 -0
  104. package/dist/{provision-Fr9pRqce.mjs → provision-C4ORE7G7.mjs} +1 -1
  105. package/dist/{provision-C4IGqkBf.mjs → provision-CJFgTZY8.mjs} +89 -198
  106. package/dist/{requests-DN-BbNiM.mjs → requests-MhxYnau8.mjs} +2 -2
  107. package/dist/resource-name-C7LVpcRm.mjs +11 -0
  108. package/dist/{rollback-D7rzSaZM.mjs → rollback-CJ6iSDoU.mjs} +3 -3
  109. package/dist/route-url-CG7U-cRN.mjs +15 -0
  110. package/dist/{runner-B8wXwWlo.mjs → runner-CXA9Fh8h.mjs} +1 -1
  111. package/dist/{runner-p-dMs2UN.mjs → runner-Ol0TNjk6.mjs} +2 -2
  112. package/dist/runtime/ai.d.mts +12 -8
  113. package/dist/runtime/ai.mjs +84 -17
  114. package/dist/runtime/better-auth-mysql.mjs +1 -1
  115. package/dist/runtime/better-auth-pg.mjs +1 -1
  116. package/dist/runtime/better-auth.mjs +1 -1
  117. package/dist/runtime/client-react.mjs +2 -2
  118. package/dist/runtime/client-solid.mjs +2 -2
  119. package/dist/runtime/client-svelte.mjs +2 -2
  120. package/dist/runtime/client-vue.mjs +2 -2
  121. package/dist/runtime/client.mjs +2 -2
  122. package/dist/runtime/durable.d.mts +3 -1
  123. package/dist/runtime/durable.mjs +4 -1
  124. package/dist/runtime/email/testing.mjs +1 -1
  125. package/dist/runtime/env-public.d.mts +1 -1
  126. package/dist/runtime/fetch-stream.mjs +1 -1
  127. package/dist/runtime/fetch.mjs +1 -1
  128. package/dist/runtime/handler.d.mts +1 -1
  129. package/dist/runtime/kv.mjs +0 -1
  130. package/dist/runtime/limits.d.mts +2 -0
  131. package/dist/runtime/limits.mjs +2 -0
  132. package/dist/runtime/live-client.d.mts +1 -1
  133. package/dist/runtime/live-server.mjs +25 -16
  134. package/dist/runtime/live.d.mts +1 -1
  135. package/dist/runtime/migration-handler.mjs +62 -42
  136. package/dist/runtime/route-url.d.mts +4 -0
  137. package/dist/runtime/route-url.mjs +2 -0
  138. package/dist/runtime/routing.d.mts +180 -0
  139. package/dist/runtime/routing.mjs +1082 -0
  140. package/dist/runtime/sandbox-container.d.mts +1 -1
  141. package/dist/runtime/sandbox-container.mjs +1 -1
  142. package/dist/runtime/sandbox.d.mts +3 -3
  143. package/dist/runtime/sandbox.mjs +75 -45
  144. package/dist/runtime/sse.mjs +1 -1
  145. package/dist/runtime/validator.d.mts +1 -1
  146. package/dist/runtime/ws-server.d.mts +4 -2
  147. package/dist/runtime/ws-server.mjs +27 -2
  148. package/dist/runtime/ws.d.mts +2 -2
  149. package/dist/runtime/ws.mjs +8 -6
  150. package/dist/{sandbox-qpNBT8a3.d.mts → sandbox-XZAqzFlG.d.mts} +11 -8
  151. package/dist/{sandbox-container-DdNEBfCc.d.mts → sandbox-container-Bo0eiFKz.d.mts} +2 -1
  152. package/dist/{sandbox-container-4fdqLnyb.mjs → sandbox-container-C6ItmVuN.mjs} +4 -2
  153. package/dist/{scan-4tfN-PSn.mjs → scan-C7okrLyM.mjs} +4 -35
  154. package/dist/{secret-BOtOl_cb.mjs → secret-Dli5fP0B.mjs} +4 -4
  155. package/dist/{sse-BaC1jXko.mjs → sse-CQNaDFFV.mjs} +6 -3
  156. package/dist/validate-Dq_L3s0S.mjs +2 -0
  157. package/dist/{validate-CIUwFpjB.mjs → validate-ctOrgiS3.mjs} +2 -1
  158. package/dist/{wrangler-DQF1vKyf.mjs → wrangler-7K-bW_DL.mjs} +8 -239
  159. package/dist/{ws-BoY7vQML.d.mts → ws-CL1w7GXU.d.mts} +13 -2
  160. package/package.json +15 -8
  161. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +34 -157
  162. package/skills/void/SKILL.md +50 -135
  163. package/skills/void/docs/guide/ai.md +94 -84
  164. package/skills/void/docs/guide/app-types.md +3 -32
  165. package/skills/void/docs/guide/auth.md +12 -116
  166. package/skills/void/docs/guide/database/d1.md +9 -54
  167. package/skills/void/docs/guide/database/mysql.md +1 -1
  168. package/skills/void/docs/guide/database/postgresql.md +5 -26
  169. package/skills/void/docs/guide/database.md +23 -75
  170. package/skills/void/docs/guide/deployment.md +27 -113
  171. package/skills/void/docs/guide/durable-state.md +43 -18
  172. package/skills/void/docs/guide/edge/headers.md +3 -47
  173. package/skills/void/docs/guide/edge/prerendering.md +5 -20
  174. package/skills/void/docs/guide/edge/redirects.md +11 -64
  175. package/skills/void/docs/guide/edge/revalidation.md +5 -18
  176. package/skills/void/docs/guide/edge/rewrites.md +56 -284
  177. package/skills/void/docs/guide/edge/static-assets.md +22 -72
  178. package/skills/void/docs/guide/email/domains.md +112 -0
  179. package/skills/void/docs/guide/email/receiving.md +139 -0
  180. package/skills/void/docs/guide/email/sending.md +231 -0
  181. package/skills/void/docs/guide/email.md +13 -619
  182. package/skills/void/docs/guide/env-migration.md +11 -11
  183. package/skills/void/docs/guide/env-vars.md +9 -29
  184. package/skills/void/docs/guide/index.md +0 -15
  185. package/skills/void/docs/guide/jobs.md +3 -18
  186. package/skills/void/docs/guide/kv.md +5 -11
  187. package/skills/void/docs/guide/live.md +5 -56
  188. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +78 -125
  189. package/skills/void/docs/guide/pages-routing/head.md +10 -10
  190. package/skills/void/docs/guide/pages-routing/islands.md +6 -36
  191. package/skills/void/docs/guide/pages-routing/layouts.md +6 -128
  192. package/skills/void/docs/guide/pages-routing/loaders.md +3 -19
  193. package/skills/void/docs/guide/pages-routing/markdown.md +13 -171
  194. package/skills/void/docs/guide/pages-routing/overview.md +7 -17
  195. package/skills/void/docs/guide/pages-routing/view-transitions.md +1 -1
  196. package/skills/void/docs/guide/platform/administration/access.md +1 -4
  197. package/skills/void/docs/guide/platform/administration/email.md +35 -8
  198. package/skills/void/docs/guide/platform/administration/operations.md +26 -4
  199. package/skills/void/docs/guide/platform/administration/plans.md +126 -0
  200. package/skills/void/docs/guide/platform/administration/projects.md +5 -2
  201. package/skills/void/docs/guide/platform/administration/zero-trust.md +23 -152
  202. package/skills/void/docs/guide/platform/development/runtime.md +3 -13
  203. package/skills/void/docs/guide/platform/development/schema-ci.md +0 -58
  204. package/skills/void/docs/guide/platform/installation/credentials.md +6 -4
  205. package/skills/void/docs/guide/platform/installation/domains.md +30 -2
  206. package/skills/void/docs/guide/platform/installation/first-deployment.md +2 -0
  207. package/skills/void/docs/guide/platform/installation/maintenance.md +3 -1
  208. package/skills/void/docs/guide/platform/installation/prerequisites.md +20 -15
  209. package/skills/void/docs/guide/platform/installation/setup.md +9 -5
  210. package/skills/void/docs/guide/platform-administration.md +1 -0
  211. package/skills/void/docs/guide/queues.md +7 -9
  212. package/skills/void/docs/guide/quickstart.md +38 -37
  213. package/skills/void/docs/guide/remote-dev.md +4 -9
  214. package/skills/void/docs/guide/sandboxes.md +29 -21
  215. package/skills/void/docs/guide/server-routing.md +9 -72
  216. package/skills/void/docs/guide/sse.md +4 -18
  217. package/skills/void/docs/guide/ssg.md +3 -15
  218. package/skills/void/docs/guide/ssr.md +14 -62
  219. package/skills/void/docs/guide/storage.md +9 -4
  220. package/skills/void/docs/guide/type-safety.md +3 -14
  221. package/skills/void/docs/guide/typed-fetch.md +3 -7
  222. package/skills/void/docs/guide/websockets.md +68 -40
  223. package/skills/void/docs/integrations/agents.md +3 -3
  224. package/skills/void/docs/integrations/cloudflare.md +85 -316
  225. package/skills/void/docs/integrations/frameworks/analog.md +5 -64
  226. package/skills/void/docs/integrations/frameworks/astro.md +4 -73
  227. package/skills/void/docs/integrations/frameworks/nuxt.md +5 -62
  228. package/skills/void/docs/integrations/frameworks/overview.md +11 -54
  229. package/skills/void/docs/integrations/frameworks/react-router.md +5 -60
  230. package/skills/void/docs/integrations/frameworks/sveltekit.md +6 -65
  231. package/skills/void/docs/integrations/frameworks/tanstack-start.md +4 -62
  232. package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -69
  233. package/skills/void/docs/reference/api/auth.md +156 -0
  234. package/skills/void/docs/reference/api/client.md +87 -0
  235. package/skills/void/docs/reference/api/database.md +95 -0
  236. package/skills/void/docs/reference/api/durable.md +46 -0
  237. package/skills/void/docs/reference/api/env.md +50 -0
  238. package/skills/void/docs/reference/api/handlers.md +254 -0
  239. package/skills/void/docs/reference/api/pages.md +241 -0
  240. package/skills/void/docs/reference/api/plugin.md +39 -0
  241. package/skills/void/docs/reference/api/resources.md +109 -0
  242. package/skills/void/docs/reference/api/rewrites.md +76 -0
  243. package/skills/void/docs/reference/api/types.md +92 -0
  244. package/skills/void/docs/reference/api.md +56 -1218
  245. package/skills/void/docs/reference/cli/auth.md +88 -0
  246. package/skills/void/docs/reference/cli/database.md +128 -0
  247. package/skills/void/docs/reference/cli/deploy.md +85 -0
  248. package/skills/void/docs/reference/cli/domains.md +41 -0
  249. package/skills/void/docs/reference/cli/email.md +129 -0
  250. package/skills/void/docs/reference/cli/generate.md +116 -0
  251. package/skills/void/docs/reference/cli/github.md +189 -0
  252. package/skills/void/docs/reference/cli/platform-config.md +92 -0
  253. package/skills/void/docs/reference/cli/platform-email.md +81 -0
  254. package/skills/void/docs/reference/cli/platform-installation.md +127 -0
  255. package/skills/void/docs/reference/cli/platform-operations.md +90 -0
  256. package/skills/void/docs/reference/cli/platform-users.md +89 -0
  257. package/skills/void/docs/reference/cli/platform-zero-trust.md +45 -0
  258. package/skills/void/docs/reference/cli/platform.md +70 -0
  259. package/skills/void/docs/reference/cli/project.md +214 -0
  260. package/skills/void/docs/reference/cli/secrets.md +76 -0
  261. package/skills/void/docs/reference/cli/setup.md +70 -0
  262. package/skills/void/docs/reference/cli.md +32 -1682
  263. package/skills/void/docs/reference/config.md +12 -18
  264. package/skills/void/docs/reference/resource-inference.md +3 -58
  265. package/skills/void/docs/reference/structure.md +14 -41
  266. package/dist/canonical-json-DuDiiUsQ.mjs +0 -13
  267. package/dist/client-Czz8o5jP.mjs +0 -2
  268. package/dist/gen-CNJ62MM7.mjs +0 -2
  269. package/dist/help-CmZzxUba.mjs +0 -2
  270. package/dist/login-CGcRKEoi.mjs +0 -2
  271. package/dist/migrate-CYfbKkXh.mjs +0 -2
  272. package/dist/plan-BEZ8VJW0.mjs +0 -256
  273. package/dist/plan-DpuOr14e.mjs +0 -2
  274. package/dist/prepare-Bm3iq-u4.mjs +0 -2
  275. package/dist/validate-EKmJWxmy.mjs +0 -2
  276. /package/dist/cli/{cf-compat.d.mts → cloudflare-operation-process.d.mts} +0 -0
@@ -19,13 +19,15 @@ If nameservers, certificates, or project Zero Trust protection are pending, foll
19
19
 
20
20
  Use `--installation <id>` to select an installation explicitly, `--zone example.com` for an app domain such as `apps.example.com`, or `--dedicated-zone` for catch-all routing on a dedicated zone. Nested domains still need the wildcard certificate described below. This command adds the first domain; replacing an existing application domain is not currently supported. It uses the installed runtime and does not require `--runtime` or an app redeploy.
21
21
 
22
+ Choose an application domain whose wildcard leaves existing Worker Custom Domains reachable. Existing more-specific routes covering all requests can preserve those hostnames. If Void reports a conflict, choose another application domain; for a new installation, you can start with `void platform install --workers-dev` and add a suitable domain later.
23
+
22
24
  Browser login sessions are specific to each origin. Apps using their own OAuth providers may need to register their new callback URLs. Void's built-in auth uses the request origin automatically unless the app overrides that configuration.
23
25
 
24
26
  ### What Changes in Testing Mode?
25
27
 
26
- Each deployed app gets a small forwarding Worker and its own `workers.dev` origin. It forwards requests, including WebSockets and SSE, through the same platform router. Names include installation and project IDs; a later project with the same slug cannot inherit a deleted project's test URL.
28
+ In testing mode, each app gets a `workers.dev` URL. These URLs continue working after you add a domain; new apps then use the domain.
27
29
 
28
- Testing origins use shared ISR storage but bypass the extra edge response cache because you cannot use your zone's purge API for `workers.dev`. Custom-domain requests use the normal edge cache after activation. Existing test URLs and forwarding Workers are retained when you add a domain; new apps then use the domain without creating more forwarding Workers. Like other platform Workers, forwarders are retained for manual cleanup on uninstall; platform disablement and project suspension still apply to their traffic.
30
+ Testing URLs support WebSockets, SSE, and shared ISR storage, but skip the extra edge response cache. Their forwarding Workers remain for manual cleanup after uninstall. Platform disablement and project suspension still block their traffic.
29
31
 
30
32
  ## Other Domain Options
31
33
 
@@ -49,6 +51,32 @@ The management token needs **SSL and Certificates: Read** (or Edit) on that zone
49
51
 
50
52
  :::
51
53
 
54
+ ## Optional Dashboard
55
+
56
+ The API's `/admin/` pages are included in the core installation. You can deploy
57
+ the optional user dashboard separately and configure its HTTPS origin during
58
+ installation with `--dashboard-url https://dash.example.com`.
59
+
60
+ For an existing installation, preview and apply the configuration with:
61
+
62
+ ```sh
63
+ void platform repair <installation-id> --dashboard-url https://dash.example.com --plan
64
+ void platform repair <installation-id> --dashboard-url https://dash.example.com --yes
65
+ ```
66
+
67
+ The origin must contain no credentials, path, query, or fragment. Void saves it
68
+ for login callbacks and keeps it across upgrades and repairs. The command does
69
+ not create a dashboard Worker or DNS records; deploy that app separately. Omit
70
+ the option to keep the saved origin. The dashboard provides sign-in, linked
71
+ login methods, and sign-out; use the CLI for user project and team management.
72
+
73
+ If Access protects the platform, its application must cover this dashboard
74
+ origin too. Configure the origin when installing protection. To change it on an
75
+ already protected platform, deliberately remove protection through authentication
76
+ configuration, apply the origin, then enable protection again. Choose a separate
77
+ admission rule first if signup depends on the Access gate. Maintenance stops if
78
+ the configured origin is outside the active coverage.
79
+
52
80
  ## Cloudflare footprint
53
81
 
54
82
  New platform resources use deterministic `void-<installation-name>-<role>` names where Cloudflare allows them, such as `void-team-api`. Choose an unused installation name in the account; Void stops on an unowned name conflict instead of replacing that resource. Existing installations keep their recorded names, including older names with suffixes.
@@ -21,6 +21,8 @@ void deploy --platform void --project my-first-app
21
21
 
22
22
  `void connect` validates the platform and signs you in when needed. Confirm project creation when deploy asks. To use a project that already exists, run `void project link` instead. An app already linked to another platform keeps its existing destination; use a fresh app directory for your first test.
23
23
 
24
+ Once accepted by the platform, a deployment continues independently of the CLI connection. The CLI reconnects automatically after a connection failure. Use `void project status` to inspect a deployment after closing the CLI, or `void project cancel` to request cancellation.
25
+
24
26
  The CLI stores login credentials in your system keychain, separately for each platform URL. With no URL, `void connect` offers Cloudflare or a Void platform; `void connect --platform void` offers saved platforms and an option to enter another URL.
25
27
 
26
28
  For CI, create a bounded, project-scoped deploy credential while signed in as
@@ -56,6 +56,8 @@ Repair recreates missing infrastructure that the installer owns. It does not res
56
56
 
57
57
  ### Upgrade the platform
58
58
 
59
+ Keep the platform runtime current when updating the Void CLI. If a developer's CLI reports that project lookup requires an upgrade, upgrade the platform before retrying.
60
+
59
61
  Use the installed CLI's packaged runtime to upgrade:
60
62
 
61
63
  ```sh
@@ -80,7 +82,7 @@ Database migrations only move forward. Void checks compatibility before upgradin
80
82
 
81
83
  Upgrades automatically enable managed Sandboxes. The platform runtime token needs Account / Containers: Edit and Account / Cloudchamber: Edit, and the Cloudflare account must use Workers Paid before its first Sandbox application deploy. The upgrade itself does not probe Containers access, so platforms that do not deploy Sandbox applications need no additional plan or permissions.
82
84
 
83
- When upgrading from a release that used tenant-owned Sandbox containers, the upgrade may first ask you to finish the legacy cleanup. Follow the [`sandbox-drain` instructions](/reference/cli#operator-system), then rerun the upgrade. Administrator login remains available during that maintenance step.
85
+ When upgrading from a release that used tenant-owned Sandbox containers, the upgrade may first ask you to finish the legacy cleanup. Follow the [`sandbox-drain` instructions](../../../reference/cli/platform-operations.md#operator-system), then rerun the upgrade. Administrator login remains available during that maintenance step.
84
86
 
85
87
  After a successful upgrade, you can restore a declared-compatible earlier runtime without reversing migrations:
86
88
 
@@ -4,11 +4,16 @@ outline: deep
4
4
 
5
5
  # Prerequisites
6
6
 
7
- Start with a Cloudflare account you can administer, an account with your chosen login provider, and an empty hosted PostgreSQL database. GitHub is the default and is optional when another method is selected. A domain is recommended. If yours is not ready, choose **Use workers.dev for testing** during installation and [add a domain later](/guide/platform/installation/domains#adding-a-domain). The steps below explain how to get the credentials the installer asks for.
7
+ To run a Void platform, you need:
8
+
9
+ - A Cloudflare account with Workers for Platforms and R2 enabled.
10
+ - An empty hosted PostgreSQL database.
11
+ - An account with your chosen login provider. GitHub is the default; Google, OIDC, and Cloudflare Access are also supported.
12
+ - A domain for your apps, or `workers.dev` for testing. You can [add a domain later](/guide/platform/installation/domains#adding-a-domain).
8
13
 
9
14
  Void creates the Workers, storage, queues, routing, and database tables through the CLI.
10
15
 
11
- This setup has costs: Workers for Platforms requires a paid plan, and your database and Cloudflare usage have their own pricing. External PostgreSQL is required in either mode.
16
+ Workers for Platforms requires a paid plan. Your database and Cloudflare usage are billed separately.
12
17
 
13
18
  ## Prepare Your Cloudflare Account and Domain
14
19
 
@@ -31,15 +36,7 @@ pnpm add --global void
31
36
  void platform install --plan
32
37
  ```
33
38
 
34
- Void checks your saved Cloudflare login while you enter the installation name. If sign-in is needed, it opens your browser after you submit the name; press Ctrl+C to cancel. The plan command then asks for the account and basic configuration and shows the resources it would create. It does not require the database or runtime secrets and does not change Cloudflare resources.
35
-
36
- The installer first offers these choices, with the domain option selected:
37
-
38
- ```text
39
- Where should your apps live?
40
- Use a domain — recommended
41
- Use workers.dev for testing — add a domain later
42
- ```
39
+ Sign in to Cloudflare when prompted, then choose an installation name and account. `--plan` previews the resources without changing them or requiring runtime secrets.
43
40
 
44
41
  For a domain installation, use these answers. Testing mode skips the application domain, zone, and catch-all questions:
45
42
 
@@ -52,9 +49,9 @@ For a domain installation, use these answers. Testing mode skips the application
52
49
  | Optional custom API hostname | Leave empty to use `workers.dev` |
53
50
  | Dedicate all unmatched traffic to Void? | Yes only if this whole zone belongs to the platform |
54
51
 
55
- Platform resources use your installation name: `team` creates names such as `void-team-api`, `void-team-proxy`, and `void-team-routing`, with no random suffix. Use a different installation name for another platform in the same account. If a required resource already exists and belongs to another installation, Void stops without overwriting it. Existing installations keep their recorded resource names.
52
+ Choose an unused installation name in your account. For example, `team` creates resources such as `void-team-api` and `void-team-proxy`.
56
53
 
57
- The preview shows the actual resource names and login callback URL that installation will use with the same configuration. It also links directly to the runtime-token form and the account's R2 token page. When you select GitHub login, it links to GitHub OAuth registration. It does not open credential setup pages or save an installation draft; Cloudflare browser login still opens when needed.
54
+ The preview includes your login callback URL and links for creating credentials. Keep it open while following [Credentials](/guide/platform/installation/credentials), then run the install command printed at the end.
58
55
 
59
56
  You can select either path directly:
60
57
 
@@ -69,7 +66,7 @@ void platform install --workers-dev --plan
69
66
 
70
67
  Use an empty PostgreSQL database dedicated to this platform. It stores users, projects, and deployments; individual apps can still use D1. Void creates the tables and the Hyperdrive connection, but does not provision the PostgreSQL server.
71
68
 
72
- Void does not require a particular database provider. Use an existing PostgreSQL host or choose a service such as **PlanetScale Postgres**, **Neon**, **Supabase**, or others.
69
+ Use any PostgreSQL provider that accepts connections from your computer and Cloudflare:
73
70
 
74
71
  1. Create a fresh database or project dedicated to the platform, with no existing application tables. Use a database role that can create and manage its tables and schemas.
75
72
  2. Open the provider's connection details and select the primary database. Use a direct connection or a session-mode pooler, not transaction pooling. The connection must work from both your computer and Cloudflare.
@@ -85,4 +82,12 @@ For a dedicated Supabase project, [disable the Data API](https://supabase.com/do
85
82
 
86
83
  Once installation claims the database, continue using that same database for resume and maintenance commands. Uninstall never deletes external PostgreSQL.
87
84
 
88
- During interactive installation, choose whether Void creates Hyperdrive or uses an existing configuration in your Cloudflare account. Select an existing configuration by name and confirm its database, host, port, runtime user, and disabled SQL result caching. If you need a new separately managed configuration, choose **Set up a separately managed Hyperdrive**; Void pauses and gives you setup instructions. Create it with any unused name, point it at the dedicated PostgreSQL database using a runtime user, and disable SQL result caching. See [Cloudflare's Hyperdrive setup guide](https://developers.cloudflare.com/hyperdrive/get-started/), or ask your organization's Hyperdrive administrator to create it. Rerun the installer and select it. Paste a database owner connection into the PostgreSQL URL prompt for installation and migrations. Void verifies the selected Hyperdrive against that database, records its identity for later maintenance, and leaves its configuration under your external manager's control. For unattended installation, supply the existing Hyperdrive ID, origin host, and runtime user through the environment variables in [Install from CI](/guide/platform/installation/ci).
85
+ ### Use an existing Hyperdrive
86
+
87
+ The installer can create Hyperdrive for you or use one you manage separately. For an existing configuration:
88
+
89
+ 1. Point it at the dedicated platform database using a runtime user, and disable SQL result caching.
90
+ 2. Select it in the installer and confirm the database, host, port, and runtime user.
91
+ 3. Supply a database owner connection at the PostgreSQL URL prompt so Void can apply migrations.
92
+
93
+ To create one first, choose **Set up a separately managed Hyperdrive** and follow the printed instructions or [Cloudflare’s setup guide](https://developers.cloudflare.com/hyperdrive/get-started/). Rerun the installer once it is ready. Void leaves its configuration under your control. For unattended setup, use the Hyperdrive variables in [Install from CI](/guide/platform/installation/ci).
@@ -29,7 +29,7 @@ void platform install
29
29
 
30
30
  :::
31
31
 
32
- After `--plan`, run the install command printed at the end of the preview. Void recalculates the plan and asks you to confirm it; choose the same login methods again if you selected them interactively. Void then saves a local setup draft and opens the runtime-token page when that token is missing. Paste the token into the masked prompt. As you continue, it opens GitHub and R2 at their respective steps. Each page has a short checklist and a clickable fallback link in the terminal. Values already supplied through the environment or saved setup are reused without opening their pages again.
32
+ After reviewing `--plan`, run the command printed under **Next step: run this command to install**. It carries your choices into installation. Confirm the plan, then follow the credential prompts. Void opens the relevant setup pages and provides fallback links in the terminal. It reuses values you have already supplied.
33
33
 
34
34
  ## Choose login methods
35
35
 
@@ -131,7 +131,9 @@ ID, and secret, without a `cloudflareAccess` block or Cloudflare management toke
131
131
  Follow Cloudflare's [OIDC application guide](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/saas-apps/generic-oidc-saas/)
132
132
  and register the exact callback printed by Void.
133
133
 
134
- For the default GitHub-only setup:
134
+ ### GitHub
135
+
136
+ For GitHub login:
135
137
 
136
138
  1. The installer opens [GitHub's new OAuth App form](https://github.com/settings/applications/new) when it needs OAuth credentials. Sign in as the account that will own the login integration.
137
139
  2. Set **Application name** to your platform's display name and **Homepage URL** to the API URL Void just printed.
@@ -140,9 +142,11 @@ For the default GitHub-only setup:
140
142
 
141
143
  This OAuth App handles sign-in.
142
144
 
143
- For the default GitHub-only setup, the prompts collect the runtime token, administrator GitHub username, PostgreSQL URL, GitHub client ID and secret, R2 credentials, and signing/encryption keys. Other login methods collect their configured provider credentials and use the one-time administrator setup code described above. Secret values are masked and setup progress is encrypted locally using the system keychain. Keep a password-manager copy for recovery on another machine.
145
+ ## Finish installation
146
+
147
+ The installer collects your runtime token, PostgreSQL URL, login-provider credentials, R2 credentials, and signing and encryption keys. It masks secret values and saves setup progress encrypted through your system keychain. Keep a password-manager copy for recovery on another machine.
144
148
 
145
- Void shows installation progress while it prepares the database, provisions Cloudflare resources, deploys the services, and verifies platform health. Progress is checkpointed for recovery. When installation finishes, follow the printed administrator sign-in instructions and open the admin dashboard link. GitHub-only setup creates the first admin user when the selected GitHub account signs in; configurable setup uses the one-time `/setup` code and selected administrator login method. No app or CLI login is required. Void also prints the API URL to use when you [connect and deploy an app](/guide/platform/installation/first-deployment).
149
+ Once installation finishes, open the printed admin dashboard link. For GitHub-only setup, sign in as the administrator selected during installation. For configurable login, use the one-time `/setup` code to confirm the administrator’s identity. Use the printed API URL to [connect and deploy an app](/guide/platform/installation/first-deployment).
146
150
 
147
151
  Remove the management token from the shell when finished:
148
152
 
@@ -162,7 +166,7 @@ void platform install --resume --name <installation-id>
162
166
 
163
167
  Keep the management token available for any remaining DNS changes. When using a source build, also pass the same `--runtime` directory. Resume uses the saved checkpoint and original secrets; do not start a second installation or generate replacement keys. If setup failed before a checkpoint was saved, rerun the original command.
164
168
 
165
- If setup stops or fails, rerun `void platform install`. It lists unfinished installations, including those that reached provisioning, and offers **Continue setup** or **Start a new platform install**. Entering an existing unfinished name also asks whether to resume it; declining lets you enter another name. Continuing restores your saved answers and checkpoints. Starting new does not reuse or delete previous credentials or resources. `--resume --name <id>` continues directly and is required for non-interactive recovery. Read-only `--plan` runs do not save drafts. Completed platforms are managed with `platform status`, `repair`, or `upgrade`, not reinstalled.
169
+ You can also rerun `void platform install` and choose **Continue setup** for an unfinished installation. For non-interactive recovery, use `--resume --name <id>`. Manage completed platforms with `platform status`, `repair`, or `upgrade`.
166
170
 
167
171
  If Cloudflare rejects a saved runtime token during continued credential setup, Void opens the token page and asks for a replacement in the same run. Network or service failures do not discard saved tokens. Tokens supplied through the environment must be corrected there instead.
168
172
 
@@ -12,6 +12,7 @@ The operator commands for users, projects, deployments, and system status requir
12
12
 
13
13
  - [Sign-in and Access](/guide/platform/administration/access)
14
14
  - [Users and Projects](/guide/platform/administration/projects)
15
+ - [Plans and Limits](/guide/platform/administration/plans)
15
16
  - [Project Zero Trust](/guide/platform/administration/zero-trust)
16
17
  - [Email](/guide/platform/administration/email)
17
18
  - [Operations](/guide/platform/administration/operations)
@@ -8,13 +8,11 @@ Use queues to process work asynchronously, such as sending emails or handling up
8
8
 
9
9
  ## Defining queues
10
10
 
11
- Create files in `queues/**/*.ts`; `.mts`, `.js`, and `.mjs` also work. The queue name is inferred from its path, with nested path segments joined by `-`. For example, `queues/emails.ts` creates a queue named `"emails"`, and `queues/order/notifications.ts` creates `"order-notifications"`. A nested path must not normalize to the same name as another file: `queues/order/notifications.ts` and `queues/order-notifications.ts` conflict, so Void reports the collision and asks you to rename one.
11
+ Create a consumer in `queues/`. TypeScript and JavaScript files are supported (`.ts`, `.mts`, `.js`, `.mjs`). Its path determines the queue name: `queues/emails.ts` creates `emails`, and `queues/order/notifications.ts` creates `order-notifications`. Each queue must have a unique name.
12
12
 
13
13
  The resulting name must follow Cloudflare's queue naming rules: 1–63 characters, only letters, digits, and `-`, beginning and ending with a letter or digit.
14
14
 
15
- If you previously used a nested queue locally, update producer calls from `queues['order/notifications']` to `queues['order-notifications']`. The derived binding remains `QUEUE_ORDER_NOTIFICATIONS`.
16
-
17
- Each queue file should export a default handler wrapped with [`defineQueue`](../reference/api.md#definequeue-t-handler). The generic `<T>` parameter defines the message body type. That is the type of each `msg.body` in the batch, and it is also used by the typed `queues` proxy for `send()` calls.
15
+ Export a default handler wrapped with [`defineQueue<T>`](../reference/api/handlers.md#definequeue-t-handler). `T` defines the message body for both the consumer and calls to `send()`:
18
16
 
19
17
  ```ts
20
18
  // queues/emails.ts
@@ -56,8 +54,6 @@ export const POST = defineHandler(async (c) => {
56
54
  });
57
55
  ```
58
56
 
59
- The binding name is derived automatically: `QUEUE_` + queue name uppercased with non-alphanumeric characters replaced by `_`. For example, `queues/emails.ts` creates binding `QUEUE_EMAILS`, while `queues/order/notifications.ts` creates binding `QUEUE_ORDER_NOTIFICATIONS`.
60
-
61
57
  ## Per-message acknowledgment
62
58
 
63
59
  Each message in the batch has `ack()` and `retry()` methods matching the [Cloudflare Queues API](https://developers.cloudflare.com/queues/configuration/consumer-concurrency/):
@@ -111,12 +107,14 @@ export default defineQueue<Message>(async (batch, env) => {
111
107
 
112
108
  - `maxBatchSize`: maximum number of messages per batch (default `10`)
113
109
  - `maxBatchTimeout`: maximum seconds to wait before delivering an incomplete batch (default `5`)
114
- - `maxRetries`: maximum number of retries before a message is dead-lettered (default `3`)
110
+ - `maxRetries`: maximum number of retries before delivery is exhausted (default `3`)
115
111
  - `retryDelay`: seconds to wait between retries (default `0`)
116
112
 
117
- ## Deployment behavior
113
+ Void-managed queues do not configure a dead-letter queue. Cloudflare permanently
114
+ deletes messages that exhaust their retries without one; see
115
+ [Cloudflare's dead-letter queue guide](https://developers.cloudflare.com/queues/configuration/dead-letter-queues/).
118
116
 
119
- On deploy, Void includes all discovered queues in the deploy manifest. The platform provisions Cloudflare Queues, configures producer bindings on the user worker, and registers the dispatch worker as the queue consumer for relay delivery.
117
+ Void provisions queues and connects their producers and consumers when you deploy.
120
118
 
121
119
  ## Local development
122
120
 
@@ -56,36 +56,9 @@ Void asks you to choose Vite+ or Vite, a UI framework, a starter, and a deployme
56
56
 
57
57
  With pnpm, you can start with `pnpm create void my-app`. It configures native build permissions before installing Void.
58
58
 
59
- If a manual pnpm install reports blocked build scripts, run `pnpm approve-builds` for `esbuild`, `sharp`, and `workerd`. Set `better-sqlite3: false` in `pnpm-workspace.yaml`'s `allowBuilds`; Void uses its bundled binaries. Setup updates the pnpm lockfile, including in CI. Later installs can use `pnpm install --frozen-lockfile`.
60
-
61
59
  The examples below use `void` for brevity. Outside package scripts, run the local binary with `npx void`, `pnpm void`, `yarn void`, or `bunx void`. Keep Void installed in the project so the CLI and app use the same version.
62
60
 
63
- ## Using with Coding Agents
64
-
65
- `void init` detects your coding agent and installs its instructions and skills. If detection fails, choose an agent when prompted. In agents that support it, load the `/void` skill and describe the app you want to build. See [Coding Agents](../integrations/agents) for setup details.
66
-
67
- ## Meta Frameworks
68
-
69
- Use Void's [Pages routing](./pages-routing/overview) or keep a framework such as TanStack Start, React Router, or SvelteKit. Follow the [framework guides](../integrations/frameworks/overview) for setup.
70
-
71
- ## Adding to an Existing Vite App
72
-
73
- Install Void using the package manager command [above](#start-in-an-empty-directory).
74
-
75
- Enable the plugin in `vite.config.ts`:
76
-
77
- ```ts
78
- import { defineConfig } from 'vite';
79
- import { voidPlugin } from 'void';
80
-
81
- export default defineConfig({
82
- plugins: [voidPlugin()],
83
- });
84
- ```
85
-
86
- Then run `void init` with your package manager to configure the remaining project files. Existing compatibility dates are preserved; new projects use Void's tested Workers compatibility date.
87
-
88
- ## Once You Have a Working App
61
+ ## Run and deploy
89
62
 
90
63
  ### 1. Edit the generated API route
91
64
 
@@ -110,32 +83,60 @@ Then visit:
110
83
  - App: `http://localhost:5173`
111
84
  - API route: `http://localhost:5173/api/hello`
112
85
 
113
- ### 3. Choose where to deploy
86
+ ### 3. Deploy
114
87
 
115
- If you chose a deployment target during setup, you're ready. If you skipped it, run `void init` again or choose Cloudflare for the first deploy:
88
+ If you chose a deployment target during setup, run:
89
+
90
+ ```sh
91
+ void deploy
92
+ ```
93
+
94
+ If you skipped deployment setup, select your Cloudflare account for the first deploy:
116
95
 
117
96
  ```sh
118
97
  void deploy --platform cloudflare
119
98
  ```
120
99
 
121
- Void opens your browser to sign in when needed. To use your team's platform, connect using the API URL from your administrator:
100
+ Void opens your browser to sign in when needed. To use your team's platform, connect using the API URL from your administrator, then link a project and deploy:
122
101
 
123
102
  ```sh
124
103
  void connect https://platform.example.com
125
104
  void project link
105
+ void deploy
126
106
  ```
127
107
 
128
- ### 4. Deploy
108
+ Void builds the app, provisions its resources, applies pending migrations, and prints the deployed URL. If a production secret is missing, [set it](./env-vars.md) and deploy again. Later deploys use the saved target.
129
109
 
130
- With your target configured, run:
110
+ See [Deployment](./deployment.md) for CI setup and rollback.
131
111
 
132
- ```sh
133
- void deploy
112
+ ## Using with Coding Agents
113
+
114
+ `void init` detects your coding agent and installs its instructions and skills. If no agent is detected, use the bundled docs linked in `AGENTS.md`. In agents that support it, load the `/void` skill and describe the app you want to build. See [Coding Agents](../integrations/agents) for setup details.
115
+
116
+ ## Meta Frameworks
117
+
118
+ Use Void's [Pages routing](./pages-routing/overview) or keep a framework such as TanStack Start, React Router, or SvelteKit. Follow the [framework guides](../integrations/frameworks/overview) for setup.
119
+
120
+ ## Adding to an Existing Vite App
121
+
122
+ Install Void using the package manager command [above](#start-in-an-empty-directory).
123
+
124
+ Enable the plugin in `vite.config.ts`:
125
+
126
+ ```ts
127
+ import { defineConfig } from 'vite';
128
+ import { voidPlugin } from 'void';
129
+
130
+ export default defineConfig({
131
+ plugins: [voidPlugin()],
132
+ });
134
133
  ```
135
134
 
136
- Void builds the app, provisions the resources it uses, applies pending migrations, and prints the deployed URL. If it reports a missing production secret, [configure that secret](./env-vars.md) and deploy again.
135
+ Then run `void init` with your package manager to configure the remaining project files.
136
+
137
+ ## Troubleshooting pnpm installs
137
138
 
138
- Subsequent deploys use the same target. See [Deployment](./deployment.md) for CI setup, migrations, and rollback. To generate a supported push-to-deploy workflow, run `void init --github`.
139
+ If a manual pnpm install reports blocked build scripts, run `pnpm approve-builds` for `esbuild`, `sharp`, and `workerd`. Set `better-sqlite3: false` in `pnpm-workspace.yaml`'s `allowBuilds`; Void uses its bundled binaries.
139
140
 
140
141
  ## Next steps
141
142
 
@@ -42,13 +42,9 @@ VOID_REMOTE=1 vite dev
42
42
  | R2 | Local file-backed R2 | Remote R2 bucket |
43
43
  | AI | Always proxied | Always proxied |
44
44
 
45
- AI inference is always routed through the proxy regardless of remote mode. There is no local AI emulation.
45
+ AI requests use your platform’s account and allowance in both local and remote mode. There is no local AI simulator.
46
46
 
47
- ## How It Works
48
-
49
- In remote mode, binding calls go through your platform's proxy, authenticated with your login token. The proxy uses the linked project's configuration to choose the D1 database, KV namespace, or R2 bucket.
50
-
51
- You don't need to change any code. Imports like `import { db } from "void/db"` and direct binding access via `c.env.KV` both work transparently.
47
+ ## Checking Remote Mode
52
48
 
53
49
  When the dev server starts with remote mode active, it prints:
54
50
 
@@ -63,7 +59,6 @@ When the dev server starts with remote mode active, it prints:
63
59
 
64
60
  - **Network latency:** each binding call makes a network request, so responses may be slower than local development.
65
61
  - **R2 multipart uploads:** `createMultipartUpload()` and `resumeMultipartUpload()` are not supported in remote mode.
66
- - **R2 conditional writes:** `put(..., { onlyIf })` requires a current Void platform and an active deployment with the native remote-binding handler. Update the platform and redeploy the project if this operation is unavailable. Failed preconditions return `null`; Void never retries a conditional write as an unconditional REST upload.
62
+ - **R2 conditional writes:** `put(..., { onlyIf })` requires a current Void platform and an active deployment with the native remote-binding handler. Update the platform and redeploy the project if this operation is unavailable. Failed preconditions return `null`.
67
63
  - **D1 dump:** `db.dump()` is not supported in remote mode.
68
- - **D1 batch compatibility:** `db.batch()` requires an active deployment with the native remote-binding handler. Void does not split a batch into REST calls because that would lose D1's atomic all-or-nothing behavior.
69
- - **Writes affect real data:** remote mode connects to your actual deployed resources. Inserts, updates, and deletes are real, so use it carefully or point it at a staging project.
64
+ - **D1 batches:** `db.batch()` requires an updated platform and project deployment.
@@ -12,13 +12,13 @@ import { getSandbox } from 'void/sandbox';
12
12
 
13
13
  export const POST = defineHandler(async (c) => {
14
14
  const sandbox = await getSandbox('default');
15
- const process = await sandbox.exec(['node', '--version']);
16
- const result = await process.output();
17
-
18
- return c.json({
19
- exitCode: result.exitCode,
20
- stdout: new TextDecoder().decode(result.stdout),
21
- stderr: new TextDecoder().decode(result.stderr),
15
+ return sandbox.run(['node', '--version']).match({
16
+ ok: (result) =>
17
+ c.json({
18
+ exitCode: result.exitCode,
19
+ stdout: new TextDecoder().decode(result.stdout),
20
+ }),
21
+ limited: (limit) => limit.response({ message: 'Execution is temporarily unavailable.' }),
22
22
  });
23
23
  });
24
24
  ```
@@ -27,7 +27,7 @@ Importing from `void/sandbox` enables the required resources. Local development,
27
27
 
28
28
  ## Configuration
29
29
 
30
- Most apps do not need config. The default binding is `SANDBOX`, the Durable Object class is `SandboxV1`, and the default environment provides Node.js 24 on Debian Trixie. Local development and native deploys build Void's packaged Dockerfile, so Docker must be running. Managed platform deploys use Cloudflare's managed Node.js image.
30
+ The default environment provides Node.js 24 on Debian Trixie. Local development and native deploys need Docker running. Managed platform deploys use Cloudflare's managed Node.js image.
31
31
 
32
32
  Use `void.config.ts` when you need a custom image or container size:
33
33
 
@@ -62,7 +62,7 @@ WORKDIR /workspace
62
62
  CMD ["sleep", "infinity"]
63
63
  ```
64
64
 
65
- For a managed platform, push your custom image to that platform account's Cloudflare registry and set `platformImage` to its digest-pinned reference. If `image` is already a Cloudflare registry reference, it also becomes the default `platformImage`. External registry references and mutable tags are not supported by the new scheduling policy. See [Cloudflare's image management guide](https://developers.cloudflare.com/containers/guides/image-management/#push-images-to-the-cloudflare-registry).
65
+ For a managed platform, push your custom image to that platform account's Cloudflare registry and set `platformImage` to its digest-pinned reference. If `image` is already a Cloudflare registry reference, it also becomes the default `platformImage`. External registries and mutable tags are not supported. See [Cloudflare's image management guide](https://developers.cloudflare.com/containers/guides/image-management/#push-images-to-the-cloudflare-registry).
66
66
 
67
67
  ## Runtime API
68
68
 
@@ -75,37 +75,45 @@ const sandbox = await getSandbox(`user-${user.id}`, {
75
75
  inactivityTimeoutMs: 10 * 60 * 1000,
76
76
  enableInternet: false,
77
77
  });
78
- await sandbox.files.writeFile('/workspace/input.txt', 'hello');
79
- const process = await sandbox.exec(['cat', '/workspace/input.txt'], {
80
- signal: AbortSignal.timeout(5_000),
81
- });
82
- const { stdout, exitCode } = await process.output();
83
- const text = new TextDecoder().decode(stdout);
78
+ const response = await sandbox
79
+ .run(['node', '--version'], {
80
+ signal: AbortSignal.timeout(5_000),
81
+ })
82
+ .match({
83
+ ok: (result) => Response.json({ exitCode: result.exitCode }),
84
+ limited: (limit) => limit.response(),
85
+ });
84
86
  ```
85
87
 
86
88
  Commands take an executable and arguments as an array. For shell syntax, explicitly run `['sh', '-c', command]`. Execution options include `cwd` (default `/workspace`), `env`, `user`, `signal`, `pty`, `stdin`, `stdout`, and `stderr`.
87
89
 
88
- `exec()` returns a process immediately after it starts. Read its `stdout` and `stderr` streams, or call `output()` to collect both as `ArrayBuffer`s together with the exit code. `exitCode` is a promise; `kill(signal?)` and `resize(cols, rows)` are asynchronous. Use `stdin: 'pipe'` to receive a writable `stdin` stream. A process can continue running after a request returns, until it exits or its container stops. When streaming output from a long command, await `process.exitCode` alongside consuming its streams. This keeps an explicit command wait active even while the command produces no output; unattended background commands can stop when the Sandbox becomes idle.
90
+ `run()` collects command output and handles limits throughout execution with one required `.match({ ok, limited })`. Both handlers are required. Other failures still reject.
89
91
 
90
- File operations live under `sandbox.files`: `readFile`, `writeFile`, `stat`, `lstat`, `readDirectory`, `mkdir`, `rename`, and `remove`. `readFile()` returns a streaming `Response`; use `.text()`, `.arrayBuffer()`, or `.body`. `writeFile()` accepts text, binary data, or a byte stream. Relative file paths require an explicit `cwd` option.
92
+ `exec()` returns a lazy operation yielding a process through its `ok` handler. Use `output()` to collect `stdout` and `stderr` as `ArrayBuffer`s with the exit code, or read the streams and match `exitCode`. Both `output()` and `exitCode` require their own `.match({ ok, limited })`. Matching `exitCode` keeps a long command active during pauses in its output; unattended background commands can stop when the Sandbox becomes idle.
91
93
 
92
- To reach a server inside the container, call `sandbox.fetch(port, new Request(url))`. `sandbox.running()` checks whether the container is running; `sandbox.destroy()` stops it.
94
+ Use `stdin: 'pipe'` for a writable input stream. `kill(signal?)` stops a process, and `resize(cols, rows)` resizes its terminal.
95
+
96
+ File operations live under `sandbox.files`: `readFile`, `writeFile`, `stat`, `lstat`, `readDirectory`, `mkdir`, `rename`, and `remove`. Each file operation requires `.match({ ok, limited })`. `readFile()` yields a streaming `Response` to `ok`; use `.text()`, `.arrayBuffer()`, or `.body`. `writeFile()` accepts text, binary data, or a byte stream. Relative file paths require an explicit `cwd` option.
97
+
98
+ To reach a server inside the container, call `sandbox.fetch(port, new Request(url)).match({ ok, limited })`. `sandbox.running()` checks whether the container is running; `sandbox.destroy()` stops it.
93
99
 
94
100
  `getSandbox()` options include `inactivityTimeoutMs` (default ten minutes, maximum six hours), `enableInternet` (default `false`), and string `labels`. Internet access and labels take effect on the next container start. `binding` selects a custom native binding; managed platforms use the configured binding.
95
101
 
96
102
  For code that runs on both deployment targets, use `getSandbox()`. Direct access through `c.env.SANDBOX` is available only on local and native Cloudflare deployments.
97
103
 
104
+ The `limited` handler receives `resource: 'sandbox'`, a `reason` of `concurrency` or `runtime_budget`, and `response({ message })` for a structured HTTP 429. Keep user input available so it can be retried. Resolving a Sandbox, checking `running()`, stopping a process, and `destroy()` do not need a quota handler; cleanup remains available after a limit.
105
+
98
106
  ## State persistence
99
107
 
100
108
  `getSandbox(id)` selects the same Durable Object for that ID within a deployment. Native Cloudflare deployments preserve that namespace across Worker versions. Each managed platform deployment has its own namespace; rolling back to a retained deployment reconnects to that deployment's namespace.
101
109
 
102
- Files, running processes, and listening servers last only as long as the container. It can stop after inactivity, crash, or restart. Save anything you need to keep in your database, KV, or R2. For custom Durable Object implementations, `void/sandbox` also exports the SDK's `Files`, `DirectoryBackup`, `DirectoryBackupGateway`, `S3Mount`, and `S3Gateway` helpers. Deleting a project on a Void platform removes both its Durable Objects and containers.
110
+ Files, running processes, and listening servers last only as long as the container. It can stop after inactivity, crash, or restart. Save anything you need to keep in your database, KV, or R2. Deleting a project on a Void platform removes both its Durable Objects and containers.
103
111
 
104
112
  ## Deployment
105
113
 
106
- Sandboxes require [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans) and Containers access. Void checks this before provisioning or building. A managed platform's runtime token needs Account / Containers: Edit and Account / Cloudchamber: Edit. Applications without Sandbox do not require Containers or perform this entitlement check.
114
+ Sandboxes require [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans) and Containers access. A managed platform's runtime token needs Account / Containers: Edit and Account / Cloudchamber: Edit.
107
115
 
108
- `void deploy --platform cloudflare` builds native images and deploys the Sandbox alongside the application. `void deploy` on a connected Void Platform creates a deployment-scoped Sandbox controller, which enforces concurrency and runtime limits. Upgrade the platform before deploying an application built with this Sandbox API.
116
+ `void deploy --platform cloudflare` builds native images and deploys the Sandbox alongside the application. `void deploy` on a connected Void Platform applies the platform's Sandbox concurrency and runtime limits. Upgrade the platform before deploying an application built with this Sandbox API.
109
117
 
110
118
  ## Moving from Sandbox SDK 0.x
111
119