void 0.21.9 → 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 (293) hide show
  1. package/README.md +5 -1
  2. package/dist/{account-cmd-DZZGK80W.mjs → account-cmd-C84Ee8cO.mjs} +5 -5
  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-B_CeugBw.mjs → auth-link-CioEg6uY.mjs} +5 -5
  8. package/dist/{auth-router-BgEFRuvZ.mjs → auth-router-BsR981d4.mjs} +5 -5
  9. package/dist/{better-auth-shared-rsBGBvWJ.mjs → better-auth-shared-hy6RPh9W.mjs} +13 -2
  10. package/dist/{build-cmd-Dpt0jd-x.mjs → build-cmd-LzvNJORH.mjs} +19 -7
  11. package/dist/{cache-7_UeZdTk.mjs → cache-C4MvnrMH.mjs} +4 -4
  12. package/dist/{cancel-deploy-D23R1RXT.mjs → cancel-deploy-abUxpP2n.mjs} +4 -4
  13. package/dist/{cf-build-output-CGT03qCD.mjs → cf-build-output-BPqOT964.mjs} +141 -63
  14. package/dist/cf-build-output-_0HNWysu.mjs +2 -0
  15. package/dist/cli/cli.mjs +114 -460
  16. package/dist/cli/cloudflare-operation-process.mjs +1103 -0
  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-QTl6ko_D.mjs → client-RV8NVeB8.mjs} +165 -21
  21. package/dist/{cloudflare-auth-C4_GPZr0.mjs → cloudflare-auth-Qdc7tw8F.mjs} +41 -43
  22. package/dist/{cloudflare-cmd-bSmZ1d5L.mjs → cloudflare-cmd-BcrVyTmJ.mjs} +9 -10
  23. package/dist/cloudflare-config-Bktvwtpf.mjs +182 -0
  24. package/dist/{cloudflare-connect-jAwacxxP.mjs → cloudflare-connect-B8uPZ4nx.mjs} +4 -4
  25. package/dist/{cloudflare-operations-BipGMJ5O.mjs → cloudflare-operations-AiWashgg.mjs} +1 -1
  26. package/dist/{cloudflare-operations-sMZXpk_S.mjs → cloudflare-operations-fxHb-byx.mjs} +118 -203
  27. package/dist/{preset-UHj9ARyP.mjs → cloudflare-process-B-wekeR6.mjs} +93 -6
  28. package/dist/{config-CF69HgXc.d.mts → config-BMHb8RCj.d.mts} +2 -2
  29. package/dist/{config-CafTW6Cz.mjs → config-Br_JZD6u.mjs} +2 -7
  30. package/dist/config-C_XRIPx2.mjs +89 -0
  31. package/dist/{config-s7Xj7tPb.mjs → config-CyQ-wVd7.mjs} +1 -1
  32. package/dist/config-entry.d.mts +1 -1
  33. package/dist/{config-write-BSduPMY8.mjs → config-write-B1f88wJA.mjs} +1 -1
  34. package/dist/{connect-BsUSRzln.mjs → connect-Bd4kJd9U.mjs} +6 -6
  35. package/dist/{create-project-BniEV0OW.mjs → create-project-Boczwj5r.mjs} +1 -1
  36. package/dist/{create-project-DBfFSZKY.mjs → create-project-bMf6ffLZ.mjs} +9 -5
  37. package/dist/{db-hRrvZaq_.mjs → db-8uG64XLl.mjs} +26 -26
  38. package/dist/{delete-D6dZ9B6B.mjs → delete-NvbiyeJf.mjs} +4 -4
  39. package/dist/{deploy-WaAQez1O.mjs → deploy-DzAIwqNU.mjs} +944 -607
  40. package/dist/{deploy-DDz7c8LK.mjs → deploy-bjXdFCtn.mjs} +1 -1
  41. package/dist/{dist-BR1quN_w.mjs → dist-AoCzRTJE.mjs} +226 -60
  42. package/dist/{dist-C5fND3R0.mjs → dist-BuDuKZJv.mjs} +1 -1
  43. package/dist/{dist-Dn6nn2IU.mjs → dist-CTBk70IR.mjs} +42 -42
  44. package/dist/{domain-Dmhvb2oU.mjs → domain-y5Tvydvo.mjs} +5 -5
  45. package/dist/{email-DFi-s2t4.mjs → email-B3umsW75.mjs} +15 -30
  46. package/dist/{env-Csi-tMbT.mjs → env-BS6qYHDb.mjs} +6 -6
  47. package/dist/{env-public-D_6u46fX.d.mts → env-public-BX_r8HR6.d.mts} +2 -1
  48. package/dist/{env-validation-BB4GkLxn.mjs → env-validation-BPn7vk-V.mjs} +18 -71
  49. package/dist/{env-validation-BXge7uyK.mjs → env-validation-DbTg7-ar.mjs} +1 -1
  50. package/dist/{fetch-CXDChK7B.mjs → fetch-BIZJh7vR.mjs} +2 -2
  51. package/dist/{fetch-stream-AOByI7Ki.mjs → fetch-stream-IvCYKyQL.mjs} +24 -4
  52. package/dist/{gen-Dz3X1Qab.mjs → gen-B580--vC.mjs} +5 -5
  53. package/dist/gen-BVaUUumi.mjs +2 -0
  54. package/dist/{github-cmd-BED3_9JD.mjs → github-cmd-v45BdfKX.mjs} +6 -8
  55. package/dist/{handler-BXJTXd02.d.mts → handler-CZ4nAylQ.d.mts} +2 -1
  56. package/dist/{headers-BOg_velo.mjs → headers-DWi2IXWx.mjs} +1 -1
  57. package/dist/help-DofyZuY7.mjs +2 -0
  58. package/dist/{help-DC7gdz7L.mjs → help-daGKjXGk.mjs} +268 -666
  59. package/dist/index.d.mts +1 -1
  60. package/dist/index.mjs +305 -1490
  61. package/dist/info-B97bTX9N.mjs +113 -0
  62. package/dist/{init-WO0JlPx8.mjs → init-Bvy7zrBo.mjs} +51 -20
  63. package/dist/limits-Bq5LG8Id.d.mts +27 -0
  64. package/dist/limits-Cjuk2VPm.mjs +68 -0
  65. package/dist/{link-CsHOinF7.mjs → link-CDqqCjFl.mjs} +5 -5
  66. package/dist/{list-CDb-4bZ1.mjs → list-CZj0dzKY.mjs} +5 -5
  67. package/dist/{live-CKiJilLr.d.mts → live-Chw1eIMv.d.mts} +1 -1
  68. package/dist/{local-d1-CC8sKFGu.mjs → local-d1-2CMnpuW_.mjs} +2 -2
  69. package/dist/login-DYt_An22.mjs +2 -0
  70. package/dist/{login-DvqXsfGs.mjs → login-UZKFM_u7.mjs} +5 -5
  71. package/dist/{logs-BdfiOezj.mjs → logs-CUZ6t9t3.mjs} +5 -5
  72. package/dist/migrate-8_2u55MD.mjs +2 -0
  73. package/dist/{migrate-B8KuoYsO.mjs → migrate-DHul7PRV.mjs} +5 -4
  74. package/dist/{node-BM43oz4G.mjs → node-BkyRWRx8.mjs} +2 -2
  75. package/dist/operator-args-CLgKGlwU.mjs +690 -0
  76. package/dist/{operator-cmd-03819ATr.mjs → operator-cmd-DBA6dl0m.mjs} +69 -23
  77. package/dist/output-Dm_A4Tbv.mjs +81 -0
  78. package/dist/pages/client.d.mts +34 -2
  79. package/dist/pages/client.mjs +59 -3
  80. package/dist/pages/index.d.mts +1 -1
  81. package/dist/pages/index.mjs +3 -3
  82. package/dist/pages/islands-plugin.d.mts +16 -6
  83. package/dist/pages/islands-plugin.mjs +2 -2
  84. package/dist/pages/protocol.d.mts +2 -2
  85. package/dist/pages/protocol.mjs +2 -308
  86. package/dist/{parse-filename-DioPHiR9.mjs → parse-filename-CUbj-1MP.mjs} +35 -1
  87. package/dist/{output-CCH48AMM.mjs → picocolors-BTps1_gs.mjs} +2 -76
  88. package/dist/plan-D1Q5rf-r.mjs +2 -0
  89. package/dist/plan-NPpwZ_kc.mjs +58 -0
  90. package/dist/platform-args-BJdRtlLq.mjs +506 -0
  91. package/dist/platform-args-D3RXyR6h.mjs +2 -0
  92. package/dist/{platform-auth-config-z92h63q5.mjs → platform-auth-config-B56E9YP1.mjs} +4 -4
  93. package/dist/{platform-auth-protection-DeE3yr2R.mjs → platform-auth-protection-BDWO_aER.mjs} +3 -3
  94. package/dist/{platform-auth-recovery-o_340Ixx.mjs → platform-auth-recovery-1gg4CSRe.mjs} +4 -4
  95. package/dist/{platform-cmd-C4ZV3Vpy.mjs → platform-cmd-Bt-1w6pY.mjs} +1 -1
  96. package/dist/{platform-cmd-DNl8WosH.mjs → platform-cmd-DMcQStSc.mjs} +26 -5
  97. package/dist/{platform-domain-CU1JtJkW.mjs → platform-domain-BNkcz0OB.mjs} +36 -9
  98. package/dist/{platform-lifecycle-Bc047IeT.mjs → platform-lifecycle-9OyBALhH.mjs} +850 -276
  99. package/dist/{platform-lifecycle-Bs2qx1E3.mjs → platform-lifecycle-BE6C_jxh.mjs} +1 -1
  100. package/dist/{platform-management-CVpGI9Y5.mjs → platform-management-CjwLVQwN.mjs} +59 -11
  101. package/dist/{platform-management-C8tt6D8h.mjs → platform-management-CnyTdcWX.mjs} +1 -1
  102. package/dist/platform-plans-config-BNGKGr4P.mjs +359 -0
  103. package/dist/{platform-recovery-dvUaptLr.mjs → platform-recovery-D6KSpuFm.mjs} +2 -2
  104. package/dist/{plugin-inference-BMfKRSqE.mjs → plugin-inference-CXWnn79A.mjs} +174 -64
  105. package/dist/{prepare-DyZ-Yok5.mjs → prepare-B5Mkic5u.mjs} +3 -3
  106. package/dist/{prepare-C3kt3Rst.mjs → prepare-DOsL0CC9.mjs} +4 -20
  107. package/dist/prepare-cgvDMtSb.mjs +2 -0
  108. package/dist/{project-cmd-B44I8J_W.mjs → project-cmd-CNzrqvBv.mjs} +30 -16
  109. package/dist/{project-team-BkbYIsXN.mjs → project-team-DQOWPfQT.mjs} +4 -4
  110. package/dist/{project-token-C8xEEQnB.mjs → project-token-CTDYU0Cc.mjs} +4 -4
  111. package/dist/project-zero-trust-BNAkW-_0.mjs +63 -0
  112. package/dist/{protocol-ZH3jP4a7.d.mts → protocol-CjF_iI9X.d.mts} +2 -2
  113. package/dist/protocol-U7bfjHmA.mjs +331 -0
  114. package/dist/{provision-DNtrtaVD.mjs → provision-C4ORE7G7.mjs} +1 -1
  115. package/dist/{provision-BhreDAOS.mjs → provision-CJFgTZY8.mjs} +111 -215
  116. package/dist/{requests-DFyhBMaf.mjs → requests-MhxYnau8.mjs} +4 -4
  117. package/dist/resource-name-C7LVpcRm.mjs +11 -0
  118. package/dist/{rollback-DHHxXZiS.mjs → rollback-CJ6iSDoU.mjs} +5 -5
  119. package/dist/route-url-CG7U-cRN.mjs +15 -0
  120. package/dist/{runner-B8wXwWlo.mjs → runner-CXA9Fh8h.mjs} +1 -1
  121. package/dist/{runner-p-dMs2UN.mjs → runner-Ol0TNjk6.mjs} +2 -2
  122. package/dist/runtime/ai.d.mts +12 -8
  123. package/dist/runtime/ai.mjs +84 -17
  124. package/dist/runtime/better-auth-mysql.mjs +1 -1
  125. package/dist/runtime/better-auth-pg.mjs +1 -1
  126. package/dist/runtime/better-auth.mjs +1 -1
  127. package/dist/runtime/client-react.mjs +2 -2
  128. package/dist/runtime/client-solid.mjs +2 -2
  129. package/dist/runtime/client-svelte.mjs +2 -2
  130. package/dist/runtime/client-vue.mjs +2 -2
  131. package/dist/runtime/client.mjs +2 -2
  132. package/dist/runtime/durable.d.mts +3 -1
  133. package/dist/runtime/durable.mjs +4 -1
  134. package/dist/runtime/email/testing.mjs +1 -1
  135. package/dist/runtime/env-public.d.mts +1 -1
  136. package/dist/runtime/fetch-stream.mjs +1 -1
  137. package/dist/runtime/fetch.mjs +1 -1
  138. package/dist/runtime/handler.d.mts +1 -1
  139. package/dist/runtime/kv.mjs +0 -1
  140. package/dist/runtime/limits.d.mts +2 -0
  141. package/dist/runtime/limits.mjs +2 -0
  142. package/dist/runtime/live-client.d.mts +1 -1
  143. package/dist/runtime/live-server.mjs +25 -16
  144. package/dist/runtime/live.d.mts +1 -1
  145. package/dist/runtime/migration-handler.mjs +62 -42
  146. package/dist/runtime/route-url.d.mts +4 -0
  147. package/dist/runtime/route-url.mjs +2 -0
  148. package/dist/runtime/routing.d.mts +180 -0
  149. package/dist/runtime/routing.mjs +1082 -0
  150. package/dist/runtime/sandbox-container.d.mts +3 -0
  151. package/dist/runtime/sandbox-container.mjs +2 -0
  152. package/dist/runtime/sandbox.d.mts +4 -32
  153. package/dist/runtime/sandbox.mjs +151 -75
  154. package/dist/runtime/sse.mjs +1 -1
  155. package/dist/runtime/validator.d.mts +1 -1
  156. package/dist/runtime/ws-server.d.mts +4 -2
  157. package/dist/runtime/ws-server.mjs +27 -2
  158. package/dist/runtime/ws.d.mts +2 -2
  159. package/dist/runtime/ws.mjs +8 -6
  160. package/dist/sandbox-XZAqzFlG.d.mts +52 -0
  161. package/dist/sandbox-container-Bo0eiFKz.d.mts +73 -0
  162. package/dist/sandbox-container-C6ItmVuN.mjs +281 -0
  163. package/dist/{scan-4tfN-PSn.mjs → scan-C7okrLyM.mjs} +4 -35
  164. package/dist/{secret-DN9sSNiV.mjs → secret-Dli5fP0B.mjs} +6 -6
  165. package/dist/{skills-O6FUaizK.mjs → skills-D1II1Juz.mjs} +1 -1
  166. package/dist/{sse-BaC1jXko.mjs → sse-CQNaDFFV.mjs} +6 -3
  167. package/dist/{subcommand-prompt-BuGYkAkC.mjs → subcommand-prompt-CY1C4fvl.mjs} +2 -2
  168. package/dist/validate-Dq_L3s0S.mjs +2 -0
  169. package/dist/{validate-CIUwFpjB.mjs → validate-ctOrgiS3.mjs} +2 -1
  170. package/dist/{wrangler-BymcxrRa.mjs → wrangler-7K-bW_DL.mjs} +14 -235
  171. package/dist/{ws-BwcqizuH.d.mts → ws-CL1w7GXU.d.mts} +13 -2
  172. package/package.json +48 -33
  173. package/sandbox.Dockerfile +4 -0
  174. package/schema.json +10 -22
  175. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +34 -157
  176. package/skills/void/SKILL.md +50 -133
  177. package/skills/void/docs/guide/ai.md +94 -84
  178. package/skills/void/docs/guide/app-types.md +3 -32
  179. package/skills/void/docs/guide/auth.md +12 -116
  180. package/skills/void/docs/guide/database/d1.md +9 -54
  181. package/skills/void/docs/guide/database/mysql.md +1 -1
  182. package/skills/void/docs/guide/database/postgresql.md +5 -26
  183. package/skills/void/docs/guide/database.md +23 -75
  184. package/skills/void/docs/guide/deployment.md +27 -113
  185. package/skills/void/docs/guide/durable-state.md +43 -18
  186. package/skills/void/docs/guide/edge/headers.md +3 -47
  187. package/skills/void/docs/guide/edge/prerendering.md +5 -20
  188. package/skills/void/docs/guide/edge/redirects.md +11 -64
  189. package/skills/void/docs/guide/edge/revalidation.md +6 -19
  190. package/skills/void/docs/guide/edge/rewrites.md +56 -284
  191. package/skills/void/docs/guide/edge/static-assets.md +23 -72
  192. package/skills/void/docs/guide/email/domains.md +112 -0
  193. package/skills/void/docs/guide/email/receiving.md +139 -0
  194. package/skills/void/docs/guide/email/sending.md +231 -0
  195. package/skills/void/docs/guide/email.md +13 -619
  196. package/skills/void/docs/guide/env-migration.md +11 -11
  197. package/skills/void/docs/guide/env-vars.md +9 -29
  198. package/skills/void/docs/guide/index.md +0 -15
  199. package/skills/void/docs/guide/jobs.md +3 -18
  200. package/skills/void/docs/guide/kv.md +5 -11
  201. package/skills/void/docs/guide/live.md +5 -56
  202. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +78 -125
  203. package/skills/void/docs/guide/pages-routing/head.md +10 -10
  204. package/skills/void/docs/guide/pages-routing/islands.md +6 -36
  205. package/skills/void/docs/guide/pages-routing/layouts.md +6 -128
  206. package/skills/void/docs/guide/pages-routing/loaders.md +3 -19
  207. package/skills/void/docs/guide/pages-routing/markdown.md +13 -171
  208. package/skills/void/docs/guide/pages-routing/overview.md +7 -17
  209. package/skills/void/docs/guide/pages-routing/view-transitions.md +1 -1
  210. package/skills/void/docs/guide/platform/administration/access.md +1 -4
  211. package/skills/void/docs/guide/platform/administration/email.md +35 -8
  212. package/skills/void/docs/guide/platform/administration/operations.md +26 -4
  213. package/skills/void/docs/guide/platform/administration/plans.md +126 -0
  214. package/skills/void/docs/guide/platform/administration/projects.md +5 -2
  215. package/skills/void/docs/guide/platform/administration/zero-trust.md +189 -0
  216. package/skills/void/docs/guide/platform/development/local.md +2 -2
  217. package/skills/void/docs/guide/platform/development/runtime.md +3 -13
  218. package/skills/void/docs/guide/platform/development/schema-ci.md +0 -58
  219. package/skills/void/docs/guide/platform/installation/credentials.md +6 -4
  220. package/skills/void/docs/guide/platform/installation/domains.md +31 -3
  221. package/skills/void/docs/guide/platform/installation/first-deployment.md +6 -0
  222. package/skills/void/docs/guide/platform/installation/maintenance.md +3 -1
  223. package/skills/void/docs/guide/platform/installation/prerequisites.md +21 -16
  224. package/skills/void/docs/guide/platform/installation/setup.md +9 -5
  225. package/skills/void/docs/guide/platform/installation/uninstall.md +17 -2
  226. package/skills/void/docs/guide/platform-administration.md +2 -0
  227. package/skills/void/docs/guide/queues.md +7 -9
  228. package/skills/void/docs/guide/quickstart.md +38 -37
  229. package/skills/void/docs/guide/remote-dev.md +4 -9
  230. package/skills/void/docs/guide/sandboxes.md +78 -41
  231. package/skills/void/docs/guide/server-routing.md +9 -72
  232. package/skills/void/docs/guide/sse.md +4 -18
  233. package/skills/void/docs/guide/ssg.md +3 -15
  234. package/skills/void/docs/guide/ssr.md +14 -62
  235. package/skills/void/docs/guide/storage.md +9 -4
  236. package/skills/void/docs/guide/type-safety.md +3 -14
  237. package/skills/void/docs/guide/typed-fetch.md +3 -7
  238. package/skills/void/docs/guide/websockets.md +68 -40
  239. package/skills/void/docs/integrations/agents.md +3 -3
  240. package/skills/void/docs/integrations/cloudflare.md +85 -316
  241. package/skills/void/docs/integrations/frameworks/analog.md +5 -64
  242. package/skills/void/docs/integrations/frameworks/astro.md +4 -73
  243. package/skills/void/docs/integrations/frameworks/nuxt.md +5 -62
  244. package/skills/void/docs/integrations/frameworks/overview.md +11 -54
  245. package/skills/void/docs/integrations/frameworks/react-router.md +5 -60
  246. package/skills/void/docs/integrations/frameworks/sveltekit.md +6 -65
  247. package/skills/void/docs/integrations/frameworks/tanstack-start.md +4 -62
  248. package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -69
  249. package/skills/void/docs/reference/api/auth.md +156 -0
  250. package/skills/void/docs/reference/api/client.md +87 -0
  251. package/skills/void/docs/reference/api/database.md +95 -0
  252. package/skills/void/docs/reference/api/durable.md +46 -0
  253. package/skills/void/docs/reference/api/env.md +50 -0
  254. package/skills/void/docs/reference/api/handlers.md +254 -0
  255. package/skills/void/docs/reference/api/pages.md +241 -0
  256. package/skills/void/docs/reference/api/plugin.md +39 -0
  257. package/skills/void/docs/reference/api/resources.md +109 -0
  258. package/skills/void/docs/reference/api/rewrites.md +76 -0
  259. package/skills/void/docs/reference/api/types.md +92 -0
  260. package/skills/void/docs/reference/api.md +56 -1218
  261. package/skills/void/docs/reference/cli/auth.md +88 -0
  262. package/skills/void/docs/reference/cli/database.md +128 -0
  263. package/skills/void/docs/reference/cli/deploy.md +85 -0
  264. package/skills/void/docs/reference/cli/domains.md +41 -0
  265. package/skills/void/docs/reference/cli/email.md +129 -0
  266. package/skills/void/docs/reference/cli/generate.md +116 -0
  267. package/skills/void/docs/reference/cli/github.md +189 -0
  268. package/skills/void/docs/reference/cli/platform-config.md +92 -0
  269. package/skills/void/docs/reference/cli/platform-email.md +81 -0
  270. package/skills/void/docs/reference/cli/platform-installation.md +127 -0
  271. package/skills/void/docs/reference/cli/platform-operations.md +90 -0
  272. package/skills/void/docs/reference/cli/platform-users.md +89 -0
  273. package/skills/void/docs/reference/cli/platform-zero-trust.md +45 -0
  274. package/skills/void/docs/reference/cli/platform.md +70 -0
  275. package/skills/void/docs/reference/cli/project.md +214 -0
  276. package/skills/void/docs/reference/cli/secrets.md +76 -0
  277. package/skills/void/docs/reference/cli/setup.md +70 -0
  278. package/skills/void/docs/reference/cli.md +33 -1621
  279. package/skills/void/docs/reference/config.md +26 -32
  280. package/skills/void/docs/reference/resource-inference.md +3 -58
  281. package/skills/void/docs/reference/structure.md +14 -41
  282. package/dist/canonical-json-DuDiiUsQ.mjs +0 -13
  283. package/dist/cli/cf-compat.mjs +0 -968
  284. package/dist/client-4cDVv7BO.mjs +0 -2
  285. package/dist/gen-Vnv2f65C.mjs +0 -2
  286. package/dist/help-DQMfeKMz.mjs +0 -2
  287. package/dist/login-DFQk7rbW.mjs +0 -2
  288. package/dist/migrate-TsHGBnDA.mjs +0 -2
  289. package/dist/plan-BEZ8VJW0.mjs +0 -256
  290. package/dist/plan-DpuOr14e.mjs +0 -2
  291. package/dist/prepare-BZXkjdNe.mjs +0 -2
  292. package/dist/validate-EKmJWxmy.mjs +0 -2
  293. /package/dist/cli/{cf-compat.d.mts → cloudflare-operation-process.d.mts} +0 -0
