void 0.26.0 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/AGENTS_TEMPLATE.md +1 -3
  2. package/README.md +19 -9
  3. package/dist/{account-cmd-CDry3B5V.mjs → account-cmd-CfUXh_nU.mjs} +8 -7
  4. package/dist/{application-analysis-DC2yPvzY.mjs → application-analysis-DKy02UY0.mjs} +21 -32
  5. package/dist/{application-routing-C9khgLiS.mjs → application-routing-DQyUh_5S.mjs} +1 -1
  6. package/dist/{auth-D52yG7hl.mjs → auth-B5_tZLxT.mjs} +7 -7
  7. package/dist/{auth-B60QDbjg.mjs → auth-BgX2qYSY.mjs} +1 -1
  8. package/dist/{auth-link-DjeOptYi.mjs → auth-link-D5RmKnzh.mjs} +5 -5
  9. package/dist/{auth-migrations-9vif1uj8.mjs → auth-migrations-BwHgeEsD.mjs} +8 -18
  10. package/dist/{auth-router-BRxIuqDi.mjs → auth-router-Bap-pvbn.mjs} +4 -17
  11. package/dist/{better-auth-shared-BVkjZ3vM.d.mts → better-auth-shared-CPvWD3nG.d.mts} +0 -4
  12. package/dist/{better-auth-shared-hy6RPh9W.mjs → better-auth-shared-DPpj8zxc.mjs} +94 -16
  13. package/dist/{build-cmd-Ce3C8huo.mjs → build-cmd-B58c8iS8.mjs} +7 -6
  14. package/dist/{cache-CS8Yxr5a.mjs → cache-Bo52trKF.mjs} +7 -7
  15. package/dist/{cancel-deploy-mZsD88Xa.mjs → cancel-deploy-BZNz3Q26.mjs} +5 -4
  16. package/dist/{cf-access-YTlqvAsk.mjs → cf-access-ngGqZpHZ.mjs} +10 -11
  17. package/dist/{cf-build-output-U8o1Gl6X.mjs → cf-build-output-DjvB_872.mjs} +62 -85
  18. package/dist/cf-build-output-H9a97vME.mjs +2 -0
  19. package/dist/cli/cli.mjs +48 -83
  20. package/dist/cli/cloudflare-operation-process.mjs +71 -77
  21. package/dist/cli/env-schema-probe.mjs +5 -6
  22. package/dist/client-By4JjMw_.mjs +2 -0
  23. package/dist/{client-mC-dFGDD.mjs → client-C2Prx_Bi.mjs} +28 -6
  24. package/dist/{cloudflare-auth-Qdc7tw8F.mjs → cloudflare-auth-CuxfF6OA.mjs} +9 -17
  25. package/dist/{cloudflare-cmd-bhwCxAN6.mjs → cloudflare-cmd-lHqNlJGW.mjs} +6 -5
  26. package/dist/{cloudflare-config-Bktvwtpf.mjs → cloudflare-config-BmhBv3HV.mjs} +1 -1
  27. package/dist/{cloudflare-connect-CuhRgk3k.mjs → cloudflare-connect-2G3rL2rP.mjs} +4 -4
  28. package/dist/{cloudflare-operations-DoQrVHAt.mjs → cloudflare-operations-BlYLlowZ.mjs} +1 -1
  29. package/dist/{cloudflare-operations-DYa3coIk.mjs → cloudflare-operations-CwI1bChl.mjs} +41 -70
  30. package/dist/{cloudflare-process-B-wekeR6.mjs → cloudflare-process-2-TfIEzB.mjs} +20 -22
  31. package/dist/{config-CyQ-wVd7.mjs → config-5r-YpMC-.mjs} +1 -1
  32. package/dist/{config-C_XRIPx2.mjs → config-B_ggY-IO.mjs} +3 -3
  33. package/dist/config-BtSFvXZx.mjs +2 -0
  34. package/dist/config-CLYAosnQ.mjs +78 -0
  35. package/dist/{config-BMHb8RCj.d.mts → config-CSa15FvD.d.mts} +1 -1
  36. package/dist/{config-Br_JZD6u.mjs → config-DiowPT80.mjs} +24 -30
  37. package/dist/config-entry.d.mts +1 -1
  38. package/dist/{config-write-B1f88wJA.mjs → config-write-AHGesphx.mjs} +8 -7
  39. package/dist/{connect-H6EvP62X.mjs → connect-X0MUA1gk.mjs} +10 -9
  40. package/dist/{create-project-B2kk9Q0o.mjs → create-project-DxiyW6iX.mjs} +6 -6
  41. package/dist/{create-project-Dbb4uiN-.mjs → create-project-iwkbqiBU.mjs} +1 -1
  42. package/dist/{db-DpCKZto0.mjs → db-XnVMHzoV.mjs} +100 -132
  43. package/dist/{delete-CxlSvsvW.mjs → delete-esYlMiSJ.mjs} +6 -6
  44. package/dist/{deploy-CeEbnv4b.mjs → deploy-BsEvnlJl.mjs} +2346 -2495
  45. package/dist/deploy-C1d-YTfp.mjs +2 -0
  46. package/dist/{dev-inbox-D64ZKUod.mjs → dev-inbox-CK-UuPob.mjs} +7 -16
  47. package/dist/{discover-BcPPiF1o.mjs → discover-CkCYv9T_.mjs} +1 -2
  48. package/dist/discover-EDUf6JJw.mjs +2 -0
  49. package/dist/{prompts-ZAuJlyCj.mjs → dist-Bx1z6Eva.mjs} +1 -1
  50. package/dist/{dist-AoCzRTJE.mjs → dist-Cegxq8gs.mjs} +8 -8
  51. package/dist/{prompts-6OSVA7DJ.mjs → dist-D3m88sjf.mjs} +10 -53
  52. package/dist/{domain-B_9VgOm6.mjs → domain-CbbBWhWE.mjs} +28 -29
  53. package/dist/{dotenv-VQxupEUv.mjs → dotenv-BfU6eqFt.mjs} +20 -32
  54. package/dist/{drizzle-Beb2Am5S.mjs → drizzle-CF84FOVM.mjs} +16 -13
  55. package/dist/{email-BokHgjKj.mjs → email-CpuT42g7.mjs} +23 -18
  56. package/dist/{email--tEtMoj_.mjs → email-d_Aux1vM.mjs} +1 -1
  57. package/dist/{entry-CF5wvH4w.mjs → entry-CMAkqBmU.mjs} +6 -6
  58. package/dist/{env-_v349JBd.mjs → env-BxocywBB.mjs} +25 -6
  59. package/dist/{env-D5liuQYR.mjs → env-DMA3cXZt.mjs} +1 -1
  60. package/dist/{env-raw-Cx8ElDdj.mjs → env-raw-jZpP5n47.mjs} +1 -2
  61. package/dist/{env-types-D5kds_OZ.mjs → env-types-CwXgeMgL.mjs} +1 -1
  62. package/dist/{env-validation-cZBvGWaP.mjs → env-validation-CrVNjsPm.mjs} +1 -1
  63. package/dist/{env-validation-vBSQ8gw5.mjs → env-validation-Dxdx_5wo.mjs} +17 -21
  64. package/dist/{env-BdTc-K2L.mjs → env-w9jOyGZn.mjs} +9 -9
  65. package/dist/{fetch-_SeGZao9.d.mts → fetch-BPCYVi3H.d.mts} +20 -1
  66. package/dist/{fetch-BIZJh7vR.mjs → fetch-sAcwjzLO.mjs} +1 -1
  67. package/dist/{fetch-stream-Nm3hkZbT.mjs → fetch-stream-PGgz4uGz.mjs} +18 -23
  68. package/dist/{fetch-stream-Bjf0hoZb.d.mts → fetch-stream-obvZ7fvO.d.mts} +1 -16
  69. package/dist/{gen-BhDlTpwW.mjs → gen-DtkQhvQg.mjs} +40 -57
  70. package/dist/gen-dA9hW7AV.mjs +2 -0
  71. package/dist/{github-cmd-hhkTzlGS.mjs → github-cmd-D_FsOFxq.mjs} +64 -163
  72. package/dist/{handler-DghKr6dU.mjs → handler-BHAn2fZJ.mjs} +1 -0
  73. package/dist/{handler-BeK3weD4.d.mts → handler-CNAwjRcW.d.mts} +4 -11
  74. package/dist/{head-Do8P4puT.d.mts → head-C8K_iGe6.d.mts} +1 -1
  75. package/dist/{head-D_QRR5Yd.mjs → head-D2VF4ApL.mjs} +29 -51
  76. package/dist/{headers-2rKda9Y6.mjs → headers-DlfR78Nu.mjs} +3 -3
  77. package/dist/{help-Bv44e2tm.mjs → help-CVFBTmBx.mjs} +13 -32
  78. package/dist/help-DzKUrQvk.mjs +2 -0
  79. package/dist/{inbound-fRkqcXaC.mjs → inbound-PfQDLXc5.mjs} +23 -24
  80. package/dist/index.d.mts +19 -2
  81. package/dist/index.mjs +617 -530
  82. package/dist/{info-DhtTKh65.mjs → info-PYWwkWyt.mjs} +4 -4
  83. package/dist/{init-BMf4T03q.mjs → init-Bw-fRKGp.mjs} +160 -197
  84. package/dist/{link-BqYsSS_I.mjs → link-DlPG8iX3.mjs} +9 -9
  85. package/dist/{list-_kBToO-l.mjs → list-2GN7_ueV.mjs} +8 -7
  86. package/dist/{live-CB1y5IuC.mjs → live-CgQuTpqD.mjs} +15 -16
  87. package/dist/{live-iAuEH1hd.d.mts → live-Du8jXwOW.d.mts} +4 -2
  88. package/dist/{local-d1-fGxYrVD6.mjs → local-d1-ga5O_idV.mjs} +2 -2
  89. package/dist/{login-DFuo-RWO.mjs → login-D-Q4xw3Q.mjs} +7 -7
  90. package/dist/login-Dc-wuTDq.mjs +2 -0
  91. package/dist/{logs-DYgnh6dH.mjs → logs-rd8J-OFh.mjs} +27 -10
  92. package/dist/migrate-BHp07yJE.mjs +2 -0
  93. package/dist/{migrate-CV1on-yJ.mjs → migrate-NLsjBbuM.mjs} +34 -20
  94. package/dist/{mime-D5Nmdzf7.mjs → mime-DxCznlJq.mjs} +45 -95
  95. package/dist/{node-C6Q6e1Es.mjs → node-DJicPvPj.mjs} +5 -5
  96. package/dist/{operator-args-DdY54Bgb.mjs → operator-args-BNsW5gfp.mjs} +10 -1
  97. package/dist/{operator-auth-2dsGlTT5.mjs → operator-auth-AzVLbrr3.mjs} +1 -1
  98. package/dist/{operator-client-BFqpp6z0.mjs → operator-client-BQtzyG-g.mjs} +1 -1
  99. package/dist/{operator-cmd-CUGHXrQf.mjs → operator-cmd-B6f6Cg9Z.mjs} +24 -11
  100. package/dist/operator-cmd-Cwn50lOV.mjs +2 -0
  101. package/dist/{output-BvdaehtE.mjs → output-C50ag2r3.mjs} +20 -2
  102. package/dist/pages/client.d.mts +19 -51
  103. package/dist/pages/client.mjs +204 -225
  104. package/dist/pages/head-client.d.mts +1 -1
  105. package/dist/pages/head.d.mts +1 -1
  106. package/dist/pages/head.mjs +1 -1
  107. package/dist/pages/index.d.mts +2 -2
  108. package/dist/pages/index.mjs +6 -12
  109. package/dist/pages/islands-plugin.d.mts +1 -1
  110. package/dist/pages/islands-plugin.mjs +21 -25
  111. package/dist/pages/protocol.d.mts +2 -2
  112. package/dist/pages/protocol.mjs +2 -2
  113. package/dist/{plan-CJGEeTEI.mjs → plan-BhLO2p4w.mjs} +2 -1
  114. package/dist/plan-CH2G51je.mjs +2 -0
  115. package/dist/{platform-args-DSV2p4nY.mjs → platform-args-BoZkWQnJ.mjs} +1 -1
  116. package/dist/platform-args-DYgITk0D.mjs +2 -0
  117. package/dist/{platform-auth-config-Bosx7U1h.mjs → platform-auth-config-n603OANg.mjs} +40 -36
  118. package/dist/{platform-auth-protection-DcbL_LW_.mjs → platform-auth-protection-zxDr0hWW.mjs} +8 -7
  119. package/dist/{platform-auth-recovery-WfTZ8K6o.mjs → platform-auth-recovery-tw9lgtgE.mjs} +7 -6
  120. package/dist/{platform-cmd-DbKtQb_4.mjs → platform-cmd-B8-bCb7t.mjs} +10 -10
  121. package/dist/{platform-cmd-dyFUof0t.mjs → platform-cmd-C00YM14r.mjs} +1 -1
  122. package/dist/{platform-domain-Bsq43AJp.mjs → platform-domain-p0kobLV8.mjs} +5 -5
  123. package/dist/{platform-lifecycle-Cfi0o6xM.mjs → platform-lifecycle-D_QEY32D.mjs} +75 -386
  124. package/dist/{platform-lifecycle--5gWmDoI.mjs → platform-lifecycle-vFqtNPPa.mjs} +1 -1
  125. package/dist/{platform-management-BrF9STZp.mjs → platform-management-BdYblvvE.mjs} +6 -6
  126. package/dist/{platform-management-Bbwf6-Dq.mjs → platform-management-oi-SvI3f.mjs} +1 -1
  127. package/dist/{platform-plans-config-DU-8nC2Y.mjs → platform-plans-config-CjiFv5J4.mjs} +5 -4
  128. package/dist/{platform-recovery-DQAqAQYu.mjs → platform-recovery-PvNS9Nl2.mjs} +2 -2
  129. package/dist/platform-setup-DVe42Ws7.mjs +299 -0
  130. package/dist/{plugin-inference-CXWnn79A.mjs → plugin-inference-BlQbOL0P.mjs} +43 -42
  131. package/dist/prepare-DRUV-g3X.mjs +2 -0
  132. package/dist/{prepare-WoUubFKL.mjs → prepare-Do96654b.mjs} +8 -8
  133. package/dist/{prepare-BMrRWLwP.mjs → prepare-Dq9hTIbo.mjs} +4 -4
  134. package/dist/{prerender-render-D9qbLs2f.mjs → prerender-render-Ct20jftc.mjs} +17 -3
  135. package/dist/prerender-render.mjs +1 -1
  136. package/dist/{project-cmd-BbH2LptN.mjs → project-cmd-ti8_yTcA.mjs} +18 -18
  137. package/dist/{project-team-Yiww3-go.mjs → project-team-CDPE1Tsg.mjs} +14 -17
  138. package/dist/{project-token-BrtT2NkY.mjs → project-token-CkZ1cN0Z.mjs} +13 -16
  139. package/dist/{project-tsconfig-B8GeM0RM.mjs → project-tsconfig-CVJhNMxs.mjs} +2 -1
  140. package/dist/{project-zero-trust-nYJ2V2nc.mjs → project-zero-trust-DdjLR61k.mjs} +11 -8
  141. package/dist/{protocol-BX8t2jiw.d.mts → protocol-BPZaNqBo.d.mts} +4 -2
  142. package/dist/{protocol-U7bfjHmA.mjs → protocol-CfaUwNs8.mjs} +46 -49
  143. package/dist/{providers-CJlNS3kT.mjs → providers-BXuhmuub.mjs} +1 -12
  144. package/dist/{provision-VeqAC77A.mjs → provision-BfaLiWbj.mjs} +38 -41
  145. package/dist/{provision-DMTPG8Rh.mjs → provision-Wu9ZBk9L.mjs} +2 -3
  146. package/dist/{requests-TIz_jtSu.mjs → requests-DFAqyYy8.mjs} +4 -4
  147. package/dist/resolve-project-BIeYs9Cw.mjs +2 -0
  148. package/dist/{resolve-project-BG5ORGID.mjs → resolve-project-CP8rZs_p.mjs} +6 -1
  149. package/dist/{rollback-dBqICPzj.mjs → rollback-BKYXBduI.mjs} +29 -36
  150. package/dist/{route-types-Clm4WD0B.mjs → route-types-CbtsIeFn.mjs} +1 -1
  151. package/dist/route-url-BgPja1GS.d.mts +5 -0
  152. package/dist/route-url-BjGv_KKY.mjs +28 -0
  153. package/dist/runner-9wjsSZx-.mjs +2 -0
  154. package/dist/{runner--2KF6Kua.mjs → runner-DMBKSrRk.mjs} +2 -2
  155. package/dist/{runner-mysql-DmWchSWJ.mjs → runner-mysql-CEzKtmFb.mjs} +8 -8
  156. package/dist/{runner-mysql-CEG5JozK.mjs → runner-mysql-CkFqZ6CE.mjs} +1 -1
  157. package/dist/{runner-pg-Bh4AgZdj.mjs → runner-pg-BGYRFdRp.mjs} +1 -1
  158. package/dist/runtime/ai.d.mts +1 -1
  159. package/dist/runtime/ai.mjs +34 -95
  160. package/dist/runtime/better-auth-mysql.d.mts +1 -1
  161. package/dist/runtime/better-auth-mysql.mjs +4 -9
  162. package/dist/runtime/better-auth-pg.d.mts +1 -1
  163. package/dist/runtime/better-auth-pg.mjs +5 -10
  164. package/dist/runtime/better-auth.d.mts +1 -1
  165. package/dist/runtime/better-auth.mjs +3 -3
  166. package/dist/runtime/client-react.d.mts +2 -3
  167. package/dist/runtime/client-react.mjs +2 -2
  168. package/dist/runtime/client-solid.d.mts +2 -3
  169. package/dist/runtime/client-solid.mjs +2 -2
  170. package/dist/runtime/client-svelte.d.mts +2 -3
  171. package/dist/runtime/client-svelte.mjs +2 -2
  172. package/dist/runtime/client-vue.d.mts +2 -3
  173. package/dist/runtime/client-vue.mjs +2 -2
  174. package/dist/runtime/client.d.mts +2 -3
  175. package/dist/runtime/client.mjs +2 -2
  176. package/dist/runtime/db.mjs +1 -1
  177. package/dist/runtime/durable.mjs +3 -10
  178. package/dist/runtime/email/testing.mjs +5 -5
  179. package/dist/runtime/email.d.mts +2 -1
  180. package/dist/runtime/email.mjs +11 -27
  181. package/dist/runtime/env-public.mjs +15 -20
  182. package/dist/runtime/env.mjs +1 -1
  183. package/dist/runtime/fetch-stream.d.mts +2 -2
  184. package/dist/runtime/fetch-stream.mjs +1 -1
  185. package/dist/runtime/fetch.d.mts +2 -3
  186. package/dist/runtime/fetch.mjs +1 -1
  187. package/dist/runtime/handler.d.mts +1 -1
  188. package/dist/runtime/handler.mjs +2 -2
  189. package/dist/runtime/isr.mjs +1 -1
  190. package/dist/runtime/kv.mjs +10 -11
  191. package/dist/runtime/live-client.d.mts +1 -1
  192. package/dist/runtime/live-client.mjs +12 -22
  193. package/dist/runtime/live-server.mjs +27 -35
  194. package/dist/runtime/live.d.mts +2 -2
  195. package/dist/runtime/live.mjs +2 -2
  196. package/dist/runtime/migration-handler.mjs +4 -81
  197. package/dist/runtime/queues.mjs +1 -1
  198. package/dist/runtime/remote/binding-handler.d.mts +2 -2
  199. package/dist/runtime/remote/binding-handler.mjs +8 -9
  200. package/dist/runtime/remote/index.mjs +27 -77
  201. package/dist/runtime/route-url.d.mts +2 -4
  202. package/dist/runtime/route-url.mjs +1 -1
  203. package/dist/runtime/routing.d.mts +1 -1
  204. package/dist/runtime/routing.mjs +15 -26
  205. package/dist/runtime/sandbox.mjs +2 -2
  206. package/dist/runtime/sse.mjs +1 -1
  207. package/dist/runtime/storage.mjs +1 -1
  208. package/dist/runtime/validator.d.mts +1 -1
  209. package/dist/runtime/ws-server.d.mts +2 -2
  210. package/dist/runtime/ws-server.mjs +30 -61
  211. package/dist/runtime/ws.d.mts +1 -1
  212. package/dist/runtime/ws.mjs +1 -1
  213. package/dist/{scan-C8dA7iM4.mjs → scan-C3uDzz6J.mjs} +12 -13
  214. package/dist/{secret-AKnNXNP5.mjs → secret-BAt2KMmO.mjs} +14 -14
  215. package/dist/{skills-BPQUGClu.mjs → skills-BgVMvQdy.mjs} +2 -2
  216. package/dist/{sse-CQNaDFFV.mjs → sse-CMvCgjNk.mjs} +1 -1
  217. package/dist/{subcommand-prompt-B6WS9Aoz.mjs → subcommand-prompt-BSlnD1fI.mjs} +2 -2
  218. package/dist/sveltekit.d.mts +0 -2
  219. package/dist/terminal-log-text-D9ACPOuG.mjs +32 -0
  220. package/dist/validate-BJr9LfXy.mjs +2 -0
  221. package/dist/{validate-ymhap6M_.mjs → validate-C9qJArv7.mjs} +9 -28
  222. package/dist/{defer-YsYDUoii.mjs → validation-error-Dg9Recn1.mjs} +11 -11
  223. package/dist/{wrangler-DhUerFkW.mjs → wrangler-D9KTuqnv.mjs} +89 -194
  224. package/dist/{ws-C79j4aED.d.mts → ws-CChrrAU-.d.mts} +1 -1
  225. package/dist/{yarn-pnp-BV4AzNul.mjs → yarn-pnp-CUX_iTPA.mjs} +19 -27
  226. package/{skills/void/docs → docs}/guide/ai.md +5 -3
  227. package/{skills/void/docs → docs}/guide/auth.md +37 -1
  228. package/{skills/void/docs → docs}/guide/database/postgresql.md +2 -2
  229. package/{skills/void/docs → docs}/guide/edge/revalidation.md +1 -1
  230. package/{skills/void/docs → docs}/guide/edge/rewrites.md +2 -4
  231. package/{skills/void/docs → docs}/guide/email/receiving.md +2 -2
  232. package/{skills/void/docs → docs}/guide/email/sending.md +0 -2
  233. package/{skills/void/docs → docs}/guide/env-vars.md +4 -0
  234. package/{skills/void/docs → docs}/guide/jobs.md +2 -2
  235. package/{skills/void/docs → docs}/guide/live.md +10 -5
  236. package/{skills/void/docs → docs}/guide/pages-routing/actions-and-forms.md +20 -8
  237. package/{skills/void/docs → docs}/guide/pages-routing/loaders.md +7 -3
  238. package/{skills/void/docs → docs}/guide/pages-routing/markdown.md +15 -23
  239. package/{skills/void/docs → docs}/guide/pages-routing/overview.md +6 -4
  240. package/{skills/void/docs → docs}/guide/platform/administration/access.md +2 -10
  241. package/{skills/void/docs → docs}/guide/platform/administration/operations.md +3 -12
  242. package/{skills/void/docs → docs}/guide/platform/administration/projects.md +1 -1
  243. package/{skills/void/docs → docs}/guide/platform/development/local.md +4 -2
  244. package/{skills/void/docs → docs}/guide/platform/development/runtime.md +1 -1
  245. package/{skills/void/docs → docs}/guide/platform/development/schema-ci.md +1 -1
  246. package/{skills/void/docs → docs}/guide/platform/installation/domains.md +3 -1
  247. package/{skills/void/docs → docs}/guide/platform/installation/first-deployment.md +3 -1
  248. package/{skills/void/docs → docs}/guide/platform/installation/maintenance.md +4 -0
  249. package/{skills/void/docs → docs}/guide/project-collaboration.md +6 -2
  250. package/{skills/void/docs → docs}/guide/queues.md +0 -2
  251. package/{skills/void/docs → docs}/guide/remote-dev.md +5 -5
  252. package/{skills/void/docs → docs}/guide/sandboxes.md +2 -2
  253. package/{skills/void/docs → docs}/guide/sse.md +0 -2
  254. package/{skills/void/docs → docs}/guide/storage.md +7 -2
  255. package/{skills/void/docs → docs}/guide/websockets.md +4 -0
  256. package/docs/integrations/agents.md +37 -0
  257. package/{skills/void/docs → docs}/integrations/frameworks/astro.md +3 -3
  258. package/{skills/void/docs → docs}/integrations/frameworks/nuxt.md +6 -2
  259. package/{skills/void/docs → docs}/integrations/hono.md +15 -7
  260. package/{skills/void/docs → docs}/integrations/nodejs-bun-deno.md +1 -0
  261. package/{skills/void/docs → docs}/reference/api/auth.md +1 -1
  262. package/{skills/void/docs → docs}/reference/api/handlers.md +4 -2
  263. package/{skills/void/docs → docs}/reference/api/pages.md +4 -0
  264. package/{skills/void/docs → docs}/reference/cli/auth.md +0 -5
  265. package/{skills/void/docs → docs}/reference/cli/database.md +3 -4
  266. package/{skills/void/docs → docs}/reference/cli/generate.md +1 -1
  267. package/{skills/void/docs → docs}/reference/cli/github.md +3 -12
  268. package/{skills/void/docs → docs}/reference/cli/platform-config.md +1 -1
  269. package/{skills/void/docs → docs}/reference/cli/platform-email.md +2 -3
  270. package/{skills/void/docs → docs}/reference/cli/platform-installation.md +1 -1
  271. package/{skills/void/docs → docs}/reference/cli/platform-operations.md +3 -0
  272. package/{skills/void/docs → docs}/reference/cli/platform-users.md +2 -2
  273. package/{skills/void/docs → docs}/reference/cli/project.md +5 -4
  274. package/{skills/void/docs → docs}/reference/cli/secrets.md +3 -3
  275. package/{skills/void/docs → docs}/reference/cli/setup.md +9 -11
  276. package/{skills/void/docs → docs}/reference/cli.md +1 -1
  277. package/{skills/void/docs → docs}/reference/config.md +13 -13
  278. package/{skills/void/docs → docs}/reference/resource-inference.md +1 -16
  279. package/package.json +34 -30
  280. package/schema.json +1 -1
  281. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +4 -1
  282. package/skills/void/SKILL.md +6 -3
  283. package/dist/cf-build-output-ChY6-XWP.mjs +0 -2
  284. package/dist/client-BxVixJBI.mjs +0 -2
  285. package/dist/config-0acf1oys.mjs +0 -2
  286. package/dist/config-D8MOgiQV.mjs +0 -32
  287. package/dist/deploy-qmiLE1G1.mjs +0 -2
  288. package/dist/discover-AMCBXivQ.mjs +0 -2
  289. package/dist/fetch-error-Sp1R4mZv.d.mts +0 -20
  290. package/dist/gen-qCBwH3fZ.mjs +0 -2
  291. package/dist/help-Dw5f9Xrg.mjs +0 -2
  292. package/dist/login-D7meQg_3.mjs +0 -2
  293. package/dist/migrate-CEu2X5DB.mjs +0 -2
  294. package/dist/operator-cmd-DRPvhpjM.mjs +0 -2
  295. package/dist/plan-COtUvdMA.mjs +0 -2
  296. package/dist/platform-args-Dcy_5b_Y.mjs +0 -2
  297. package/dist/prepare-BBknoZI1.mjs +0 -2
  298. package/dist/resolve-project-DtbidV4y.mjs +0 -2
  299. package/dist/route-url-CG7U-cRN.mjs +0 -15
  300. package/dist/runner-voIltZrY.mjs +0 -2
  301. package/dist/validate-pna7R3Pv.mjs +0 -2
  302. package/skills/void/docs/integrations/agents.md +0 -26
  303. package/dist/{runner-pg-D4OPlil-.mjs → runner-pg-DV8p_zjA.mjs} +4 -4
  304. package/{skills/void/docs → docs}/guide/app-types.md +0 -0
  305. package/{skills/void/docs → docs}/guide/database/d1.md +2 -2
  306. package/{skills/void/docs → docs}/guide/database/mysql.md +0 -0
  307. package/{skills/void/docs → docs}/guide/database.md +8 -8
  308. package/{skills/void/docs → docs}/guide/deployment.md +0 -0
  309. package/{skills/void/docs → docs}/guide/durable-state.md +0 -0
  310. package/{skills/void/docs → docs}/guide/edge/headers.md +0 -0
  311. package/{skills/void/docs → docs}/guide/edge/prerendering.md +0 -0
  312. package/{skills/void/docs → docs}/guide/edge/redirects.md +0 -0
  313. package/{skills/void/docs → docs}/guide/edge/static-assets.md +0 -0
  314. package/{skills/void/docs → docs}/guide/email/domains.md +0 -0
  315. package/{skills/void/docs → docs}/guide/email.md +0 -0
  316. package/{skills/void/docs → docs}/guide/index.md +0 -0
  317. package/{skills/void/docs → docs}/guide/kv.md +0 -0
  318. package/{skills/void/docs → docs}/guide/pages-routing/head.md +0 -0
  319. package/{skills/void/docs → docs}/guide/pages-routing/islands.md +2 -2
  320. package/{skills/void/docs → docs}/guide/pages-routing/layouts.md +0 -0
  321. package/{skills/void/docs → docs}/guide/pages-routing/view-transitions.md +0 -0
  322. package/{skills/void/docs → docs}/guide/platform/administration/email.md +0 -0
  323. package/{skills/void/docs → docs}/guide/platform/administration/plans.md +0 -0
  324. package/{skills/void/docs → docs}/guide/platform/administration/zero-trust.md +0 -0
  325. package/{skills/void/docs → docs}/guide/platform/installation/ci.md +0 -0
  326. package/{skills/void/docs → docs}/guide/platform/installation/credentials.md +0 -0
  327. package/{skills/void/docs → docs}/guide/platform/installation/prerequisites.md +0 -0
  328. package/{skills/void/docs → docs}/guide/platform/installation/setup.md +0 -0
  329. package/{skills/void/docs → docs}/guide/platform/installation/uninstall.md +0 -0
  330. package/{skills/void/docs → docs}/guide/platform-administration.md +0 -0
  331. package/{skills/void/docs → docs}/guide/platform-development.md +0 -0
  332. package/{skills/void/docs → docs}/guide/quickstart.md +0 -0
  333. package/{skills/void/docs → docs}/guide/self-hosted-platform.md +0 -0
  334. package/{skills/void/docs → docs}/guide/server-routing.md +3 -3
  335. package/{skills/void/docs → docs}/guide/ssg.md +0 -0
  336. package/{skills/void/docs → docs}/guide/ssr.md +0 -0
  337. package/{skills/void/docs → docs}/guide/type-safety.md +0 -0
  338. package/{skills/void/docs → docs}/guide/typed-fetch.md +0 -0
  339. package/{skills/void/docs → docs}/index.md +0 -0
  340. package/{skills/void/docs → docs}/integrations/cloudflare.md +0 -0
  341. package/{skills/void/docs → docs}/integrations/frameworks/analog.md +3 -3
  342. package/{skills/void/docs → docs}/integrations/frameworks/overview.md +0 -0
  343. package/{skills/void/docs → docs}/integrations/frameworks/react-router.md +3 -3
  344. package/{skills/void/docs → docs}/integrations/frameworks/sveltekit.md +1 -1
  345. package/{skills/void/docs → docs}/integrations/frameworks/tanstack-start.md +2 -2
  346. package/{skills/void/docs → docs}/reference/api/client.md +0 -0
  347. package/{skills/void/docs → docs}/reference/api/database.md +2 -2
  348. /package/{skills/void/docs → docs}/reference/api/durable.md +0 -0
  349. /package/{skills/void/docs → docs}/reference/api/env.md +0 -0
  350. /package/{skills/void/docs → docs}/reference/api/plugin.md +0 -0
  351. /package/{skills/void/docs → docs}/reference/api/resources.md +0 -0
  352. /package/{skills/void/docs → docs}/reference/api/rewrites.md +0 -0
  353. /package/{skills/void/docs → docs}/reference/api/types.md +0 -0
  354. /package/{skills/void/docs → docs}/reference/api.md +0 -0
  355. /package/{skills/void/docs → docs}/reference/cli/deploy.md +0 -0
  356. /package/{skills/void/docs → docs}/reference/cli/domains.md +0 -0
  357. /package/{skills/void/docs → docs}/reference/cli/email.md +0 -0
  358. /package/{skills/void/docs → docs}/reference/cli/platform-zero-trust.md +0 -0
  359. /package/{skills/void/docs → docs}/reference/cli/platform.md +0 -0
  360. /package/{skills/void/docs → docs}/reference/structure.md +0 -0