@@ -50,38 +50,15 @@ function namedLayoutItems(ext) {
50
50
  ]
51
51
  }
52
52
 
53
- function blogLayoutItems(ext) {
54
- return [
55
- {
56
- name: "pages/",
57
- children: [
58
- {
59
- name: "_layouts/",
60
- children: [
61
- { name: `post${ext}`, description: "sidebar, date, author" },
62
- ],
63
- },
64
- { name: `layout${ext}`, description: "nav + footer" },
65
- {
66
- name: "blog/",
67
- children: [
68
- { name: `layout${ext}`, description: "blog sidebar" },
69
- { name: "hello.md", description: "layout: post → chain: [root, _layouts/post]" },
70
- { name: `archive${ext}`, description: "(no layout) → chain: [root, blog/layout]" },
71
- ],
72
- },
73
- ],
74
- },
75
- ]
76
- }
77
-
78
53
  </script>
79
54
 
80
55
  # Layouts & Shared Data
81
56
 
57
+ Use layouts for navigation, headers, and other UI shared by several pages. Layouts nest with your directories and keep their component state as you navigate.
58
+
82
59
  ## Layouts
83
60
 
84
- Place a layout file in any `pages/` directory to wrap all pages in that subtree:
61
+ Place a layout file in a `pages/` directory to wrap its pages:
85
62
 