@@ -1,8 +1,8 @@
1
1
  import { a as join, n as dirname, o as normalize, t as basename } from "./dist-BVqXeR_h.mjs";
2
2
  import "./project-paths-GgcMozYz.mjs";
3
- import { m as readConfig } from "./config-Br_JZD6u.mjs";
4
- import { a as hasSandboxSqliteMigration, c as resolveSandboxConfig, i as assertSandboxNamespaceConfig, l as sandboxContainerConfig, r as SANDBOX_MIGRATION_TAG } from "./config-C_XRIPx2.mjs";
5
- import { i as persistCloudflareConfig, r as materializeCloudflareConfig } from "./cloudflare-config-Bktvwtpf.mjs";
3
+ import { m as readConfig } from "./config-DiowPT80.mjs";
4
+ import { a as hasSandboxSqliteMigration, c as resolveSandboxConfig, i as assertSandboxNamespaceConfig, l as sandboxContainerConfig, r as SANDBOX_MIGRATION_TAG } from "./config-B_ggY-IO.mjs";
5
+ import { i as persistCloudflareConfig, r as materializeCloudflareConfig } from "./cloudflare-config-BmhBv3HV.mjs";
6
6
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
7
7
  import { appendSqliteClassMigration, isRecord } from "@void/deploy-core";
8
8
  import { createHash } from "node:crypto";
@@ -18,9 +18,39 @@ function projectWranglerPaths(root) {
18
18
  if (existsSync(join(root, "void.config.ts"))) return [materializeCloudflareConfig(root)];
19
19
  return ["wrangler.jsonc", "wrangler.json"].map((name) => join(root, name));
20
20
  }
21
+ /** Record a change to the generated Cloudflare config in `void.lock.json`. */
22
+ function persistMaterializedWranglerConfig(configPath) {
23
+ if (basename(configPath) === ".void-wrangler.jsonc") persistCloudflareConfig(dirname(configPath));
24
+ }
21
25
  function writeProjectWranglerFile(configPath, text) {
22
26
  writeFileSync(configPath, text);
23
- if (basename(configPath) === ".void-wrangler.jsonc") persistCloudflareConfig(dirname(configPath));
27
+ persistMaterializedWranglerConfig(configPath);
28
+ }
29
+ /**
30
+ * Read the first existing project Wrangler config. A missing or unparseable one is
31
+ * replaced by the generated config, starting from an empty object.
32
+ */
33
+ function readOrCreateProjectWranglerConfig(root) {
34
+ const configPath = projectWranglerPaths(root).find((path) => existsSync(path));
35
+ if (configPath) {
36
+ let parsed;
37
+ try {
38
+ parsed = parseJsonc(readFileSync(configPath, "utf-8"));
39
+ } catch {}
40
+ if (parsed) return {
41
+ configPath,
42
+ parsed,
43
+ created: false
44
+ };
45
+ }
46
+ return {
47
+ configPath: materializeCloudflareConfig(root),
48
+ parsed: {},
49
+ created: true
50
+ };
51
+ }
52
+ function durableObjectBindingsOf(config) {
53
+ return config.durable_objects?.bindings ?? [];
24
54
  }