86
63
  <FileTree :items="layoutBasicItems" adapter-tabs default-expanded />
87
64
 
@@ -169,8 +146,6 @@ When a page renders, the layout wraps it. The page component is injected as the
169
146
 
170
147
  <img src="./layout-nesting.svg" alt="Layout nesting diagram: pages/layout wraps pages/users/layout wraps pages/users/[id] page component" style="max-width: 520px; width: 100%;" />
171
148
 
172
- Layouts nest automatically and persist across navigations within their subtree, so component state is preserved.
173
-
174
149
  ## Named Layouts
175
150
 
176
151
  Named layouts let individual pages opt into a different layout without changing the URL structure. Define them in `_layouts/` directories within `pages/`:
@@ -237,68 +212,9 @@ layout: post
237
212
  | `"!landing"` | Replace the **entire** chain. Only the named layout wraps the page. |
238
213
  | `false` | No layout wrapping at all. Page renders standalone. |
239
214
 
240
- "Innermost" means the deepest layout in the resolved chain. If the chain is `[root, docs/layout]`, the named layout replaces `docs/layout`. If the chain is only `[root]`, it replaces root.
241
-
242
- ### Resolution order
243
-
244
- When a page specifies `layout: "post"`, the scanner walks up the directory tree to find `_layouts/post`:
245
-
246
- ```
247
- pages/guide/intro.md (layout: post)
248
-
249
- 1. pages/guide/_layouts/post.vue → not found
250
- 2. pages/_layouts/post.vue → found ✓
251
- ```
252
-
253
- Closest ancestor wins, same as default layout chain. If no matching named layout is found in any ancestor, the build fails with a clear error.
254
-
255
- ### Examples
256
-
257
- **Blog with shared nav but post-specific layout:**
258
-
259
- <FileTree :items="blogLayoutItems" adapter-tabs default-expanded />
260
-
261
- `layout: post` on `blog/hello.md` replaces the innermost default layout (`blog/layout`) with `_layouts/post`. The root layout still wraps.
262
-
263
- **Fullscreen page with no layout:**
264
-
265
- ::: code-group
266
-
267
- ```tsx [React]
268
- export const layout = false;
269
-
270
- export default function Landing() {
271
- return (
272
- <div className="hero fullscreen">
273
- <h1>Welcome</h1>
274
- </div>
275
- );
276
- }
277
- ```
278
-
279
- ```vue [Vue]
280
- <script>
281
- export const layout = false;
282
- </script>
283
-
284
- <template>
285
- <div class="hero fullscreen"><h1>Welcome</h1></div>
286
- </template>
287
- ```
288
-
289
- :::
290
-
291
- **Exclusive layout (skip all ancestors):**
292
-
293
- ```md
294
- ---
295
- layout: '!landing'
296
- ---
215
+ A named layout replaces the deepest default layout: in `[root, docs/layout]`, it replaces `docs/layout`; in `[root]`, it replaces the root.
297
216
 
298
- # Standalone Landing Page
299
- ```
300
-
301
- Only `_layouts/landing` wraps this page, and the root layout is skipped entirely.
217
+ Void uses the closest matching `_layouts/` file in the page's directory or an ancestor. A missing named layout fails the build.
302
218
 