25
55
  const MANAGED_QUEUES_MARKER = /^\s*\/\/ void:managed-queues:v1:([A-Za-z0-9_-]+)\s*$/m;
26
56
  const PUBLISHED_TRAFFIC_MARKER = /^\s*\/\/ void:published-traffic:v1:([A-Za-z0-9_-]+)\s*$/m;
@@ -241,21 +271,7 @@ function ensureVoidCompatibilityDate(root, config) {
241
271
  * Returns true if the file was modified.
242
272
  */
243
273
  function syncWranglerBindings(root, bindings, options) {
244
- let configPath;
245
- let parsed;
246
- let created = false;
247
- for (const p of projectWranglerPaths(root)) if (existsSync(p)) {
248
- configPath = p;
249
- try {
250
- parsed = parseJsonc(readFileSync(p, "utf-8"));
251
- } catch {}
252
- break;
253
- }
254
- if (!configPath || !parsed) {
255
- configPath = materializeCloudflareConfig(root);
256
- parsed = {};
257
- created = true;
258
- }
274
+ const { configPath, parsed, created } = readOrCreateProjectWranglerConfig(root);
259
275
  let modified = false;
260
276
  const d1Name = options?.bindingNames?.d1 ?? "DB";
261
277
  if (bindings.needsD1) {
@@ -317,18 +333,17 @@ function syncWranglerBindings(root, bindings, options) {
317
333
  }
318
334
  }
319
335
  if (options?.websockets) {
320
- const existing = parsed.durable_objects?.bindings ?? [];
336
+ const existing = durableObjectBindingsOf(parsed);
321
337
  const migrations = Array.isArray(parsed.migrations) ? parsed.migrations : [];
322
- const retained = existing;
323
338
  for (const route of options.websockets) {
324
- const conflict = retained.find((binding) => binding.name === route.bindingName && binding.class_name !== route.className);
339
+ const conflict = existing.find((binding) => binding.name === route.bindingName && binding.class_name !== route.className);
325
340
  if (conflict) throw new Error(`websocket: binding '${route.bindingName}' is already configured for class '${conflict.class_name}', but '${route.filePath}' requires '${route.className}'.`);
326
341
  }
327
- const additions = options.websockets.filter((route) => !retained.some((binding) => binding.name === route.bindingName)).map((route) => ({
342
+ const additions = options.websockets.filter((route) => !existing.some((binding) => binding.name === route.bindingName)).map((route) => ({
328
343
  name: route.bindingName,
329
344
  class_name: route.className
330
345
  }));
331
- const nextBindings = [...retained, ...additions];
346
+ const nextBindings = [...existing, ...additions];
332
347
  if (nextBindings.length !== existing.length || nextBindings.some((binding, index) => binding.name !== existing[index]?.name || binding.class_name !== existing[index]?.class_name)) {
333
348
  parsed.durable_objects = {
334
349
  ...parsed.durable_objects ?? {},
@@ -336,14 +351,14 @@ function syncWranglerBindings(root, bindings, options) {
336
351
  };
337
352
  modified = true;
338
353
  }
339
- const planned = appendSqliteClassMigration(migrations, options.websockets.map((route) => route.className), "void-ws-v1", retained.map((binding) => binding.class_name));
354
+ const planned = appendSqliteClassMigration(migrations, options.websockets.map((route) => route.className), "void-ws-v1", existing.map((binding) => binding.class_name));
340
355
  if (planned.added) {
341
356
  parsed.migrations = planned.migrations;
342
357
  modified = true;
343
358
  }
344
359
  }
345
360
  if (options?.durableObjects && options.durableObjects.length > 0) {
346
- const existingBindings = parsed.durable_objects?.bindings ?? [];
361
+ const existingBindings = durableObjectBindingsOf(parsed);
347
362
  for (const module of options.durableObjects) {
348
363
  const conflict = existingBindings.find((binding) => binding.name === module.bindingName && binding.class_name !== module.className);
349
364
  if (conflict) throw new Error(`durable: binding '${module.bindingName}' is already configured for class '${conflict.class_name}', but durable-objects/ requires '${module.className}'.`);
@@ -374,7 +389,7 @@ function syncWranglerBindings(root, bindings, options) {
374
389
  const bindingName = options?.bindingNames?.sandbox ?? sandbox?.binding ?? "SANDBOX";
375
390
  const className = sandbox.className;
376
391
  assertSandboxNamespaceConfig(parsed, sandbox);
377
- const existingDurableObjectBindings = parsed.durable_objects?.bindings ?? [];
392
+ const existingDurableObjectBindings = durableObjectBindingsOf(parsed);
378
393
  if (!existingDurableObjectBindings.some((binding) => binding.name === bindingName)) {
379
394
  parsed.durable_objects = { bindings: [...existingDurableObjectBindings, {
380
395
  name: bindingName,
@@ -398,7 +413,7 @@ function syncWranglerBindings(root, bindings, options) {
398
413
  }
399
414
  }
400
415
  if (bindings.needsLive || options?.live) {
401
- const existingDurableObjectBindings = parsed.durable_objects?.bindings ?? [];
416
+ const existingDurableObjectBindings = durableObjectBindingsOf(parsed);
402
417
  const liveConfig = typeof options?.live === "object" ? options.live : resolveLiveBindingConfig(root, {
403
418
  existingBindings: existingDurableObjectBindings,
404
419
  reservedBindings: options?.websockets?.map((route) => route.bindingName),
@@ -466,19 +481,7 @@ function readWranglerWebSocketTombstones(root, websockets) {
466
481
  */
467
482
  function ensureWranglerCompatibilityDate(root, compatibilityDate) {
468
483
  validateCompatDate(compatibilityDate, "void.json worker config");
469
- let configPath;
470
- let parsed;
471
- for (const p of projectWranglerPaths(root)) if (existsSync(p)) {
472
- configPath = p;
473
- try {
474
- parsed = parseJsonc(readFileSync(p, "utf-8"));
475
- } catch {}
476
- break;
477
- }
478
- if (!configPath || !parsed) {
479
- configPath = materializeCloudflareConfig(root);
480
- parsed = {};
481
- }
484
+ const { configPath, parsed } = readOrCreateProjectWranglerConfig(root);
482
485
  if (parsed.compatibility_date === compatibilityDate) return false;
483
486
  parsed.compatibility_date = compatibilityDate;
484
487
  writeProjectWranglerFile(configPath, JSON.stringify(parsed, null, 2) + "\n");
@@ -489,19 +492,7 @@ function ensureWranglerCompatibilityDate(root, compatibilityDate) {
489
492
  * Returns true if the config file was modified.
490
493
  */
491
494
  function ensureWranglerNodejsAlsFlag(root) {
492
- let configPath;
493
- let parsed;
494
- for (const p of projectWranglerPaths(root)) if (existsSync(p)) {
495
- configPath = p;
496
- try {
497
- parsed = parseJsonc(readFileSync(p, "utf-8"));
498
- } catch {}
499
- break;
500
- }
501
- if (!configPath || !parsed) {
502
- configPath = materializeCloudflareConfig(root);
503
- parsed = {};
504
- }
495
+ const { configPath, parsed } = readOrCreateProjectWranglerConfig(root);
505
496
  const compatibilityFlags = Array.isArray(parsed.compatibility_flags) ? parsed.compatibility_flags : [];
506
497
  if (compatibilityFlags.includes(NODEJS_ALS_FLAG)) return false;
507
498
  parsed.compatibility_flags = [...compatibilityFlags, NODEJS_ALS_FLAG];
@@ -509,30 +500,24 @@ function ensureWranglerNodejsAlsFlag(root) {
509
500
  return true;
510
501
  }
511
502
  function readManagedQueueProvenance(text) {
512
- const encoded = MANAGED_QUEUES_MARKER.exec(text)?.[1];
513
- if (!encoded) return {
503
+ const none = {
514
504
  producerBindings: [],
515
505
  consumerQueues: [],
516
506
  pendingConsumerRemovals: []
517
507
  };
508
+ const encoded = MANAGED_QUEUES_MARKER.exec(text)?.[1];
509
+ if (!encoded) return none;
510
+ const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
518
511
  try {
519
512
  const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
520
- if (!isRecord(parsed)) return {
521
- producerBindings: [],
522
- consumerQueues: [],
523
- pendingConsumerRemovals: []
524
- };
513
+ if (!isRecord(parsed)) return none;
525
514
  return {
526
- producerBindings: Array.isArray(parsed.producerBindings) ? parsed.producerBindings.filter((value) => typeof value === "string") : [],
527
- consumerQueues: Array.isArray(parsed.consumerQueues) ? parsed.consumerQueues.filter((value) => typeof value === "string") : [],
528
- pendingConsumerRemovals: Array.isArray(parsed.pendingConsumerRemovals) ? parsed.pendingConsumerRemovals.filter((value) => typeof value === "string") : []
515
+ producerBindings: strings(parsed.producerBindings),
516
+ consumerQueues: strings(parsed.consumerQueues),
517
+ pendingConsumerRemovals: strings(parsed.pendingConsumerRemovals)
529
518
  };
530
519
  } catch {
531
- return {
532
- producerBindings: [],
533
- consumerQueues: [],
534
- pendingConsumerRemovals: []
535
- };
520
+ return none;
536
521
  }
537
522
  }
538
523
  function writeManagedQueueProvenance(text, provenance) {
@@ -592,14 +577,7 @@ function acknowledgeWranglerManagedQueueRemovals(configPath, removedQueues) {
592
577
  * idempotent upsert — running twice produces byte-identical output.
593
578
  */
594
579
  function writeProvisionedWranglerConfig(root, patch, options) {
595
- let configPath = options?.configPath;
596
- if (configPath === void 0) {
597
- for (const p of projectWranglerPaths(root)) if (existsSync(p)) {
598
- configPath = p;
599
- break;
600
- }
601
- configPath ??= materializeCloudflareConfig(root);
602
- }
580
+ const configPath = options?.configPath ?? discoverWranglerConfigPath(root);
603
581
  const rawContent = existsSync(configPath) ? readFileSync(configPath, "utf-8") : "{}";
604
582
  const hasBom = rawContent.startsWith(UTF8_BOM);
605
583
  const original = hasBom ? rawContent.slice(1) : rawContent;
@@ -1427,7 +1405,7 @@ function findBindingNameOwner(config, field, name) {
1427
1405
  * 2. MORE THAN ONE entry in the target field sharing `binding` (ambiguous identity —
1428
1406
  * wrangler also rejects duplicate binding names);
1429
1407
  * 3. a worker-wide CROSS-TYPE collision — `binding` is ALSO owned by any OTHER binding
1430
- * type (reuses the {@link collectWorkerBindingNames} Task-3 collector, EXCLUDING the
1408
+ * type (reuses the {@link collectWorkerBindingNames} collector, EXCLUDING the
1431
1409
  * target field so the entry never self-collides, and INCLUDING `queues.producers`).
1432
1410
  * Returns the single matching entry, or `undefined` when the binding is absent.
1433
1411
  */
@@ -1513,15 +1491,8 @@ const BINDING_FIELD_SHAPES = {
1513
1491
  * `ratelimits` name-keying and `logfwdr`'s nested `.bindings`, among others).
1514
1492
  */
1515
1493
  function bindingNamesForField(field, value) {
1516
- const shape = BINDING_FIELD_SHAPES[field] ?? { kind: "namespace-array" };
1517
- switch (shape.kind) {
1518
- case "key-map": return keyMapBindingNames(field, value);
1519
- case "name-keyed-array": return nameKeyedBindingNames(field, value);
1520
- case "namespace-array": return namespaceArrayBindingNames(field, value);
1521
- case "singleton": return singletonBindingName(field, value, shape.bindingRequired);
1522
- case "binding-list": return bindingListNames(field, value, shape.bindingsRequired);
1523
- case "whole-object": return [];
1524
- }
1494
+ if (BINDING_FIELD_SHAPES[field]?.kind === "key-map") return keyMapBindingNames(field, value);
1495
+ return bindingEntriesForField(field, value).map((entry) => entry.name);
1525
1496
  }
1526
1497
  /**
1527
1498
  * The entry-shaped sibling of {@link bindingNamesForField}: routes each field to its KNOWN
@@ -1529,8 +1500,8 @@ function bindingNamesForField(field, value) {
1529
1500
  * caller can compare not just WHICH bindings a field declares but the TARGET each one points
1530
1501
  * at (a `services` binding's `service`, an `unsafe` binding's `type`, …). Same fail-closed
1531
1502
  * philosophy as {@link bindingNamesForField} — a malformed/missing REQUIRED identity or wrong
1532
- * outer shape THROWS. By construction `bindingEntriesForField(f, v).map((e) => e.name)` equals
1533
- * `bindingNamesForField(f, v)` for every field (both read identity through the same shapes).
1503
+ * outer shape THROWS. {@link bindingNamesForField} is this reader's `.name` projection for every
1504
+ * non-key-map field.
1534
1505
  *
1535
1506
  * Exported so the deploy orchestrator's pass-through assert-set check can pin a legitimately
1536
1507
  * hand-declared binding's ENTRY pre-build and reject a build that KEEPS the name but REWRITES
@@ -1559,9 +1530,10 @@ function keyMapBindingEntries(field) {
1559
1530
  throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" must be an object mapping names to values. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1560
1531
  }
1561
1532
  /**
1562
- * Entry-shaped reader for a NAMESPACE-array field (mirror of {@link namespaceArrayBindingNames}):
1563
- * a PRESENT non-array THROWS; every member is strictly validated for a non-empty string
1564
- * `.binding` and returned with its full entry object.
1533
+ * Entry-shaped reader for a NAMESPACE-array field (`[{ binding }]`: kv_namespaces, d1_databases,
1534
+ * r2_buckets, hyperdrive, services, vectorize, …). A PRESENT value that is not an array THROWS
1535
+ * rather than being re-read as a key-map (which could under-collect and hide a real collision);
1536
+ * every member is strictly validated for a non-empty string `.binding`.
1565
1537
  */
1566
1538
  function namespaceArrayBindingEntries(field, value) {
1567
1539
  if (value === void 0) return [];
@@ -1569,8 +1541,15 @@ function namespaceArrayBindingEntries(field, value) {
1569
1541
  return strictBindingEntries(value, "binding", field);
1570
1542
  }
1571
1543
  /**
1572
- * Entry-shaped reader for a NAME-keyed array field (mirror of {@link nameKeyedBindingNames}):
1573
- * identity is `.name` only; a PRESENT non-array THROWS; every member is strictly validated.
1544
+ * Entry-shaped reader for a NAME-keyed array field (`send_email` / `ratelimits`: an array of
1545
+ * `{ name }`). A PRESENT non-array THROWS; every member is strictly validated.
1546
+ *
1547
+ * Identity is the `.name` ONLY. Verified against wrangler 4.131's bundle +
1548
+ * `config-schema.json`: NEITHER `send_email` NOR `ratelimits` has a `.binding` property in
1549
+ * the schema, and on UPLOAD wrangler keys them by `.name`. An optional `.binding` that happens
1550
+ * to sit on such an entry is NOT a binding identity wrangler recognizes, so unioning it would
1551
+ * invent a PHANTOM collision (e.g. `send_email:[{name:"EMAIL_A",binding:"QUEUE_JOBS"}]` would
1552
+ * falsely block a legitimate `QUEUE_JOBS` queue producer).
1574
1553
  */
1575
1554
  function nameKeyedBindingEntries(field, value) {
1576
1555
  if (value === void 0) return [];
@@ -1578,10 +1557,10 @@ function nameKeyedBindingEntries(field, value) {
1578
1557
  return strictBindingEntries(value, "name", field);
1579
1558
  }
1580
1559
  /**
1581
- * Entry-shaped reader for a binding-LIST field (mirror of {@link bindingListNames}): the entry
1582
- * of each member is the member itself (`{ name, ... }`), keyed on `.name`. Same throw semantics
1583
- * as the name reader — a wrong outer shape, or a required-but-missing `bindings`, THROWS; a
1584
- * `bindings`-less `unsafe` (optional) contributes nothing.
1560
+ * Entry-shaped reader for a binding-LIST field (`{ bindings: [{ name }] }`: durable_objects /
1561
+ * logfwdr / unsafe): the entry of each member is the member itself, keyed on `.name`. A wrong
1562
+ * outer shape, or a missing `bindings` when required (durable_objects / logfwdr per schema),
1563
+ * THROWS; a `bindings`-less `unsafe` (optional) contributes nothing.
1585
1564
  */
1586
1565
  function bindingListEntries(field, value, bindingsRequired) {
1587
1566
  if (value === void 0) return [];
@@ -1594,10 +1573,11 @@ function bindingListEntries(field, value, bindingsRequired) {
1594
1573
  return strictBindingEntries(value.bindings, "name", `${field}.bindings`);
1595
1574
  }
1596
1575
  /**
1597
- * Entry-shaped reader for a SINGLETON field (mirror of {@link singletonBindingName}): the entry
1598
- * is the singleton value itself. A PRESENT non-object THROWS; a present-but-malformed `binding`
1599
- * THROWS; a required-but-absent `binding` THROWS; a binding-optional `assets` with no binding
1600
- * contributes nothing.
1576
+ * Entry-shaped reader for a SINGLETON field (`{ binding }`: ai / browser / images / stream /
1577
+ * media / websearch / version_metadata / assets): the entry is the singleton value itself. A
1578
+ * PRESENT non-object THROWS; a present-but-malformed `binding` THROWS; a required-but-absent
1579
+ * `binding` THROWS (never a fall-through that would mis-collect the object's OTHER keys); a
1580
+ * binding-optional `assets` with no binding contributes nothing.
1601
1581
  */
1602
1582
  function singletonBindingEntry(field, value, bindingRequired) {
1603
1583
  if (value === void 0) return [];
@@ -1614,8 +1594,7 @@ function singletonBindingEntry(field, value, bindingRequired) {
1614
1594
  * Read binding names from a KEY-MAP field (`vars`/`wasm_modules`/`text_blobs`/
1615
1595
  * `data_blobs`): the object's KEYS are the binding names. Reads ONLY the keys — never
1616
1596
  * the values — so a value that happens to look like a binding list (`{bindings:[…]}`)
1617
- * or a singleton (`{binding:'x'}`) is NOT misread (the old generic path returned the
1618
- * VALUE, or a nested `name`, instead of the real KEY). A PRESENT value that is not a
1597
+ * or a singleton (`{binding:'x'}`) is NOT misread. A PRESENT value that is not a
1619
1598
  * plain object is the wrong outer shape and THROWS (fail closed). An explicitly
1620
1599
  * `undefined`-valued key is not a real binding and is skipped.
1621
1600
  */
@@ -1625,95 +1604,11 @@ function keyMapBindingNames(field, value) {
1625
1604
  return Object.keys(value).filter((key) => value[key] !== void 0);
1626
1605
  }
1627
1606
  /**
1628
- * Read binding names from a NAMESPACE-array field (`[{ binding }]`: kv_namespaces,
1629
- * d1_databases, r2_buckets, hyperdrive, services, vectorize, …). A PRESENT value that
1630
- * is not an array is the wrong outer shape and THROWS rather than being re-read as a
1631
- * key-map (which could under-collect and hide a real collision); every member is
1632
- * strictly validated for a non-empty string `.binding`.
1633
- */
1634
- function namespaceArrayBindingNames(field, value) {
1635
- if (value === void 0) return [];
1636
- if (!Array.isArray(value)) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" must be an array of binding entries. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1637
- return strictBindingArray(value, "binding", field);
1638
- }
1639
- /**
1640
- * Read binding names from a NAME-keyed array field (`send_email` / `ratelimits`:
1641
- * an array of `{ name }`). Encodes the field's REQUIRED outer shape: a PRESENT value that
1642
- * is not an array THROWS (fail closed) rather than falling back to generic key collection —
1643
- * wrangler validates these via `validateBindingArray`, so a non-array is malformed and
1644
- * could hide a real collision if silently re-read as a key-map. An ABSENT value contributes
1645
- * nothing. Every array member is strictly validated (a malformed one rejects the whole
1646
- * config).
1647
- *
1648
- * Identity is the `.name` ONLY. Verified against wrangler 4.131's bundle +
1649
- * `config-schema.json`: NEITHER `send_email` NOR `ratelimits` has a `.binding` property in
1650
- * the schema, and on UPLOAD wrangler keys them by `.name` (send_email:
1651
- * `output[name] = { type: "send_email", ...}`; ratelimits push `{ name: binding.name, … }`).
1652
- * An optional `.binding` that happens to sit on such an entry is NOT a binding identity
1653
- * wrangler recognizes, so unioning it invents a PHANTOM collision — e.g. a
1654
- * `send_email:[{name:"EMAIL_A",binding:"QUEUE_JOBS"}]` would falsely block a legitimate
1655
- * `QUEUE_JOBS` queue producer / adopt / read-first. We therefore collect ONLY the `.name`
1656
- * of every member (a genuine same-`name` collision is still caught).
1657
- */
1658
- function nameKeyedBindingNames(field, value) {
1659
- if (value === void 0) return [];
1660
- if (!Array.isArray(value)) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" must be an array of binding entries. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1661
- return strictBindingArray(value, "name", field);
1662
- }
1663
- /**
1664
- * Read the binding names from a binding-LIST field (`{ bindings: [{ name }] }`:
1665
- * durable_objects / logfwdr / unsafe). A PRESENT value that is not an object is the
1666
- * wrong outer shape and THROWS. When `bindingsRequired` (durable_objects / logfwdr per
1667
- * schema), a MISSING `bindings` array THROWS (never a silent empty read); `unsafe` is
1668
- * optional, so a `bindings`-less `{ metadata }` contributes nothing. A PRESENT
1669
- * `bindings` array has EVERY member strictly validated for a non-empty string `name`.
1670
- */
1671
- function bindingListNames(field, value, bindingsRequired) {
1672
- if (value === void 0) return [];
1673
- if (!isRecord(value)) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" must be an object with a "bindings" array. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1674
- if (value.bindings === void 0) {
1675
- if (bindingsRequired) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" requires a "bindings" array. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1676
- return [];
1677
- }
1678
- if (!Array.isArray(value.bindings)) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}.bindings" must be an array. Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1679
- return strictBindingArray(value.bindings, "name", `${field}.bindings`);
1680
- }
1681
- /**
1682
- * Read the binding name from a SINGLETON field (`{ binding }`: ai / browser /
1683
- * images / stream / media / websearch / version_metadata / assets). A PRESENT value
1684
- * that is not an object is the wrong outer shape and THROWS. A PRESENT-but-malformed
1685
- * `binding` (non-string / empty) THROWS. When `bindingRequired` (every singleton except
1686
- * `assets`, per schema), an ABSENT `binding` also THROWS — never a silent empty read,
1687
- * and never a fall-through that would mis-collect the object's OTHER keys (e.g.
1688
- * `{ staging: true }`) as bogus binding names. `assets` is binding-optional, so an
1689
- * absent binding (e.g. `{ directory }`) contributes nothing.
1690
- */
1691
- function singletonBindingName(field, value, bindingRequired) {
1692
- if (value === void 0) return [];
1693
- if (!isRecord(value)) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" must be an object with a "binding". Refusing to proceed on a partially-readable binding set (a wrong-shaped field could hide a real collision). Fix the wrangler config and retry.`);
1694
- if (typeof value.binding === "string" && value.binding.length > 0) return [value.binding];
1695
- if (value.binding !== void 0) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" has a malformed "binding" (expected a non-empty string). Refusing to proceed on a partially-readable binding set (a dropped binding could hide a real collision). Fix the wrangler config and retry.`);
1696
- if (bindingRequired) throw new Error(`deploy: cannot verify binding-name uniqueness — "${field}" requires a "binding" (a non-empty string). Refusing to proceed on a partially-readable binding set (a dropped binding could hide a real collision). Fix the wrangler config and retry.`);
1697
- return [];
1698
- }
1699
- /**
1700
- * Strictly read `keyField` (a non-empty string) from EVERY member of a
1701
- * binding-bearing array. THROWS (fail closed) on ANY malformed member — never
1702
- * silently drops one. Dropping a malformed member could convert a mixed-validity
1703
- * array (e.g. `[null, { binding: 'DB', id: '…' }]`) into an empty/partial binding
1704
- * set, so the worker-wide uniqueness guard would MISS the existing `DB` and commit
1705
- * a conflicting binding — a fail-open in a documented invariant. Mirrors the
1706
- * writer's existing fail-closed-on-malformed-config philosophy.
1707
- */
1708
- function strictBindingArray(members, keyField, field) {
1709
- return strictBindingEntries(members, keyField, field).map((e) => e.name);
1710
- }
1711
- /**
1712
- * The entry-shaped sibling of {@link strictBindingArray}: reads `keyField` (a non-empty string)
1713
- * from EVERY member and returns it PAIRED with the member's full entry object. Same fail-closed
1714
- * validation — a non-record member, or one missing a non-empty string `keyField`, THROWS (never
1715
- * silently dropped). {@link strictBindingArray} is defined in terms of this, so the two agree on
1716
- * names and error messages for every field.
1607
+ * Strictly read `keyField` (a non-empty string) from EVERY member of a binding-bearing array and
1608
+ * return it PAIRED with the member's full entry object. THROWS (fail closed) on ANY malformed
1609
+ * member — never silently drops one. Dropping a malformed member could convert a mixed-validity
1610
+ * array (e.g. `[null, { binding: 'DB', id: '…' }]`) into an empty/partial binding set, so the
1611
+ * worker-wide uniqueness guard would MISS the existing `DB` and commit a conflicting binding.
1717
1612
  */
1718
1613
  function strictBindingEntries(members, keyField, field) {
1719
1614
  return members.map((member, index) => {
@@ -1755,4 +1650,4 @@ function canonicalize(value) {
1755
1650
  return value;
1756
1651
  }
1757
1652
  //#endregion
1758
- export { writeProvisionedWranglerConfig as A, readWranglerPublishedTrafficSnapshot as C, syncWranglerDurableObjects as D, syncWranglerBindings as E, syncWranglerWebSockets as O, readWranglerManagedQueueCleanupCandidates as S, resolveLiveBindingConfig as T, readExistingLiveBindingConfig as _, LIVE_MIGRATION_TAG as a, readWranglerCompat as b, bindingEntriesForField as c, ensureWranglerCompatibilityDate as d, ensureWranglerNodejsAlsFlag as f, normalizeWranglerCompatibilityFlags as g, nextDurableObjectMigrationTag as h, LATEST_KNOWN_COMPAT_DATE as i, writeWranglerPublishedTrafficSnapshot as j, updateWranglerCustomDomain as k, bindingNamesForField as l, hasDurableObjectSqliteMigration as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, findBindingNameOwner as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompat as u, readProvisionedBindingEntry as v, readWranglerWebSocketTombstones as w, readWranglerCustomDomains as x, readRootWranglerConfig as y };
1653
+ export { updateWranglerCustomDomain as A, readWranglerManagedQueueCleanupCandidates as C, syncWranglerBindings as D, resolveLiveBindingConfig as E, writeWranglerPublishedTrafficSnapshot as M, syncWranglerDurableObjects as O, readWranglerCustomDomains as S, readWranglerWebSocketTombstones as T, persistMaterializedWranglerConfig as _, LIVE_MIGRATION_TAG as a, readRootWranglerConfig as b, bindingEntriesForField as c, ensureWranglerCompatibilityDate as d, ensureWranglerNodejsAlsFlag as f, normalizeWranglerCompatibilityFlags as g, nextDurableObjectMigrationTag as h, LATEST_KNOWN_COMPAT_DATE as i, writeProvisionedWranglerConfig as j, syncWranglerWebSockets as k, bindingNamesForField as l, hasDurableObjectSqliteMigration as m, DEFAULT_LIVE_CLASS as n, acknowledgeWranglerManagedQueueRemovals as o, findBindingNameOwner as p, FRIENDLY_BINDING_NAMES as r, assertNoDuplicateMembers as s, DEFAULT_LIVE_BINDING as t, ensureWranglerCompat as u, readExistingLiveBindingConfig as v, readWranglerPublishedTrafficSnapshot as w, readWranglerCompat as x, readProvisionedBindingEntry as y };
@@ -1,6 +1,6 @@
1
1
  import { t as StandardSchemaV1 } from "./standard-schema-Fo_vCAZh.mjs";
2
2
  import { r as AuthUser } from "./auth-DkcFflXV.mjs";
3
- import { a as CloudEnv } from "./handler-BeK3weD4.mjs";
3
+ import { a as CloudEnv } from "./handler-CNAwjRcW.mjs";
4
4
  import { WebSocketRouteMap } from "void/routes";
5
5
  //#region src/runtime/ws.d.ts
6
6
  type MaybePromise<T> = T | Promise<T>;
@@ -69,26 +69,28 @@ function hasLocalLockfile(dir) {
69
69
  * PnP monorepo, `.pnp.cjs` lives at the workspace root, not in each
70
70
  * subpackage. Checking only `start` would miss the common shape.
71
71
  *
72
- * Round 46: local PnP files at `start` are always authoritative and
73
- * take precedence over the leaf-managed guard below. When `start` has
74
- * no local PnP files but DOES have local install ownership (lockfile or
75
- * Corepack pin), stop here — ancestor PnP data belongs to a different
76
- * install graph and injecting it will break resolution for the local
77
- * one. Only walk past `start` when neither condition holds.
78
- *
79
- * Internal: only `buildDrizzleKitSpawnEnv` below consumes this. The
80
- * stricter `findInstalledYarnPnpRuntime` is the public variant callers
81
- * outside this module reach for.
72
+ * Local PnP files at `start` are always authoritative and take
73
+ * precedence over the leaf-managed guard below. When `start` has no
74
+ * local PnP files but DOES have a local lockfile, stop here — ancestor
75
+ * PnP data belongs to a different install graph and injecting it will
76
+ * break resolution for the local one. Only walk past `start` when
77
+ * neither condition holds.
82
78
  */
83
79
  function findYarnPnpRuntime(start) {
84
80
  const local = readPnpRuntimeAt(start);
85
- if (local !== void 0) return local;
81
+ if (local !== void 0) return {
82
+ dir: start,
83
+ runtime: local
84
+ };
86
85
  if (hasLocalLockfile(start)) return;
87
86
  let dir = dirname(start);
88
87
  if (dir === start) return;
89
88
  while (true) {
90
89
  const found = readPnpRuntimeAt(dir);
91
- if (found !== void 0) return found;
90
+ if (found !== void 0) return {
91
+ dir,
92
+ runtime: found
93
+ };
92
94
  const parent = dirname(dir);
93
95
  if (parent === dir) return;
94
96
  dir = parent;
@@ -99,7 +101,7 @@ function findYarnPnpRuntime(start) {
99
101
  * when the PnP runtime files AND a post-install marker live in the
100
102
  * SAME ancestor directory.
101
103
  *
102
- * Round 40 rationale: Yarn Berry repos commonly commit `.pnp.cjs` to
104
+ * Yarn Berry repos commonly commit `.pnp.cjs` to
103
105
  * version control but NOT `.yarn/cache/*.zip` (zero-install is an
104
106
  * opt-in, not the default). A fresh `git clone` before `yarn install`
105
107
  * therefore has `.pnp.cjs` on disk while the PnP data points at ZIP
@@ -108,7 +110,7 @@ function findYarnPnpRuntime(start) {
108
110
  * install step, and the subsequent `drizzle-kit generate` spawn crashes
109
111
  * because PnP tries to load `void/schema-d1` from a missing ZIP.
110
112
  *
111
- * Round 42: accept EITHER of two markers, to cover both non-zero-install
113
+ * Accept EITHER of two markers, to cover both non-zero-install
112
114
  * and zero-install shapes:
113
115
  *
114
116
  * 1. `.yarn/install-state.gz` in the same dir. Yarn Berry (3.x and
@@ -135,18 +137,8 @@ function findYarnPnpRuntime(start) {
135
137
  * a spawn, the env needs to be prepared.
136
138
  */
137
139
  function findInstalledYarnPnpRuntime(start) {
138
- const local = readPnpRuntimeAt(start);
139
- if (local !== void 0) return isYarnPnpInstalled(start) ? local : void 0;
140
- if (hasLocalLockfile(start)) return;
141
- let dir = dirname(start);
142
- if (dir === start) return;
143
- while (true) {
144
- const found = readPnpRuntimeAt(dir);
145
- if (found !== void 0) return isYarnPnpInstalled(dir) ? found : void 0;
146
- const parent = dirname(dir);
147
- if (parent === dir) return;
148
- dir = parent;
149
- }
140
+ const found = findYarnPnpRuntime(start);
141
+ return found && isYarnPnpInstalled(found.dir) ? found.runtime : void 0;
150
142
  }
151
143
  /**
152
144
  * Return true when `dir` looks like a post-install Yarn Berry PnP
@@ -183,7 +175,7 @@ function isYarnPnpInstalled(dir) {
183
175
  */
184
176
  function buildDrizzleKitSpawnEnv(root) {
185
177
  const env = { ...process.env };
186
- const pnp = findYarnPnpRuntime(root);
178
+ const pnp = findYarnPnpRuntime(root)?.runtime;
187
179
  if (!pnp) return env;
188
180
  const flags = [];
189
181
  if (pnp.pnpCjs) flags.push(`--require ${JSON.stringify(pnp.pnpCjs)}`);
@@ -41,7 +41,7 @@ export const POST = defineHandler(async (c) => {
41
41
  });
42
42
  ```
43
43
 
44
- AI methods return promises. Await them to receive the result, or return the promise directly from a handler. Usage limits reject with [`UsageLimit`](#usage-limits); Void route handlers and Pages actions automatically send a structured HTTP 429 when it is left uncaught.
44
+ AI methods return promises. Await them to receive the result, or return the promise directly from a handler. See [Usage Limits](#usage-limits) for limit errors.
45
45
 
46
46
  You can use any model available through Cloudflare's AI binding, including Workers AI models such as `@cf/meta/llama-3.3-70b-instruct-fp8-fast` and Cloudflare Gateway models such as `google/gemini-2.5-flash` or `openai/gpt-4.1-mini`. The input object must match the selected Cloudflare model's schema. Models that return binary data, such as generated images, are returned as a `Blob` from `ai.run()`.
47
47
 
@@ -133,7 +133,7 @@ const result = await ai.run('google/gemini-2.5-flash', {
133
133
  });
134
134
  ```
135
135
 
136
- Pass AI Gateway options as the third argument: `ai.run(model, inputs, { gateway: { skipCache: true } })`.
136
+ Pass AI Gateway options as the third argument: `ai.run(model, inputs, { gateway: { skipCache: true } })`. On a team platform, the platform chooses the gateway and sets its metadata and logging; options such as `skipCache` and `cacheTtl` still apply.
137
137
 
138
138
  For provider-native requests on a direct deployment, configure [`ai.gateway`](../integrations/cloudflare.md#ai-self-host).
139
139
 
@@ -142,7 +142,9 @@ For provider-native requests on a direct deployment, configure [`ai.gateway`](..
142
142
  Use `ai.provider(provider).fetch(path, init)` for a provider-native API with your
143
143
  own provider key. The request goes through the configured Cloudflare AI Gateway
144
144
  and retains the provider's native HTTP shape. On a team platform, it also passes
145
- through that installation's proxy.
145
+ through that installation's proxy. AI Gateway cache, timeout and retry headers,
146
+ such as `cf-aig-cache-ttl` and `cf-aig-max-attempts`, still apply there; the
147
+ platform ignores logging, metadata and cost headers.
146
148
 
147
149
  ### OpenAI
148
150
 
@@ -92,7 +92,7 @@ Email/password is enabled by default. To add social providers:
92
92
  }
93
93
  ```
94
94
 
95
- Use `auth.providers` when you want to enable social providers explicitly. Provider credentials come from `AUTH_<PROVIDER>_CLIENT_ID` and `AUTH_<PROVIDER>_CLIENT_SECRET`.
95
+ Provider credentials come from `AUTH_<PROVIDER>_CLIENT_ID` and `AUTH_<PROVIDER>_CLIENT_SECRET`.
96
96
 
97
97
  See the full provider list in the [config reference](../reference/config.md#auth).
98
98
 
@@ -127,6 +127,42 @@ Auth sessions use the same database as your app. Void creates `BETTER_AUTH_SECRE
127
127
 
128
128
  Local development needs no secret setup. To preview a production build locally, provide `BETTER_AUTH_SECRET`.
129
129
 
130
+ `POST`, `PUT`, `PATCH` and `DELETE` requests and WebSocket connections from another origin don't use the signed-in session unless that origin is in `trustedOrigins`. If a separate frontend calls your app, add its origin there (see [Customization](#customization)). If your routes use their own cookies, check the request `Origin` yourself, for example with Hono's [`csrf()`](https://hono.dev/docs/middleware/builtin/csrf) middleware.
131
+
132
+ Deployed apps on Cloudflare limit auth requests per client IP with Better Auth's defaults, for example 3 sign-in attempts per 10 seconds. Each Worker instance keeps its own count. Change or turn off the limits with `rateLimit` in `auth.ts`. To share one count across instances, set `rateLimit: { storage: 'database' }`, then run `void db generate` for a direct Cloudflare deploy.
133
+
134
+ ### Proxies and end-to-end tests
135
+
136
+ All requests from one IP share one count. Two common setups reach the limits:
137
+
138
+ - A server calls your auth endpoints for your users, such as a backend-for-frontend, a rewrite from Vercel or nginx, or another Worker's `fetch`. All of those users share that server's IP.
139
+ - End-to-end tests sign up or sign in many times against a deployed app.
140
+
141
+ Don't read the client IP from `x-forwarded-for` instead: any client can send that header. Give the trusted caller a secret header, and skip the limits only for requests that carry it:
142
+
143
+ ```ts
144
+ import { defineAuth } from 'void/auth';
145
+
146
+ export default defineAuth(({ defaults, env }) => ({
147
+ ...defaults,
148
+ rateLimit: {
149
+ customRules: {
150
+ '/**': (request, rule) =>
151
+ env.AUTH_TRUSTED_KEY && request.headers.get('x-auth-trusted-key') === env.AUTH_TRUSTED_KEY
152
+ ? false
153
+ : rule,
154
+ },
155
+ },
156
+ }));
157
+ ```
158
+
159
+ `'/**'` matches every auth endpoint. Returning `false` skips the limit, and returning `rule` keeps the default limit for everyone else. Declare `AUTH_TRUSTED_KEY: string().optional()` in `env.ts` and set it with `void secret put AUTH_TRUSTED_KEY` (see [Environment variables](./env-vars.md#production-server-values)).
160
+
161
+ Your app no longer limits requests that carry the key, so:
162
+
163
+ - A proxy that sends it must limit every auth request it forwards for each of its users, including sign-up, password reset and verification emails.
164
+ - A test runner should send it only to your app. Never put the key in code that runs in your users' browsers.
165
+
130
166
  ## Customization
131
167
 
132
168
  For advanced configuration, create `auth.ts` at the project root and export `defineAuth(...)`:
@@ -59,7 +59,7 @@ export const users = pgTable('users', {
59
59
  });
60
60
  ```
61
61
 
62
- `void gen model` generates PostgreSQL-appropriate code when the dialect is set to `postgresql`.
62
+ `void gen model` generates PostgreSQL-appropriate code when `database` is set to `"pg"`.
63
63
 
64
64
  ## Migrations
65
65
 
@@ -88,4 +88,4 @@ To update a linked Void project's connection, for example after moving the datab
88
88
  void db set-url
89
89
  ```
90
90
 
91
- This prompts for the new connection string and updates the Hyperdrive configuration. The change takes effect on the next deploy.
91
+ This prompts for the new connection string and updates the Hyperdrive configuration.