303
219
  ## Shared Data
304
220
 
@@ -322,42 +238,4 @@ export default defineMiddleware(async (c, next) => {
322
238
  });
323
239
  ```
324
240
 
325
- Access it on the client with `useShared()`. The return type is inferred from your augmentation:
326
-
327
- ::: code-group
328
-
329
- ```tsx [React]
330
- import { useShared } from '@void/react';
331
-
332
- export default function Page() {
333
- const { auth } = useShared(); // { auth: { user: AuthUser | null } }
334
- return <p>Hello, {auth?.user?.name}</p>;
335
- }
336
- ```
337
-
338
- ```vue [Vue]
339
- <script setup lang="ts">
340
- import { useShared } from '@void/vue';
341
- const { auth } = useShared(); // { auth: { user: AuthUser | null } }
342
- </script>
343
- ```
344
-
345
- ```svelte [Svelte]
346
- <script>
347
- import { useShared } from "@void/svelte";
348
- const { auth } = useShared(); // { auth: { user: AuthUser | null } }
349
- </script>
350
- ```
351
-
352
- ```tsx [Solid]
353
- import { useShared } from '@void/solid';
354
-
355
- export default function Page() {
356
- const shared = useShared(); // { auth: { user: AuthUser | null } }
357
- return <p>Hello, {shared.auth?.user?.name}</p>;
358
- }
359
- ```
360
-
361
- :::
362
-
363
- Shared data is separate from page props. Props come from the loader, while `useShared()` returns global data from middleware. See [Type Safety](../type-safety.md#context-variables) for more on augmenting `CloudContextVariables`.
241
+ Call `useShared()` from your framework adapter, as in the layout examples above. Its return type is inferred from `CloudContextVariables`. Shared data comes from middleware; page props come from the loader. See [Context variables](../type-safety.md#context-variables).
@@ -24,17 +24,7 @@ export const loader = defineHandler(async (c) => {
24
24
  });
25
25
  ```
26
26
 
27
- `InferProps` extracts the return type from a `defineHandler` call, so you don't need to maintain a separate interface. You can also write the interface explicitly if you prefer:
28
-
29
- ```ts
30
- export interface Props {
31
- users: Array<{ id: number; name: string; email: string }>;
32
- }
33
-
34
- export const loader = defineHandler<Props>(async (c) => {
35
- return { users: await db.select().from(users) };
36
- });
37
- ```
27
+ `InferProps` infers the loader’s return type, so page props stay in sync with the data it returns.
38
28
 
39
29
  ## Using the Data in Page Components
40
30
 
@@ -109,7 +99,7 @@ export default function UsersPage(props: Props) {
109
99
 
110
100
  ## Deferred Props
111
101
 
112
- Loaders sometimes need to fetch slower data such as analytics, external API responses, or AI inference. `defer()` lets you return a placeholder immediately so the page renders quickly, then streams the real data when it resolves:
102
+ Use `defer()` for slow data. The page renders immediately and receives the result when it is ready:
113
103
 
114
104
  ```ts
115
105
  // pages/dashboard.server.ts
@@ -235,16 +225,10 @@ export default function Dashboard(props: Props) {
235
225
 
236
226
  :::
237
227
 
238
- ### How Streaming Works
239
-
240
- On the first request, React renders the nearest Suspense fallback for deferred props; the other adapters render their loading state. As data becomes available, the server sends it in inline scripts on the same response.
241
-
242
- A route with `ssr = false` still receives those scripts, even though its component mounts in the browser. During client-side navigation, deferred data arrives as newline-delimited JSON on the navigation response.
243
-
244
228
  ### Deferred Props After Mutations
245
229
 
246
230
  ::: info
247
- When a mutation runs, the loader runs again to provide fresh props, but deferred props cannot stream over a mutation response. The client preserves the last resolved value for each deferred prop, so the UI keeps showing the previous data until the next full page load or SPA navigation.
231
+ After an action, deferred props keep their last resolved values until the next page load or client-side navigation. Other loader props refresh immediately.
248
232
  :::
249
233
 
250
234
  ### Grouped Deferred Props
@@ -33,9 +33,7 @@ function mdFileItems(ext) {
33
33
 
34
34
  # Markdown
35
35
 
36
- Markdown pages let you use `.md` files as first-class pages in Void's file-based routing. They compile to static HTML at build time with zero client JavaScript, integrate with the layout chain, and can embed interactive framework components as [islands](./islands).
37
-
38
- The `@void/md` package is opt-in as it contains markdown processing and syntax highlighting dependencies that are not necessarily needed in every app.
36
+ Add `.md` files to `pages/` for Markdown routes. Pages inherit layouts and render as HTML, with JavaScript only for [islands](./islands), client scripts, and code-copy buttons.
39
37
 
40
38
  ## Setup
41
39
 
@@ -115,8 +113,6 @@ export default defineConfig({
115
113
 
116
114
  :::
117
115
 
118
- That's it. Any `.md` file in `pages/` is now a routable page.
119
-
120
116
  ## Page Anatomy
121
117
 
122
118
  A markdown page has three optional parts: a script block, frontmatter, and the body.
@@ -146,7 +142,7 @@ Welcome to Void. Here's an interactive demo:
146
142
 
147
143
  ## Client Scripts
148
144
 
149
- The `<script>` block can contain both island imports and regular JavaScript. Island imports (with `{ island }`) go through the SSR + hydration pipeline as usual. Everything else is bundled as a client module and executed when the page loads.
145
+ Use the `<script>` block for island imports and JavaScript that runs when the page loads:
150
146
 
151
147
  ```md
152
148
  <script>
@@ -163,14 +159,7 @@ document.querySelector('.date').textContent = format(new Date(), 'PPP')
163
159
  Published: <span class="date"></span>
164
160
  ```
165
161
 
166
- In this example:
167
-
168
- - `Counter` is an island, so it is SSR'd and hydrated on the client
169
- - `date-fns` and the `querySelector` call are client code, so they are bundled and run on page load
170
-
171
- Each page's client script is code-split into its own chunk via dynamic import, so only the current page's script is loaded. Pages without client code ship zero extra JS.
172
-
173
- Client scripts work in both dev (served on-demand, HMR support) and production builds.
162
+ Only the current page's client script loads. Pages without client code need no additional script.
174
163
 
175
164
  ## File Structure
176
165
 
@@ -329,7 +318,7 @@ Users who want full control can skip the import and write their own CSS.
329
318
 
330
319
  ## Markdown Features
331
320
 
332
- All features produce static HTML at build time with zero client JS (except the copy button).
321
+ Markdown features render as static HTML. Code-copy buttons add a small client script.
333
322
 
334
323
  ### Containers
335
324
 
@@ -378,7 +367,7 @@ Custom titles work too: `::: tip Pro Tip`.
378
367
 
379
368
  ### Syntax Highlighting
380
369
 
381
- Code blocks are highlighted at build time with [Shiki](https://shiki.style) using dual light and dark themes by default: `github-light` and `github-dark`. No client-side JavaScript is needed because theme switching is pure CSS.
370
+ Code blocks use [Shiki](https://shiki.style) with `github-light` and `github-dark` themes by default.
382
371
 
383
372
  ### Line Highlighting
384
373
 
@@ -408,9 +397,7 @@ export function hello() {
408
397
  }
409
398
  ```
410
399
 
411
- ### Copy Button
412
-
413
- Code blocks include a copy button. That is the only feature here that needs client-side JS, and it only adds a roughly 200 byte inline script for the clipboard API. The script is injected only when code blocks are present.
400
+ Code blocks include a copy button.
414
401
 
415
402
  ### Line Numbers
416
403
 
@@ -459,21 +446,9 @@ Add classes, IDs, or attributes to any element:
459
446
  Paragraph with attributes. {.note}
460
447
  ```
461
448
 
462
- ### Heading Anchors
463
-
464
- All headings get permalink anchors automatically, enabling direct linking to any section.
465
-
466
- ### Table of Contents
449
+ ### Navigation and Media
467
450
 
468
- Use the `[[toc]]` directive to render an inline table of contents from the page's headings.
469
-
470
- ### Images
471
-
472
- Image paths are normalized automatically. Images are lazy-loaded by default.
473
-
474
- ### Links
475
-
476
- External links automatically get `target="_blank" rel="noreferrer"`. Internal `.md` references resolve to their route paths.
451
+ Headings include permalink anchors. Use `[[toc]]` for a table of contents. Images are lazy-loaded, and `.md` links resolve to page routes.
477
452
 
478
453
  ## Plugin Options
479
454
 
@@ -491,147 +466,14 @@ voidMarkdown({
491
466
  | `shiki.themes` | `{ light: string; dark: string}` | `{ light: "github-light", dark: "github-dark" }` | Shiki color themes |
492
467
  | `shiki.langs` | `string[]` | Common web languages | Additional languages to load |
493
468
 
494
- ## Example: Docs Layout with Sidebar
495
-
496
- Here's a full example of a docs layout using `useFrontmatter()` and `@void/md/pages` to build a sidebar:
497
-
498
- ::: code-group
499
-
500
- ```tsx [React]
501
- // pages/docs/layout.island.tsx
502
- import '@void/md/theme-content.css';
503
- import { useFrontmatter } from '@void/md';
504
- import pages from '@void/md/pages';
505
- import { useRouter } from '@void/react';
506
-
507
- const docPages = pages.filter((p) => p.path.startsWith('/docs/'));
469
+ ## Building a Sidebar
508
470
 
509
- export default function DocsLayout({ children }) {
510
- const fm = useFrontmatter();
511
- const { path } = useRouter();
512
-
513
- return (
514
- <div className="docs-layout">
515
- <aside>
516
- <nav>
517
- {docPages.map((page) => (
518
- <a key={page.path} href={page.path} className={page.path === path ? 'active' : ''}>
519
- {page.title}
520
- </a>
521
- ))}
522
- </nav>
523
- </aside>
524
- <main className="void-md">
525
- <h1>{fm.title}</h1>
526
- {children}
527
- </main>
528
- </div>
529
- );
530
- }
531
- ```
471
+ Use `@void/md/pages` to select the pages for your sidebar:
532
472
 
533
- ```vue [Vue]
534
- <!-- pages/docs/layout.island.vue -->
535
- <script setup>
536
- import { useFrontmatter } from '@void/md';
537
- import pages from '@void/md/pages';
538
- import { useRouter } from '@void/vue';
539
-
540
- const fm = useFrontmatter();
541
- const { path } = useRouter();
542
- const docPages = pages.filter((p) => p.path.startsWith('/docs/'));
543
- </script>
544
-
545
- <style>
546
- @import '@void/md/theme-content.css';
547
- </style>
548
-
549
- <template>
550
- <div class="docs-layout">
551
- <aside>
552
- <nav>
553
- <a
554
- v-for="page in docPages"
555
- :key="page.path"
556
- :href="page.path"
557
- :class="{ active: page.path === path }"
558
- >
559
- {{ page.title }}
560
- </a>
561
- </nav>
562
- </aside>
563
- <main class="void-md">
564
- <h1>{{ fm.title }}</h1>
565
- <slot />
566
- </main>
567
- </div>
568
- </template>
569
- ```
570
-
571
- ```svelte [Svelte]
572
- <!-- pages/docs/layout.island.svelte -->
573
- <script>
574
- import "@void/md/theme-content.css";
575
- import { useFrontmatter } from "@void/md";
576
- import pages from "@void/md/pages";
577
- import { useRouter } from "@void/svelte";
578
-
579
- const fm = useFrontmatter();
580
- const { path } = useRouter();
581
- const docPages = pages.filter((p) => p.path.startsWith("/docs/"));
582
- </script>
583
-
584
- <div class="docs-layout">
585
- <aside>
586
- <nav>
587
- {#each docPages as page}
588
- <a href={page.path} class:active={page.path === path}>
589
- {page.title}
590
- </a>
591
- {/each}
592
- </nav>
593
- </aside>
594
- <main class="void-md">
595
- <h1>{fm.title}</h1>
596
- <slot />
597
- </main>
598
- </div>
599
- ```
600
-
601
- ```tsx [Solid]
602
- // pages/docs/layout.island.tsx
603
- import '@void/md/theme-content.css';
604
- import { useFrontmatter } from '@void/md';
473
+ ```ts
605
474
  import pages from '@void/md/pages';
606
- import { useRouter } from '@void/solid';
607
- import { For } from 'solid-js';
608
475
 
609
- const docPages = pages.filter((p) => p.path.startsWith('/docs/'));
610
-
611
- export default function DocsLayout(props) {
612
- const fm = useFrontmatter();
613
- const { path } = useRouter();
614
-
615
- return (
616
- <div class="docs-layout">
617
- <aside>
618
- <nav>
619
- <For each={docPages}>
620
- {(page) => (
621
- <a href={page.path} classList={{ active: page.path === path() }}>
622
- {page.title}
623
- </a>
624
- )}
625
- </For>
626
- </nav>
627
- </aside>
628
- <main class="void-md">
629
- <h1>{fm.title}</h1>
630
- {props.children}
631
- </main>
632
- </div>
633
- );
634
- }
476
+ const docPages = pages.filter((page) => page.path.startsWith('/docs/'));
635
477
  ```
636
478
 
637
- :::
479
+ Render a link with `page.path` and `page.title` for each entry. Use `useFrontmatter()` in the layout to display the current page's metadata, and wrap its content in `.void-md` when using the provided theme.
@@ -86,9 +86,7 @@ export default defineConfig({
86
86
 
87
87
  :::
88
88
 
89
- The adapter generates the server entry, client entry, and hydration code.
90
-
91
- Each adapter plugin includes the framework's Vite plugin (`@vitejs/plugin-react`, `@vitejs/plugin-vue`, `@sveltejs/vite-plugin-svelte`, `vite-plugin-solid`) so you don't need to install or configure it separately. Pass framework plugin options via `voidReact({ react: { ... } })`, `voidVue({ vue: { ... } })`, `voidSvelte({ svelte: { ... } })`, or `voidSolid({ solid: { ... } })` if needed.
89
+ Each adapter includes its framework's Vite plugin. Pass framework plugin options via `voidReact({ react: { ... } })`, `voidVue({ vue: { ... } })`, `voidSvelte({ svelte: { ... } })`, or `voidSolid({ solid: { ... } })` if needed.
92
90
 
93
91
  ## Directory Structure
94
92
 
@@ -106,15 +104,7 @@ File-based routing rules are the same as [server routing](../server-routing.md):
106
104
 
107
105
  ## How Navigation Works
108
106
 
109
- The first page load and later navigations use the same server loaders:
110
-
111
- | Request | Response |
112
- | --------------------- | -------------------------------------------------------------------------------------------------------------- |
113
- | Initial page load | Full SSR HTML. Client hydrates automatically. Routes with `ssr = false` return a client-mounted shell instead. |
114
- | Subsequent navigation | JSON with component name + props. Client component swap or re-render. |
115
- | Form submission | Runs action, then returns fresh props or a redirect. |
116
-
117
- The first request receives rendered HTML. Later navigations load page data and update the UI without reloading the whole document.
107
+ The first request receives rendered HTML. Later navigations run the loader and update the page without reloading the document. Form submissions run an action, then refresh page props or redirect.
118
108
 
119
109
  To opt a specific route out of server-rendered component HTML, export `ssr = false` from its companion `.server.ts` file:
120
110
 
@@ -182,7 +172,7 @@ import { Link } from "@void/solid";
182
172
 
183
173
  :::
184
174
 
185
- The `Link` components also support query data, history replacement, document navigation, and cancellable client-side navigation:
175
+ `Link` also supports query data, history replacement, full-page navigation, and cancellation:
186
176
 
187
177
  ```tsx
188
178
  <Link href="/users" data={{ page: 2, tag: ['active', 'new'] }}>
@@ -209,7 +199,7 @@ The `Link` components also support query data, history replacement, document nav
209
199
  </Link>
210
200
  ```
211
201
 
212
- `prefetch` and `reloadDocument` are GET-only. Passing either prop to a mutation link throws. GET `data` is merged into the rendered `href` query string; arrays become repeated keys, `null` and `undefined` are omitted, and nested objects throw.
202
+ `prefetch` and `reloadDocument` work only with GET links. GET `data` becomes query parameters; use scalar values or arrays.
213
203
 
214
204
  For programmatic navigation, use `useRouter()`:
215
205
 
@@ -235,13 +225,13 @@ export default function PostPage() {
235
225
 
236
226
  ## Scroll Restoration
237
227
 
238
- The Void Router automatically saves and restores scroll position during client-side navigation:
228
+ Client-side navigation manages scroll position automatically:
239
229
 
240
230
  - **Back/forward navigation** restores the exact scroll position you were at before navigating away.
241
- - **Forward navigation** scrolls to the top of the page.
231
+ - **New navigation** scrolls to the top of the page.
242
232
  - **Hash links** (`/docs#api`) scroll to the target element. Same-page hash links (`#section`) skip the server fetch entirely.
243
233
 
244
- This works out of the box with no configuration. If you need to opt out for a specific navigation, pass `preserveScroll: true`:
234
+ To keep the current scroll position, pass `preserveScroll: true`:
245
235
 
246
236
  ```ts
247
237
  router.visit('/users', { preserveScroll: true });
@@ -4,7 +4,7 @@ outline: deep
4
4
 
5
5
  # View Transitions
6
6
 
7
- Pages mode supports the browser's native [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API) for animated page transitions. When enabled, navigations are wrapped in `document.startViewTransition()`, which gives you a smooth cross-fade between pages by default. You can customize the effect entirely with CSS.
7
+ Add animated page transitions with the browser’s [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API). Pages cross-fade by default; use CSS to customize the animation.
8
8
 
9
9
  ## Enabling View Transitions
10
10
 
@@ -30,10 +30,7 @@ the company sign-in before Void login. Interactive Access authentication uses a
30
30
  locally installed `cloudflared` and saves its short-lived credential in your
31
31
  system keychain for that platform origin. You do not need to copy browser cookies.
32
32
 
33
- For CI, Access credentials do not replace Void deployment credentials. A project
34
- owner creates the latter with `void project token create`; it is independently
35
- revocable, expires within 90 days, and authorizes only that project's deploy
36
- workflow. Human and operator tokens cannot be renewed by Access service proof.
33
+ For CI, use a [project deploy token](/guide/platform/installation/first-deployment) alongside your Access credentials. An Access service token does not authorize a Void deployment.
37
34
 
38
35
  Store Access credentials in origin-keyed `VOID_ACCESS_CREDENTIALS`. A deploy
39
36
  that uses prerendering or remote bindings needs entries for both the exact API
@@ -6,7 +6,26 @@ outline: deep
6
6
 
7
7
  ## Managing Email
8
8
 
9
- These commands apply to a platform that enables email. Every project can send from and receive at `<slug>+tag@<mail domain>` on the platform's shared mail domain; the [email guide](/guide/email) describes what applications do with that.
9
+ These commands apply to a platform that enables email. Every project can send from `<slug>+tag@<mail domain>` on the platform’s shared mail domain. Deploying an app with `email/` handlers sets up receiving at that address once its recipient rule is ready; the [email guide](/guide/email) describes what applications do with that.
10
+
11
+ Shared inbound mail uses one exact routing rule per receiving project and enables Cloudflare’s per-zone plus addressing. Creating a project or deploying an app that only sends mail consumes no inbound rule. Existing rules and the apex catch-all remain in place. Cloudflare normally allows [200 routing rules per domain](https://developers.cloudflare.com/email-service/platform/limits/); remove unused rules or request a higher limit if the shared domain reaches capacity. An unrelated rule for a project’s base address or a plus address blocks its setup until that conflict is removed.
12
+
13
+ If recipient creation is interrupted, inspect its retained intent:
14
+
15
+ ```sh
16
+ void platform email shared-recipients --project my-app
17
+ void platform email shared-recipient-resolve <recipient-id> --ended --outcome not-applied --reason "Provider audit confirms the request did not create a rule" --plan
18
+ ```
19
+
20
+ Wait until the reported recovery time, confirm the original execution ended,
21
+ and inspect the exact provider resource shown in the plan. Use `applied` when
22
+ the exact owned rule exists, or `not-applied` only when the provider audit
23
+ establishes that creation did not occur. Absence alone does not establish the
24
+ outcome. Run the same command with `--yes` after inspection. Recovery records
25
+ the decision in platform events without creating or deleting rules. Normal
26
+ reconciliation verifies delivery afterward; a deleting project stays closed
27
+ and its deletion can be retried. See [operator email commands](../../../reference/cli/platform-email.md#operator-email)
28
+ for the recovery requirements.
10
29
 
11
30
  ### Deciding who mail may reach
12
31
 
@@ -19,7 +38,15 @@ void platform email policy-set any
19
38
  void platform email policy-set verified
20
39
  ```
21
40
 
22
- `domains` lets every project mail any address on the listed domains in addition to its verified recipients; `any` lifts the check. Cloudflare still refuses a recipient it has not verified until your mail domain is onboarded for Email Sending, which needs Workers Paid on the platform's account. Until then such sends come back as `UNVERIFIED_DESTINATION` for that recipient, whatever the policy says. Two things the policy never changes: sends from a project's own custom domain, and mail to any address on the platform's own mail domain — those stay verified-recipient-only, so no project reaches another project's inbox without its consent. A tightening applies to new send admissions as soon as it commits; previously admitted attempts may finish. The same setting is on the admin UI's **Email** page.
41
+ Choose a policy in the admin UI's **Email** page or with the commands above:
42
+
43
+ - `verified`: only each project's verified recipients.
44
+ - `domains`: verified recipients plus any address on the listed domains.
45
+ - `any`: any recipient.
46
+
47
+ Unverified recipients still require Cloudflare Email Sending onboarding and [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans). Otherwise those sends return `UNVERIFIED_DESTINATION`. Mail from a project's custom domain, and mail to the platform's own mail domain, always requires recipient verification.
48
+
49
+ Policy changes apply to new sends; admitted attempts may finish.
23
50
 
24
51
  ### Project caps
25
52
 
@@ -75,16 +102,16 @@ void platform email settings-set --domains admin
75
102
  Then register a domain for a project. The zone must be in the platform's Cloudflare account; the platform's own credential does the setup, and no Cloudflare credential is stored per domain:
76
103
 
77
104
  ```sh
78
- void platform email domain-add mail.example.com --project hr-portal
79
- void platform email domain-status mail.example.com
80
- void platform email domain-rotate-secret mail.example.com
105
+ void platform email domain-add example.com --project hr-portal
106
+ void platform email domain-status example.com
107
+ void platform email domain-rotate-secret example.com
81
108
  void platform email domains
82
109
  ```
83
110
 
84
- Name the exact mail domain: a subdomain such as `mail.example.com` when the apex already receives mail, otherwise the apex itself. `domain-status` reports inbound, outbound, and management readiness separately. Follow any required DNS or Cloudflare dashboard step, then use `domain-sync` to reconcile. Use `domain-rotate-secret` when you need to replace the zone ingress credential explicitly. Email Sending onboarding needs Workers Paid; after upgrading, `domain-sync` re-attempts it. For a zone in another Cloudflare account, pipe an API token for that account on standard input:
111
+ Use the apex of the selected Cloudflare zone. Platform-managed custom inbound email uses its catch-all, which does not cover subdomains; choose an apex without another mail provider or use the platform’s shared mail address. `domain-status` reports inbound, outbound, and management readiness separately. Follow any required DNS or Cloudflare dashboard step, then use `domain-sync` to reconcile. Use `domain-rotate-secret` when you need to replace the zone ingress credential explicitly. Email Sending onboarding needs Workers Paid; after upgrading, `domain-sync` re-attempts it. For a zone in another Cloudflare account, pipe an API token for that account on standard input:
85
112
 
86
113
  ```sh
87
- void platform email domain-add mail.other.example --project hr-portal --token-stdin --yes < token.txt
114
+ void platform email domain-add other.example --project hr-portal --token-stdin --yes < token.txt
88
115
  ```
89
116
 
90
117
  Project owners see administrator-registered domains in `void email domain list` and `status`; `status` names the `void platform email` command for any step they cannot take themselves, and `sync` and `remove` point them at `domain-sync` and `domain-remove`. A domain an owner registered before you switched to `admin` stays theirs to renew, sync and remove. The runtime token needs the email permissions listed in the [self-hosting guide](/guide/platform/installation/credentials#runtime-token-permissions) for this to work.
@@ -97,7 +124,7 @@ to finish the retained cleanup. If its token has expired or been revoked, provid
97
124
  a replacement scoped to the same account and zone:
98
125
 
99
126
  ```sh
100
- void platform email domain-remove mail.other.example --token-stdin --yes < token.txt
127
+ void platform email domain-remove other.example --token-stdin --yes < token.txt
101
128
  ```
102
129
 
103
130
  This recovery is available only after project deletion has begun and no other