void 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/README.md +5 -1
  2. package/dist/{account-cmd-CjyxcGkM.mjs → account-cmd-C84Ee8cO.mjs} +4 -4
  3. package/dist/{scan-ClYmX3sa.mjs → application-analysis-BVsVqc11.mjs} +135 -18
  4. package/dist/application-routing-B7QEjqSR.mjs +27 -0
  5. package/dist/{auth-CZuiVsFh.mjs → auth-CCjt0hcq.mjs} +1 -1
  6. package/dist/{auth-DLNN0D3Z.mjs → auth-CSkdO2Bb.mjs} +4 -47
  7. package/dist/{auth-link-BLO4ptzo.mjs → auth-link-CioEg6uY.mjs} +4 -4
  8. package/dist/{auth-router-ZUg9MF_U.mjs → auth-router-BsR981d4.mjs} +4 -4
  9. package/dist/{better-auth-shared-rsBGBvWJ.mjs → better-auth-shared-hy6RPh9W.mjs} +13 -2
  10. package/dist/{build-cmd-BxR5FROK.mjs → build-cmd-LzvNJORH.mjs} +17 -5
  11. package/dist/{cache-D0sWhgKI.mjs → cache-C4MvnrMH.mjs} +2 -2
  12. package/dist/{cancel-deploy-D4NUqFbi.mjs → cancel-deploy-abUxpP2n.mjs} +2 -2
  13. package/dist/{cf-build-output-BJ6yGEIS.mjs → cf-build-output-BPqOT964.mjs} +2 -1
  14. package/dist/cf-build-output-_0HNWysu.mjs +2 -0
  15. package/dist/cli/cli.mjs +80 -455
  16. package/dist/cli/{cf-compat.mjs → cloudflare-operation-process.mjs} +442 -421
  17. package/dist/cli/env-schema-probe.d.mts +2 -1
  18. package/dist/cli/env-schema-probe.mjs +3 -3
  19. package/dist/client-Cu7jWiF1.mjs +2 -0
  20. package/dist/{client-BTZ3XkrB.mjs → client-RV8NVeB8.mjs} +140 -21
  21. package/dist/{cloudflare-auth-DQkqoMYa.mjs → cloudflare-auth-Qdc7tw8F.mjs} +41 -38
  22. package/dist/{cloudflare-cmd-BKlfGHAy.mjs → cloudflare-cmd-BcrVyTmJ.mjs} +5 -5
  23. package/dist/cloudflare-config-Bktvwtpf.mjs +182 -0
  24. package/dist/{cloudflare-connect-Ctmrw579.mjs → cloudflare-connect-B8uPZ4nx.mjs} +3 -3
  25. package/dist/{cloudflare-operations-BT6OWFBk.mjs → cloudflare-operations-AiWashgg.mjs} +1 -1
  26. package/dist/{cloudflare-operations-B9tzgjmf.mjs → cloudflare-operations-fxHb-byx.mjs} +116 -172
  27. package/dist/{preset-UHj9ARyP.mjs → cloudflare-process-B-wekeR6.mjs} +93 -6
  28. package/dist/{config-VavjpDnp.d.mts → config-BMHb8RCj.d.mts} +1 -0
  29. package/dist/config-C_XRIPx2.mjs +89 -0
  30. package/dist/config-entry.d.mts +1 -1
  31. package/dist/{connect-Dg-WkW-C.mjs → connect-Bd4kJd9U.mjs} +5 -5
  32. package/dist/{create-project-DdoqwFLF.mjs → create-project-Boczwj5r.mjs} +1 -1
  33. package/dist/{create-project-l9J7pbtm.mjs → create-project-bMf6ffLZ.mjs} +2 -2
  34. package/dist/{db-gp2sCXyN.mjs → db-8uG64XLl.mjs} +21 -21
  35. package/dist/{delete-TTedbH6B.mjs → delete-NvbiyeJf.mjs} +2 -2
  36. package/dist/{deploy-CH-o2CaZ.mjs → deploy-DzAIwqNU.mjs} +908 -582
  37. package/dist/{deploy-B19L2Bra.mjs → deploy-bjXdFCtn.mjs} +1 -1
  38. package/dist/{domain-JRF59P_r.mjs → domain-y5Tvydvo.mjs} +3 -3
  39. package/dist/{email-Bo6G9LOZ.mjs → email-B3umsW75.mjs} +13 -28
  40. package/dist/{env-BYOrWQnv.mjs → env-BS6qYHDb.mjs} +4 -4
  41. package/dist/{env-public-BxU_0yTL.d.mts → env-public-BX_r8HR6.d.mts} +1 -1
  42. package/dist/{env-validation-BB4GkLxn.mjs → env-validation-BPn7vk-V.mjs} +18 -71
  43. package/dist/{env-validation-BXge7uyK.mjs → env-validation-DbTg7-ar.mjs} +1 -1
  44. package/dist/{fetch-CXDChK7B.mjs → fetch-BIZJh7vR.mjs} +2 -2
  45. package/dist/{fetch-stream-AOByI7Ki.mjs → fetch-stream-IvCYKyQL.mjs} +24 -4
  46. package/dist/{gen-sCtlCOdA.mjs → gen-B580--vC.mjs} +2 -2
  47. package/dist/gen-BVaUUumi.mjs +2 -0
  48. package/dist/{github-cmd-0-7PexDq.mjs → github-cmd-v45BdfKX.mjs} +2 -2
  49. package/dist/{handler-HEcZsaij.d.mts → handler-CZ4nAylQ.d.mts} +1 -1
  50. package/dist/help-DofyZuY7.mjs +2 -0
  51. package/dist/{help-GKtwl07I.mjs → help-daGKjXGk.mjs} +229 -747
  52. package/dist/index.d.mts +1 -1
  53. package/dist/index.mjs +288 -1502
  54. package/dist/info-B97bTX9N.mjs +113 -0
  55. package/dist/{init-FZx3Elvz.mjs → init-Bvy7zrBo.mjs} +46 -15
  56. package/dist/limits-Bq5LG8Id.d.mts +27 -0
  57. package/dist/limits-Cjuk2VPm.mjs +68 -0
  58. package/dist/{link-BrQfb_CU.mjs → link-CDqqCjFl.mjs} +3 -3
  59. package/dist/{list-D44jmIAM.mjs → list-CZj0dzKY.mjs} +3 -3
  60. package/dist/{live-CKJlvlNp.d.mts → live-Chw1eIMv.d.mts} +1 -1
  61. package/dist/{local-d1-Bg9OzEEO.mjs → local-d1-2CMnpuW_.mjs} +2 -2
  62. package/dist/login-DYt_An22.mjs +2 -0
  63. package/dist/{login-CAsAsQ-_.mjs → login-UZKFM_u7.mjs} +3 -3
  64. package/dist/{logs-BjKvFnVM.mjs → logs-CUZ6t9t3.mjs} +3 -3
  65. package/dist/migrate-8_2u55MD.mjs +2 -0
  66. package/dist/{migrate-BPITvDJN.mjs → migrate-DHul7PRV.mjs} +2 -1
  67. package/dist/{node-Dt7z256D.mjs → node-BkyRWRx8.mjs} +1 -1
  68. package/dist/operator-args-CLgKGlwU.mjs +690 -0
  69. package/dist/{operator-cmd-BK5CCiT9.mjs → operator-cmd-DBA6dl0m.mjs} +68 -22
  70. package/dist/pages/client.d.mts +34 -2
  71. package/dist/pages/client.mjs +59 -3
  72. package/dist/pages/index.d.mts +1 -1
  73. package/dist/pages/index.mjs +1 -1
  74. package/dist/pages/islands-plugin.mjs +1 -1
  75. package/dist/pages/protocol.d.mts +2 -2
  76. package/dist/pages/protocol.mjs +2 -308
  77. package/dist/{parse-filename-DioPHiR9.mjs → parse-filename-CUbj-1MP.mjs} +35 -1
  78. package/dist/plan-D1Q5rf-r.mjs +2 -0
  79. package/dist/plan-NPpwZ_kc.mjs +58 -0
  80. package/dist/platform-args-BJdRtlLq.mjs +506 -0
  81. package/dist/platform-args-D3RXyR6h.mjs +2 -0
  82. package/dist/{platform-auth-config-BlN8xTdD.mjs → platform-auth-config-B56E9YP1.mjs} +3 -3
  83. package/dist/{platform-auth-protection-7d5aV2Jg.mjs → platform-auth-protection-BDWO_aER.mjs} +2 -2
  84. package/dist/{platform-auth-recovery-Dxij8ZbR.mjs → platform-auth-recovery-1gg4CSRe.mjs} +3 -3
  85. package/dist/{platform-cmd-E0FuL212.mjs → platform-cmd-Bt-1w6pY.mjs} +1 -1
  86. package/dist/{platform-cmd-B3hwKrFK.mjs → platform-cmd-DMcQStSc.mjs} +24 -3
  87. package/dist/{platform-domain-D6Xcy9ZX.mjs → platform-domain-BNkcz0OB.mjs} +2 -2
  88. package/dist/{platform-lifecycle-k0E0xoxx.mjs → platform-lifecycle-9OyBALhH.mjs} +327 -215
  89. package/dist/{platform-lifecycle-DMh_qrry.mjs → platform-lifecycle-BE6C_jxh.mjs} +1 -1
  90. package/dist/{platform-management-Brz_BDiT.mjs → platform-management-CjwLVQwN.mjs} +6 -3
  91. package/dist/{platform-management-DOtss0BN.mjs → platform-management-CnyTdcWX.mjs} +1 -1
  92. package/dist/platform-plans-config-BNGKGr4P.mjs +359 -0
  93. package/dist/{platform-recovery-BvtcXON5.mjs → platform-recovery-D6KSpuFm.mjs} +2 -2
  94. package/dist/{plugin-inference-BMfKRSqE.mjs → plugin-inference-CXWnn79A.mjs} +174 -64
  95. package/dist/{prepare-C-6YZyyg.mjs → prepare-B5Mkic5u.mjs} +1 -1
  96. package/dist/{prepare-CRhJbVrG.mjs → prepare-DOsL0CC9.mjs} +4 -20
  97. package/dist/prepare-cgvDMtSb.mjs +2 -0
  98. package/dist/{project-cmd-BZLCqOqw.mjs → project-cmd-CNzrqvBv.mjs} +16 -16
  99. package/dist/{project-team-BvgM0WoX.mjs → project-team-DQOWPfQT.mjs} +2 -2
  100. package/dist/{project-token-l5DqK6Az.mjs → project-token-CTDYU0Cc.mjs} +2 -2
  101. package/dist/{project-zero-trust-v6Mvpp8y.mjs → project-zero-trust-BNAkW-_0.mjs} +2 -2
  102. package/dist/{protocol-BBa6cstI.d.mts → protocol-CjF_iI9X.d.mts} +2 -2
  103. package/dist/protocol-U7bfjHmA.mjs +331 -0
  104. package/dist/{provision-Fr9pRqce.mjs → provision-C4ORE7G7.mjs} +1 -1
  105. package/dist/{provision-C4IGqkBf.mjs → provision-CJFgTZY8.mjs} +89 -198
  106. package/dist/{requests-DN-BbNiM.mjs → requests-MhxYnau8.mjs} +2 -2
  107. package/dist/resource-name-C7LVpcRm.mjs +11 -0
  108. package/dist/{rollback-D7rzSaZM.mjs → rollback-CJ6iSDoU.mjs} +3 -3
  109. package/dist/route-url-CG7U-cRN.mjs +15 -0
  110. package/dist/{runner-B8wXwWlo.mjs → runner-CXA9Fh8h.mjs} +1 -1
  111. package/dist/{runner-p-dMs2UN.mjs → runner-Ol0TNjk6.mjs} +2 -2
  112. package/dist/runtime/ai.d.mts +12 -8
  113. package/dist/runtime/ai.mjs +84 -17
  114. package/dist/runtime/better-auth-mysql.mjs +1 -1
  115. package/dist/runtime/better-auth-pg.mjs +1 -1
  116. package/dist/runtime/better-auth.mjs +1 -1
  117. package/dist/runtime/client-react.mjs +2 -2
  118. package/dist/runtime/client-solid.mjs +2 -2
  119. package/dist/runtime/client-svelte.mjs +2 -2
  120. package/dist/runtime/client-vue.mjs +2 -2
  121. package/dist/runtime/client.mjs +2 -2
  122. package/dist/runtime/durable.d.mts +3 -1
  123. package/dist/runtime/durable.mjs +4 -1
  124. package/dist/runtime/email/testing.mjs +1 -1
  125. package/dist/runtime/env-public.d.mts +1 -1
  126. package/dist/runtime/fetch-stream.mjs +1 -1
  127. package/dist/runtime/fetch.mjs +1 -1
  128. package/dist/runtime/handler.d.mts +1 -1
  129. package/dist/runtime/kv.mjs +0 -1
  130. package/dist/runtime/limits.d.mts +2 -0
  131. package/dist/runtime/limits.mjs +2 -0
  132. package/dist/runtime/live-client.d.mts +1 -1
  133. package/dist/runtime/live-server.mjs +25 -16
  134. package/dist/runtime/live.d.mts +1 -1
  135. package/dist/runtime/migration-handler.mjs +62 -42
  136. package/dist/runtime/route-url.d.mts +4 -0
  137. package/dist/runtime/route-url.mjs +2 -0
  138. package/dist/runtime/routing.d.mts +180 -0
  139. package/dist/runtime/routing.mjs +1082 -0
  140. package/dist/runtime/sandbox-container.d.mts +1 -1
  141. package/dist/runtime/sandbox-container.mjs +1 -1
  142. package/dist/runtime/sandbox.d.mts +3 -3
  143. package/dist/runtime/sandbox.mjs +75 -45
  144. package/dist/runtime/sse.mjs +1 -1
  145. package/dist/runtime/validator.d.mts +1 -1
  146. package/dist/runtime/ws-server.d.mts +4 -2
  147. package/dist/runtime/ws-server.mjs +27 -2
  148. package/dist/runtime/ws.d.mts +2 -2
  149. package/dist/runtime/ws.mjs +8 -6
  150. package/dist/{sandbox-qpNBT8a3.d.mts → sandbox-XZAqzFlG.d.mts} +11 -8
  151. package/dist/{sandbox-container-DdNEBfCc.d.mts → sandbox-container-Bo0eiFKz.d.mts} +2 -1
  152. package/dist/{sandbox-container-4fdqLnyb.mjs → sandbox-container-C6ItmVuN.mjs} +4 -2
  153. package/dist/{scan-4tfN-PSn.mjs → scan-C7okrLyM.mjs} +4 -35
  154. package/dist/{secret-BOtOl_cb.mjs → secret-Dli5fP0B.mjs} +4 -4
  155. package/dist/{sse-BaC1jXko.mjs → sse-CQNaDFFV.mjs} +6 -3
  156. package/dist/validate-Dq_L3s0S.mjs +2 -0
  157. package/dist/{validate-CIUwFpjB.mjs → validate-ctOrgiS3.mjs} +2 -1
  158. package/dist/{wrangler-DQF1vKyf.mjs → wrangler-7K-bW_DL.mjs} +8 -239
  159. package/dist/{ws-BoY7vQML.d.mts → ws-CL1w7GXU.d.mts} +13 -2
  160. package/package.json +15 -8
  161. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +34 -157
  162. package/skills/void/SKILL.md +50 -135
  163. package/skills/void/docs/guide/ai.md +94 -84
  164. package/skills/void/docs/guide/app-types.md +3 -32
  165. package/skills/void/docs/guide/auth.md +12 -116
  166. package/skills/void/docs/guide/database/d1.md +9 -54
  167. package/skills/void/docs/guide/database/mysql.md +1 -1
  168. package/skills/void/docs/guide/database/postgresql.md +5 -26
  169. package/skills/void/docs/guide/database.md +23 -75
  170. package/skills/void/docs/guide/deployment.md +27 -113
  171. package/skills/void/docs/guide/durable-state.md +43 -18
  172. package/skills/void/docs/guide/edge/headers.md +3 -47
  173. package/skills/void/docs/guide/edge/prerendering.md +5 -20
  174. package/skills/void/docs/guide/edge/redirects.md +11 -64
  175. package/skills/void/docs/guide/edge/revalidation.md +5 -18
  176. package/skills/void/docs/guide/edge/rewrites.md +56 -284
  177. package/skills/void/docs/guide/edge/static-assets.md +22 -72
  178. package/skills/void/docs/guide/email/domains.md +112 -0
  179. package/skills/void/docs/guide/email/receiving.md +139 -0
  180. package/skills/void/docs/guide/email/sending.md +231 -0
  181. package/skills/void/docs/guide/email.md +13 -619
  182. package/skills/void/docs/guide/env-migration.md +11 -11
  183. package/skills/void/docs/guide/env-vars.md +9 -29
  184. package/skills/void/docs/guide/index.md +0 -15
  185. package/skills/void/docs/guide/jobs.md +3 -18
  186. package/skills/void/docs/guide/kv.md +5 -11
  187. package/skills/void/docs/guide/live.md +5 -56
  188. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +78 -125
  189. package/skills/void/docs/guide/pages-routing/head.md +10 -10
  190. package/skills/void/docs/guide/pages-routing/islands.md +6 -36
  191. package/skills/void/docs/guide/pages-routing/layouts.md +6 -128
  192. package/skills/void/docs/guide/pages-routing/loaders.md +3 -19
  193. package/skills/void/docs/guide/pages-routing/markdown.md +13 -171
  194. package/skills/void/docs/guide/pages-routing/overview.md +7 -17
  195. package/skills/void/docs/guide/pages-routing/view-transitions.md +1 -1
  196. package/skills/void/docs/guide/platform/administration/access.md +1 -4
  197. package/skills/void/docs/guide/platform/administration/email.md +35 -8
  198. package/skills/void/docs/guide/platform/administration/operations.md +26 -4
  199. package/skills/void/docs/guide/platform/administration/plans.md +126 -0
  200. package/skills/void/docs/guide/platform/administration/projects.md +5 -2
  201. package/skills/void/docs/guide/platform/administration/zero-trust.md +23 -152
  202. package/skills/void/docs/guide/platform/development/runtime.md +3 -13
  203. package/skills/void/docs/guide/platform/development/schema-ci.md +0 -58
  204. package/skills/void/docs/guide/platform/installation/credentials.md +6 -4
  205. package/skills/void/docs/guide/platform/installation/domains.md +30 -2
  206. package/skills/void/docs/guide/platform/installation/first-deployment.md +2 -0
  207. package/skills/void/docs/guide/platform/installation/maintenance.md +3 -1
  208. package/skills/void/docs/guide/platform/installation/prerequisites.md +20 -15
  209. package/skills/void/docs/guide/platform/installation/setup.md +9 -5
  210. package/skills/void/docs/guide/platform-administration.md +1 -0
  211. package/skills/void/docs/guide/queues.md +7 -9
  212. package/skills/void/docs/guide/quickstart.md +38 -37
  213. package/skills/void/docs/guide/remote-dev.md +4 -9
  214. package/skills/void/docs/guide/sandboxes.md +29 -21
  215. package/skills/void/docs/guide/server-routing.md +9 -72
  216. package/skills/void/docs/guide/sse.md +4 -18
  217. package/skills/void/docs/guide/ssg.md +3 -15
  218. package/skills/void/docs/guide/ssr.md +14 -62
  219. package/skills/void/docs/guide/storage.md +9 -4
  220. package/skills/void/docs/guide/type-safety.md +3 -14
  221. package/skills/void/docs/guide/typed-fetch.md +3 -7
  222. package/skills/void/docs/guide/websockets.md +68 -40
  223. package/skills/void/docs/integrations/agents.md +3 -3
  224. package/skills/void/docs/integrations/cloudflare.md +85 -316
  225. package/skills/void/docs/integrations/frameworks/analog.md +5 -64
  226. package/skills/void/docs/integrations/frameworks/astro.md +4 -73
  227. package/skills/void/docs/integrations/frameworks/nuxt.md +5 -62
  228. package/skills/void/docs/integrations/frameworks/overview.md +11 -54
  229. package/skills/void/docs/integrations/frameworks/react-router.md +5 -60
  230. package/skills/void/docs/integrations/frameworks/sveltekit.md +6 -65
  231. package/skills/void/docs/integrations/frameworks/tanstack-start.md +4 -62
  232. package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -69
  233. package/skills/void/docs/reference/api/auth.md +156 -0
  234. package/skills/void/docs/reference/api/client.md +87 -0
  235. package/skills/void/docs/reference/api/database.md +95 -0
  236. package/skills/void/docs/reference/api/durable.md +46 -0
  237. package/skills/void/docs/reference/api/env.md +50 -0
  238. package/skills/void/docs/reference/api/handlers.md +254 -0
  239. package/skills/void/docs/reference/api/pages.md +241 -0
  240. package/skills/void/docs/reference/api/plugin.md +39 -0
  241. package/skills/void/docs/reference/api/resources.md +109 -0
  242. package/skills/void/docs/reference/api/rewrites.md +76 -0
  243. package/skills/void/docs/reference/api/types.md +92 -0
  244. package/skills/void/docs/reference/api.md +56 -1218
  245. package/skills/void/docs/reference/cli/auth.md +88 -0
  246. package/skills/void/docs/reference/cli/database.md +128 -0
  247. package/skills/void/docs/reference/cli/deploy.md +85 -0
  248. package/skills/void/docs/reference/cli/domains.md +41 -0
  249. package/skills/void/docs/reference/cli/email.md +129 -0
  250. package/skills/void/docs/reference/cli/generate.md +116 -0
  251. package/skills/void/docs/reference/cli/github.md +189 -0
  252. package/skills/void/docs/reference/cli/platform-config.md +92 -0
  253. package/skills/void/docs/reference/cli/platform-email.md +81 -0
  254. package/skills/void/docs/reference/cli/platform-installation.md +127 -0
  255. package/skills/void/docs/reference/cli/platform-operations.md +90 -0
  256. package/skills/void/docs/reference/cli/platform-users.md +89 -0
  257. package/skills/void/docs/reference/cli/platform-zero-trust.md +45 -0
  258. package/skills/void/docs/reference/cli/platform.md +70 -0
  259. package/skills/void/docs/reference/cli/project.md +214 -0
  260. package/skills/void/docs/reference/cli/secrets.md +76 -0
  261. package/skills/void/docs/reference/cli/setup.md +70 -0
  262. package/skills/void/docs/reference/cli.md +32 -1682
  263. package/skills/void/docs/reference/config.md +12 -18
  264. package/skills/void/docs/reference/resource-inference.md +3 -58
  265. package/skills/void/docs/reference/structure.md +14 -41
  266. package/dist/canonical-json-DuDiiUsQ.mjs +0 -13
  267. package/dist/client-Czz8o5jP.mjs +0 -2
  268. package/dist/gen-CNJ62MM7.mjs +0 -2
  269. package/dist/help-CmZzxUba.mjs +0 -2
  270. package/dist/login-CGcRKEoi.mjs +0 -2
  271. package/dist/migrate-CYfbKkXh.mjs +0 -2
  272. package/dist/plan-BEZ8VJW0.mjs +0 -256
  273. package/dist/plan-DpuOr14e.mjs +0 -2
  274. package/dist/prepare-Bm3iq-u4.mjs +0 -2
  275. package/dist/validate-EKmJWxmy.mjs +0 -2
  276. /package/dist/cli/{cf-compat.d.mts → cloudflare-operation-process.d.mts} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { t as cfAccessHeaders } from "../cf-access-DRsQRe6k.mjs";
2
2
  import { a as getRawRuntimeEnv } from "../env-raw-Cx8ElDdj.mjs";
3
+ import { a as readUsageLimit, i as limitOperation, r as limitFromResponse, t as UsageLimit } from "../limits-Cjuk2VPm.mjs";
3
4
  //#region src/runtime/ai-types.ts
4
5
  /** Maps provider prefix to expected env var name for the API key */
5
6
  const PROVIDER_KEY_MAP = {
@@ -315,6 +316,8 @@ function makeServiceBindingBackend(proxy, runtimeEnv) {
315
316
  ...body
316
317
  })
317
318
  });
319
+ const limit = await limitFromResponse(res, "ai");
320
+ if (limit) throw limit;
318
321
  if (options.throwOnError !== false && !res.ok) {
319
322
  const text = await res.text();
320
323
  throw new Error(`ai: Proxy request failed with ${res.status}: '${text}'.`);
@@ -395,6 +398,8 @@ function makeHttpBackend(token, projectId, runtimeEnv) {
395
398
  }),
396
399
  redirect: "manual"
397
400
  });
401
+ const limit = await limitFromResponse(res, "ai");
402
+ if (limit) throw limit;
398
403
  if (options.throwOnError !== false && !res.ok) {
399
404
  const text = await res.text();
400
405
  throw new Error(`ai: Proxy request failed with ${res.status}: '${text}'.`);
@@ -434,11 +439,24 @@ function makeHttpBackend(token, projectId, runtimeEnv) {
434
439
  };
435
440
  }
436
441
  function makeDirectBackend(directAi, runtimeEnv, gatewayId) {
442
+ const run = async (model, inputs, options) => {
443
+ const opts = options ?? {};
444
+ const response = await directAi.run(model, inputs, {
445
+ ...opts,
446
+ returnRawResponse: true
447
+ });
448
+ if (!(response instanceof Response)) return response;
449
+ const limit = await limitFromResponse(response, "ai");
450
+ if (limit) throw limit;
451
+ if (opts.returnRawResponse || opts.websocket) return response;
452
+ if (!response.ok) throw new Error(`ai: Request failed with ${response.status}: '${await response.text()}'.`);
453
+ return isJsonMediaType(mediaTypeFromContentType(response.headers.get("content-type"))) ? response.json() : response.body;
454
+ };
437
455
  return {
438
- run: directAi.run.bind(directAi),
456
+ run,
439
457
  async image(model, inputs, options) {
440
458
  const { runOptions } = splitImageOptions(options);
441
- return responseFromResult(await directAi.run(model, inputs, runOptions));
459
+ return responseFromResult(await run(model, inputs, runOptions));
442
460
  },
443
461
  async providerFetch(provider, path, init, options) {
444
462
  if (!gatewayId) return Response.json({ error: "ai: ai.provider().fetch() needs an AI Gateway when self-hosting. Set \"ai\": { \"gateway\": \"<id>\" } in void.json." }, { status: 501 });
@@ -474,22 +492,71 @@ let _backend;
474
492
  function backend() {
475
493
  return _backend ??= resolveBackend();
476
494
  }
495
+ /** Normalize provider 429 responses and binding quota failures before they reach callers. */
496
+ function aiOperation(execute, rawStream = false) {
497
+ return limitOperation(async () => {
498
+ const value = await execute();
499
+ if (value instanceof Response) {
500
+ const limit = await limitFromResponse(value, "ai");
501
+ if (limit) throw limit;
502
+ }
503
+ return value;
504
+ }, classifyAiLimit, (value, limited) => {
505
+ if (value instanceof Response && value.body && value.headers.get("content-type")?.includes("text/event-stream")) return new Response(streamResponse(value.body, limited).body, value);
506
+ if (rawStream && value instanceof ReadableStream) return streamResponse(value, limited).body;
507
+ return value;
508
+ });
509
+ }
510
+ function classifyAiLimit(error) {
511
+ if (error instanceof UsageLimit) return error;
512
+ const e = error;
513
+ return e && (e.status === 429 || e.statusCode === 429 || e.response?.status === 429) ? new UsageLimit({
514
+ resource: "ai",
515
+ reason: "rate_limit",
516
+ message: "AI usage limit exceeded."
517
+ }) : null;
518
+ }
519
+ /** Streaming failures after headers are sent end with an explicit terminal SSE event. */
520
+ function streamResponse(body, limited) {
521
+ const reader = body.getReader();
522
+ return new Response(new ReadableStream({
523
+ async pull(controller) {
524
+ try {
525
+ const chunk = await reader.read();
526
+ if (chunk.done) controller.close();
527
+ else controller.enqueue(chunk.value);
528
+ } catch (error) {
529
+ const limit = classifyAiLimit(error);
530
+ let data = { message: "Generation was interrupted. Please try again." };
531
+ if (limit) {
532
+ data = await limit.response().json();
533
+ try {
534
+ const fallback = await limited(limit);
535
+ if (fallback instanceof Response) data = readUsageLimit(await fallback.json().catch(() => null)) ?? data;
536
+ } catch {}
537
+ }
538
+ controller.enqueue(new TextEncoder().encode(`event: ${limit ? "void:limit" : "void:error"}\ndata: ${JSON.stringify(data)}\n\n`));
539
+ controller.close();
540
+ }
541
+ },
542
+ cancel(reason) {
543
+ return reader.cancel(reason);
544
+ }
545
+ }), { headers: {
546
+ "content-type": "text/event-stream",
547
+ "cache-control": "no-cache"
548
+ } });
549
+ }
477
550
  const ai = new Proxy({}, { get(_, prop) {
478
- if (prop === "stream") return async (model, inputs, options) => {
479
- const body = await backend().run(model, {
480
- ...inputs,
481
- stream: true
482
- }, options);
483
- return new Response(body, { headers: {
484
- "content-type": "text/event-stream",
485
- "cache-control": "no-cache"
486
- } });
487
- };
488
- if (prop === "run") return backend().run;
489
- if (prop === "image") return backend().image;
490
- if (prop === "provider") return (provider, options) => ({ fetch: (path, init) => backend().providerFetch(provider, path, init, options) });
491
- if (prop === "models") return backend().models;
492
- if (prop === "toMarkdown") return backend().toMarkdown;
551
+ if (prop === "stream") return (model, inputs, options) => aiOperation(async () => new Response(await backend().run(model, {
552
+ ...inputs,
553
+ stream: true
554
+ }, options), { headers: {
555
+ "content-type": "text/event-stream",
556
+ "cache-control": "no-cache"
557
+ } }));
558
+ if (prop === "provider") return (provider, options) => ({ fetch: (path, init) => aiOperation(() => backend().providerFetch(provider, path, init, options)) });
559
+ if (prop === "run" || prop === "image" || prop === "models" || prop === "toMarkdown") return (...args) => aiOperation(() => backend()[prop](...args), prop === "run" && hasStreamFlag(args[1]) && args[1].stream === true);
493
560
  } });
494
561
  //#endregion
495
562
  export { ai };
@@ -1,5 +1,5 @@
1
1
  import { t as applyMySqlAuthMigrations } from "../auth-migrations-9vif1uj8.mjs";
2
- import { t as createVoidAuthRuntime } from "../better-auth-shared-rsBGBvWJ.mjs";
2
+ import { t as createVoidAuthRuntime } from "../better-auth-shared-hy6RPh9W.mjs";
3
3
  //#region src/runtime/better-auth-mysql.ts
4
4
  function resolveConnectionString(env) {
5
5
  const connectionString = typeof env.DATABASE_URL === "string" && env.DATABASE_URL.length > 0 ? env.DATABASE_URL : typeof env.HYPERDRIVE?.connectionString === "string" && env.HYPERDRIVE.connectionString.length > 0 ? env.HYPERDRIVE.connectionString : void 0;
@@ -1,5 +1,5 @@
1
1
  import { n as applyPgAuthMigrations } from "../auth-migrations-9vif1uj8.mjs";
2
- import { t as createVoidAuthRuntime } from "../better-auth-shared-rsBGBvWJ.mjs";
2
+ import { t as createVoidAuthRuntime } from "../better-auth-shared-hy6RPh9W.mjs";
3
3
  import { t as disablePgPassFallback } from "../pg-J2HbZIkX.mjs";
4
4
  //#region src/runtime/better-auth-pg.ts
5
5
  function resolveConnectionString(env) {
@@ -1,5 +1,5 @@
1
1
  import { r as applySqliteAuthMigrations } from "../auth-migrations-9vif1uj8.mjs";
2
- import { t as createVoidAuthRuntime } from "../better-auth-shared-rsBGBvWJ.mjs";
2
+ import { t as createVoidAuthRuntime } from "../better-auth-shared-hy6RPh9W.mjs";
3
3
  //#region src/runtime/better-auth.ts
4
4
  async function resolveDatabase(env) {
5
5
  if (!env.DB) throw new Error("auth: Better Auth requires the \"DB\" D1 binding for sqlite apps.");
@@ -1,5 +1,5 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
3
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
4
4
  import { n as createAuthClient, t as auth } from "../auth-client-react-CMLwT2xI.mjs";
5
5
  export { FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,5 +1,5 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
3
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
4
4
  import { n as createAuthClient, t as auth } from "../auth-client-solid-UoreJWZG.mjs";
5
5
  export { FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,5 +1,5 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
3
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
4
4
  import { n as createAuthClient, t as auth } from "../auth-client-svelte-Cv_WvrRk.mjs";
5
5
  export { FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,5 +1,5 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
3
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
4
4
  import { n as createAuthClient, t as auth } from "../auth-client-vue-CFk7Xbv3.mjs";
5
5
  export { FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -1,5 +1,5 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
3
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
4
4
  import { n as createAuthClient, t as auth } from "../auth-client-BWBT8HLp.mjs";
5
5
  export { FetchError, FetchError as StreamError, auth, createAuthClient, fetch, fetchStream };
@@ -25,6 +25,8 @@ export type DurableStateClass<TMethods> = {
25
25
  };
26
26
  };
27
27
  export type DurableStateDefinition<TState, TEnv extends Record<string, unknown>, TMethods extends DurableStateMethods<TState, TEnv>> = {
28
+ /** Optional persistent resource name. Pin the name reported by `void info` before moving this definition. */
29
+ name?: string;
28
30
  initialState: TState | ((env: TEnv) => TState | Promise<TState>);
29
31
  /** Current persisted state version. Defaults to 0. */
30
32
  version?: number;
@@ -37,7 +39,7 @@ export type DurableStateDefinition<TState, TEnv extends Record<string, unknown>,
37
39
  export type DurableStateApi<TMethods> = {
38
40
  class: DurableStateClass<TMethods>;
39
41
  /** @internal Called by Void's generated worker entry. */
40
- __bind(bindingName: string): void;
42
+ __bind(bindingName: string, resourceName?: string): void;
41
43
  get(name: string): TypedDurableObjectStub<TMethods>;
42
44
  get(namespace: DurableObjectNamespace, name: string): TypedDurableObjectStub<TMethods>;
43
45
  getById(id: DurableObjectId): TypedDurableObjectStub<TMethods>;
@@ -1,3 +1,4 @@
1
+ import { t as isResourceName } from "../resource-name-C7LVpcRm.mjs";
1
2
  import { a as requireRuntimeBinding, o as withRuntimeEnv } from "../env-D5liuQYR.mjs";
2
3
  import { DurableObject } from "cloudflare:workers";
3
4
  //#region src/runtime/durable.ts
@@ -17,6 +18,7 @@ function assertMigrations(version, migrations) {
17
18
  return byVersion;
18
19
  }
19
20
  function defineDurableState(definition) {
21
+ if (definition.name !== void 0 && !isResourceName(definition.name)) throw new Error("durable: name must contain a word starting with a letter.");
20
22
  const version = definition.version ?? 0;
21
23
  if (!Number.isInteger(version) || version < 0) throw new Error("durable: version must be a non-negative integer.");
22
24
  const migrations = assertMigrations(version, definition.migrations ?? []);
@@ -126,7 +128,8 @@ function defineDurableState(definition) {
126
128
  }
127
129
  return {
128
130
  class: VoidDurableState,
129
- __bind(name) {
131
+ __bind(name, resourceName) {
132
+ if (definition.name !== resourceName) throw new Error("durable: name must be statically discoverable in defineDurableState(). Run void info to inspect this definition.");
130
133
  if (bindingName && bindingName !== name) throw new Error(`durable: state definition is already bound to '${bindingName}' and cannot also bind to '${name}'.`);
131
134
  bindingName = name;
132
135
  },
@@ -1,6 +1,6 @@
1
1
  import { i as normalizeEmail, r as buildMime } from "../../mime-D5Nmdzf7.mjs";
2
- import { y as registerEmailSink } from "../../dev-inbox-P0u4tM8Y.mjs";
3
2
  import { n as compileEmailPattern, t as compareEmailRoutes } from "../../email--tEtMoj_.mjs";
3
+ import { y as registerEmailSink } from "../../dev-inbox-P0u4tM8Y.mjs";
4
4
  import { i as createMessageProxy, n as MAX_INBOUND_HEADERS, t as MAX_INBOUND_BYTES } from "../../inbound-aVHEUhKo.mjs";
5
5
  //#region src/runtime/email/testing.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import { a as number, c as url, i as json, n as boolean, o as oneOf, r as email, s as string, t as EnvSchema } from "../env-helpers-CyKtOBpj.mjs";
3
- import { a as _getSchemaDefaults, c as defineEnv, i as _getRegisteredSchema, l as env, n as EnvValidationReport, o as _hasRegisteredSchema, r as ValidatedEnv, s as _validateEnvOnce, t as EnvValidationError, u as validateAllEnv } from "../env-public-BxU_0yTL.mjs";
3
+ import { a as _getSchemaDefaults, c as defineEnv, i as _getRegisteredSchema, l as env, n as EnvValidationReport, o as _hasRegisteredSchema, r as ValidatedEnv, s as _validateEnvOnce, t as EnvValidationError, u as validateAllEnv } from "../env-public-BX_r8HR6.mjs";
4
4
  export { type EnvSchema, EnvValidationError, EnvValidationReport, ValidatedEnv, _getRegisteredSchema, _getSchemaDefaults, _hasRegisteredSchema, _validateEnvOnce, boolean, defineEnv, email, env, json, number, oneOf, string, url, validateAllEnv };
@@ -1,3 +1,3 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetchStream } from "../fetch-stream-AOByI7Ki.mjs";
2
+ import { t as fetchStream } from "../fetch-stream-IvCYKyQL.mjs";
3
3
  export { FetchError as StreamError, fetchStream };
@@ -1,3 +1,3 @@
1
1
  import { t as FetchError } from "../fetch-error-Dj3crt0e.mjs";
2
- import { t as fetch } from "../fetch-CXDChK7B.mjs";
2
+ import { t as fetch } from "../fetch-BIZJh7vR.mjs";
3
3
  export { FetchError, fetch };
@@ -1,3 +1,3 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { C as defer, E as ValidatorSlots, S as InferProps, T as HandlerInput, _ as defineQueue, a as CloudEnv, b as Deferred, c as QueueRetryOptions, d as TypedQueueHandler, f as VoidAssetRewriteError, g as defineMiddleware, h as defineHead, i as CloudContextVariables, l as RenderAssetTags, m as defineHandler, n as CloudBindings, o as QueueBatch, p as basicAuth, r as CloudContext, s as QueueMessage, t as BasicAuthOptions, u as TypedHandler, v as defineRender, w as ValidationError, y as defineScheduled } from "../handler-HEcZsaij.mjs";
2
+ import { C as defer, E as ValidatorSlots, S as InferProps, T as HandlerInput, _ as defineQueue, a as CloudEnv, b as Deferred, c as QueueRetryOptions, d as TypedQueueHandler, f as VoidAssetRewriteError, g as defineMiddleware, h as defineHead, i as CloudContextVariables, l as RenderAssetTags, m as defineHandler, n as CloudBindings, o as QueueBatch, p as basicAuth, r as CloudContext, s as QueueMessage, t as BasicAuthOptions, u as TypedHandler, v as defineRender, w as ValidationError, y as defineScheduled } from "../handler-CZ4nAylQ.mjs";
3
3
  export { BasicAuthOptions, CloudBindings, CloudContext, CloudContextVariables, CloudEnv, type Deferred, type HandlerInput, type InferProps, QueueBatch, QueueMessage, QueueRetryOptions, RenderAssetTags, TypedHandler, TypedQueueHandler, ValidationError, type ValidatorSlots, VoidAssetRewriteError, basicAuth, defer, defineHandler, defineHead, defineMiddleware, defineQueue, defineRender, defineScheduled };
@@ -9,7 +9,6 @@ function parseValue(raw) {
9
9
  }
10
10
  }
11
11
  function serializeValue(value) {
12
- if (typeof value === "string") return value;
13
12
  return JSON.stringify(value);
14
13
  }
15
14
  function getListCursor(result) {
@@ -0,0 +1,2 @@
1
+ import { a as asUsageLimit, c as readUsageLimit, i as UsageLimitData, n as LimitOperation, o as limitFromResponse, r as UsageLimit, s as limitOperation, t as LimitHandlers } from "../limits-Bq5LG8Id.mjs";
2
+ export { LimitHandlers, LimitOperation, UsageLimit, type UsageLimitData, asUsageLimit, limitFromResponse, limitOperation, readUsageLimit };
@@ -0,0 +1,2 @@
1
+ import { a as readUsageLimit, i as limitOperation, n as asUsageLimit, r as limitFromResponse, t as UsageLimit } from "../limits-Cjuk2VPm.mjs";
2
+ export { UsageLimit, asUsageLimit, limitFromResponse, limitOperation, readUsageLimit };
@@ -1,4 +1,4 @@
1
- import { t as LiveClientEvent } from "../live-CKJlvlNp.mjs";
1
+ import { t as LiveClientEvent } from "../live-Chw1eIMv.mjs";
2
2
  //#region src/runtime/live-client.d.ts
3
3
  export type LiveSubscribeOptions<Data = unknown> = {
4
4
  id: string;
@@ -1,4 +1,4 @@
1
- import { n as eventStream } from "../sse-BaC1jXko.mjs";
1
+ import { n as eventStream } from "../sse-CQNaDFFV.mjs";
2
2
  import { t as __getLiveBindingName } from "../live-CB1y5IuC.mjs";
3
3
  //#region src/runtime/live-server.ts
4
4
  const GENERATION_KEY = "connection:generation";
@@ -42,16 +42,18 @@ function createLiveDurableObject() {
42
42
  if (previous) {
43
43
  const active = [...previous.subscriptions.values()].filter((sub) => sub.active);
44
44
  for (const subscription of previous.subscriptions.values()) subscription.active = false;
45
- await previous.stream.close().catch(() => {});
45
+ previous.abort.abort();
46
46
  await Promise.all(active.map((sub) => this.unregisterTopic(message.streamId, message.connectionId, sub)));
47
47
  }
48
48
  const generation = (await this.state.storage.get(GENERATION_KEY) ?? 0) + 1;
49
49
  await this.state.storage.put(GENERATION_KEY, generation);
50
+ const abort = new AbortController();
50
51
  return eventStream(async (stream) => {
51
52
  const subscriptions = previous?.owner === message.owner ? previous.subscriptions : /* @__PURE__ */ new Map();
52
53
  for (const subscription of subscriptions.values()) subscription.active = false;
53
54
  this.connection = {
54
55
  stream,
56
+ abort,
55
57
  owner: message.owner,
56
58
  generation,
57
59
  subscriptions,
@@ -59,17 +61,22 @@ function createLiveDurableObject() {
59
61
  queued: 0,
60
62
  limits: message.limits
61
63
  };
62
- await stream.comment("connected");
63
- await stream.closed;
64
- if (this.connection?.generation === generation) {
65
- const active = [...this.connection.subscriptions.values()].filter((sub) => sub.active);
66
- this.connection = null;
64
+ try {
65
+ await stream.comment("connected");
66
+ await stream.closed;
67
+ } finally {
68
+ const active = [...subscriptions.values()].filter((sub) => sub.active && sub.generation === generation);
69
+ for (const sub of active) sub.active = false;
70
+ if (this.connection?.generation === generation) this.connection = null;
67
71
  await Promise.all(active.map((sub) => this.unregisterTopic(message.streamId, message.connectionId, sub)));
68
72
  }
69
- }, { keepAlive: {
70
- intervalMs: 15e3,
71
- comment: "keep-alive"
72
- } });
73
+ }, {
74
+ signal: abort.signal,
75
+ keepAlive: {
76
+ intervalMs: 15e3,
77
+ comment: "keep-alive"
78
+ }
79
+ });
73
80
  }
74
81
  async control(message) {
75
82
  const connection = this.connection;
@@ -174,8 +181,8 @@ function createLiveDurableObject() {
174
181
  continue;
175
182
  }
176
183
  if (connection.queued >= connection.limits.maxQueuedEventsPerConnection) {
177
- await connection.stream.close().catch(() => {});
178
- this.connection = null;
184
+ connection.abort.abort();
185
+ if (this.connection === connection) this.connection = null;
179
186
  return new Response("connection queue full", { status: 410 });
180
187
  }
181
188
  const event = {
@@ -193,7 +200,7 @@ function createLiveDurableObject() {
193
200
  data: event
194
201
  })).catch(() => {
195
202
  if (this.connection === activeConnection) this.connection = null;
196
- connection.stream.close().catch(() => {});
203
+ connection.abort.abort();
197
204
  }).finally(() => {
198
205
  connection.queued--;
199
206
  });
@@ -275,7 +282,8 @@ function createLiveDurableObject() {
275
282
  if (outcome.status === "rejected") throw outcome.reason;
276
283
  const response = outcome.value;
277
284
  const items = batch[index][1];
278
- if (!response || response.status === 410 || response.status === 404) {
285
+ if (!response) continue;
286
+ if (response.status === 410 || response.status === 404) {
279
287
  await this.state.storage.delete(items.map((item) => item.key));
280
288
  continue;
281
289
  }
@@ -316,7 +324,8 @@ function createLiveDurableObject() {
316
324
  if (outcome.status === "rejected") throw outcome.reason;
317
325
  const response = outcome.value;
318
326
  const items = batch[index][1];
319
- if (!response || response.status === 410 || response.status === 404) {
327
+ if (!response) continue;
328
+ if (response.status === 410 || response.status === 404) {
320
329
  staleKeys.push(...items.map((item) => item.key));
321
330
  continue;
322
331
  }
@@ -1,3 +1,3 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
- import { _ as __getLiveBindingName, a as LiveControlErrorCode, c as LiveControlOptions, d as LiveHookContext, f as LiveLimits, g as LiveSubscribeHookContext, h as LiveStreamOptions, i as LiveControlError, l as LiveControlRequest, m as LiveStream, n as LiveConnectHookContext, o as LiveControlOperation, p as LivePublishOptions, r as LiveConnectOptions, s as LiveControlOperationResult, t as LiveClientEvent, u as LiveControlResponse, v as __setLiveBindingName, y as defineLiveStream } from "../live-CKJlvlNp.mjs";
2
+ import { _ as __getLiveBindingName, a as LiveControlErrorCode, c as LiveControlOptions, d as LiveHookContext, f as LiveLimits, g as LiveSubscribeHookContext, h as LiveStreamOptions, i as LiveControlError, l as LiveControlRequest, m as LiveStream, n as LiveConnectHookContext, o as LiveControlOperation, p as LivePublishOptions, r as LiveConnectOptions, s as LiveControlOperationResult, t as LiveClientEvent, u as LiveControlResponse, v as __setLiveBindingName, y as defineLiveStream } from "../live-Chw1eIMv.mjs";
3
3
  export { LiveClientEvent, LiveConnectHookContext, LiveConnectOptions, LiveControlError, LiveControlErrorCode, LiveControlOperation, LiveControlOperationResult, LiveControlOptions, LiveControlRequest, LiveControlResponse, LiveHookContext, LiveLimits, LivePublishOptions, LiveStream, LiveStreamOptions, LiveSubscribeHookContext, __getLiveBindingName, __setLiveBindingName, defineLiveStream };
@@ -1,4 +1,4 @@
1
- import { t as canonicalJson } from "../canonical-json-DuDiiUsQ.mjs";
1
+ import { canonicalJson } from "@void/deploy-core";
2
2
  //#region src/runtime/migration-handler.ts
3
3
  const SUPPORTED_CLASSIFIER_VERSION = 1;
4
4
  function createMigrationHandler(env, migrations, _dialect, runAuthMigrations, planBundle) {
@@ -85,7 +85,8 @@ async function createTrackingTable(db) {
85
85
  )`).run();
86
86
  }
87
87
  async function createAttemptTables(db) {
88
- await db.batch([db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_attempts (
88
+ await db.batch([
89
+ db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_attempts (
89
90
  attempt_id TEXT PRIMARY KEY,
90
91
  deployment_id TEXT,
91
92
  migration_list_hash TEXT NOT NULL,
@@ -95,16 +96,23 @@ async function createAttemptTables(db) {
95
96
  started_at TEXT NOT NULL,
96
97
  completed_at TEXT,
97
98
  error TEXT
98
- )`), db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_lock (
99
+ )`),
100
+ db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_lock (
99
101
  name TEXT PRIMARY KEY,
100
102
  attempt_id TEXT NOT NULL,
101
103
  acquired_at TEXT NOT NULL
102
- )`)]);
104
+ )`),
105
+ db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_fences (
106
+ attempt_id TEXT PRIMARY KEY,
107
+ owned INTEGER NOT NULL CHECK (owned = 1)
108
+ )`)
109
+ ]);
103
110
  }
104
- async function upgradeTrackingTable(db) {
111
+ async function upgradeTrackingTable(db, fencedAttemptId) {
105
112
  const { results } = await db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='_migrations'").all();
106
113
  if (!results || results.length === 0) return;
107
114
  await db.batch([
115
+ ...ownershipFence(db, fencedAttemptId),
108
116
  db.prepare(`CREATE TABLE IF NOT EXISTS _void_migrations (
109
117
  name TEXT PRIMARY KEY,
110
118
  applied_at TEXT NOT NULL
@@ -121,18 +129,13 @@ async function runD1AppMigrations(db, migrations, planBundle, attempt) {
121
129
  const verified = await verifyPlanBundle(migrations, planBundle);
122
130
  await createAttemptTables(db);
123
131
  const now = (/* @__PURE__ */ new Date()).toISOString();
124
- const lock = await acquireAttemptLock(db, attempt.attemptId, now);
125
- if (lock !== "acquired") return lock;
126
132
  const plannedNames = migrations.map((migration) => migration.name);
127
133
  const planHashes = verified.plans.map((plan) => plan.planHash);
128
- try {
129
- await db.prepare(`INSERT INTO _void_migration_attempts
134
+ const fenced = verified.plans.every((plan) => plan.kind !== "legacy-unsplit-multi-statement");
135
+ const lock = await acquireAttemptLock(db, attempt.attemptId, now, [db.prepare(`INSERT INTO _void_migration_attempts
130
136
  (attempt_id, deployment_id, migration_list_hash, planned_names_json, plan_hashes_json, status, started_at)
131
- VALUES (?, ?, ?, ?, ?, 'running', ?)`).bind(attempt.attemptId, attempt.deploymentId ?? null, verified.migrationListHash, JSON.stringify(plannedNames), JSON.stringify(planHashes), now).run();
132
- } catch {
133
- await releaseAttemptLock(db, attempt.attemptId);
134
- return reconcileAttempt(db, attempt.attemptId);
135
- }
137
+ VALUES (?, ?, ?, ?, ?, 'running', ?)`).bind(attempt.attemptId, attempt.deploymentId ?? null, verified.migrationListHash, JSON.stringify(plannedNames), JSON.stringify(planHashes), now), ...fenced ? [db.prepare("INSERT INTO _void_migration_fences (attempt_id, owned) VALUES (?, 1)").bind(attempt.attemptId)] : []]);
138
+ if (lock !== "acquired") return lock;
136
139
  const migrationResults = [];
137
140
  const confirmedApplied = [];
138
141
  const confirmedSkipped = [];
@@ -140,7 +143,7 @@ async function runD1AppMigrations(db, migrations, planBundle, attempt) {
140
143
  let stability = "stable";
141
144
  try {
142
145
  await createTrackingTable(db);
143
- await upgradeTrackingTable(db);
146
+ await upgradeTrackingTable(db, fenced ? attempt.attemptId : void 0);
144
147
  const applied = await readAppliedSet(db);
145
148
  for (let index = 0; index < migrations.length; index++) {
146
149
  const migration = migrations[index];
@@ -159,7 +162,7 @@ async function runD1AppMigrations(db, migrations, planBundle, attempt) {
159
162
  }
160
163
  const start = Date.now();
161
164
  try {
162
- await executeMigrationPlan(db, migration, plan);
165
+ await executeMigrationPlan(db, migration, plan, fenced ? attempt.attemptId : void 0);
163
166
  applied.add(migration.name);
164
167
  confirmedApplied.push(migration.name);
165
168
  migrationResults.push({
@@ -223,16 +226,16 @@ async function runD1AppMigrations(db, migrations, planBundle, attempt) {
223
226
  };
224
227
  }
225
228
  }
226
- async function acquireAttemptLock(db, attemptId, acquiredAt) {
229
+ async function acquireAttemptLock(db, attemptId, acquiredAt, initialize) {
227
230
  for (let tries = 0; tries < 2; tries++) try {
228
- await db.prepare("INSERT INTO _void_migration_lock (name, attempt_id, acquired_at) VALUES (?, ?, ?)").bind("app", attemptId, acquiredAt).run();
231
+ await db.batch([db.prepare("INSERT INTO _void_migration_lock (name, attempt_id, acquired_at) VALUES (?, ?, ?)").bind("app", attemptId, acquiredAt), ...initialize]);
229
232
  return "acquired";
230
233
  } catch {
231
234
  const existing = await db.prepare("SELECT attempt_id FROM _void_migration_lock WHERE name = ?").bind("app").first();
232
- if (existing?.attempt_id === attemptId) return reconcileAttempt(db, attemptId);
235
+ if (!existing && await readAttempt(db, attemptId)) return reconcileAttempt(db, attemptId, false);
233
236
  if (existing?.attempt_id) {
234
237
  const row = await readAttempt(db, existing.attempt_id);
235
- if (!row || row.status === "completed" || row.status === "failed" || row.status === "unknown") {
238
+ if (row?.status === "completed" || row?.status === "failed") {
236
239
  await releaseAttemptLock(db, existing.attempt_id).catch(() => {});
237
240
  continue;
238
241
  }
@@ -253,23 +256,41 @@ async function acquireAttemptLock(db, attemptId, acquiredAt) {
253
256
  error: "migration lock could not be acquired"
254
257
  };
255
258
  }
256
- async function executeMigrationPlan(db, migration, plan) {
259
+ async function executeMigrationPlan(db, migration, plan, fencedAttemptId) {
257
260
  const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
258
261
  if (plan.kind === "single-statement") {
259
- await db.batch([db.prepare(migration.sql), db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)]);
262
+ await db.batch([
263
+ ...ownershipFence(db, fencedAttemptId),
264
+ db.prepare(migration.sql),
265
+ db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)
266
+ ]);
260
267
  return;
261
268
  }
262
269
  if (plan.kind === "breakpoint-framed") {
263
- await db.batch([...plan.statements.map((statement) => db.prepare(statement)), db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)]);
270
+ await db.batch([
271
+ ...ownershipFence(db, fencedAttemptId),
272
+ ...plan.statements.map((statement) => db.prepare(statement)),
273
+ db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)
274
+ ]);
264
275
  return;
265
276
  }
266
277
  await db.exec(migration.sql);
267
278
  await db.prepare("INSERT OR IGNORE INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt).run();
268
279
  }
269
- async function markAttempt(db, attemptId, status, error) {
270
- await db.prepare(`UPDATE _void_migration_attempts
280
+ /** Fail the whole D1 batch if recovery has revoked this executor's ownership. */
281
+ function ownershipFence(db, attemptId) {
282
+ if (!attemptId) return [];
283
+ return [db.prepare(`INSERT INTO _void_migration_fences (attempt_id, owned)
284
+ VALUES (?, EXISTS(SELECT 1 FROM _void_migration_lock WHERE name = 'app' AND attempt_id = ?))
285
+ ON CONFLICT(attempt_id) DO UPDATE SET owned = excluded.owned`).bind(attemptId, attemptId)];
286
+ }
287
+ function attemptUpdate(db, attemptId, status, error) {
288
+ return db.prepare(`UPDATE _void_migration_attempts
271
289
  SET status = ?, completed_at = ?, error = ?
272
- WHERE attempt_id = ?`).bind(status, (/* @__PURE__ */ new Date()).toISOString(), error ?? null, attemptId).run();
290
+ WHERE attempt_id = ? AND status ${status === "completed" ? "IN ('running', 'unknown')" : "= 'running'"}`).bind(status, (/* @__PURE__ */ new Date()).toISOString(), error ?? null, attemptId);
291
+ }
292
+ async function markAttempt(db, attemptId, status, error) {
293
+ await attemptUpdate(db, attemptId, status, error).run();
273
294
  }
274
295
  async function releaseAttemptLock(db, attemptId) {
275
296
  await db.prepare("DELETE FROM _void_migration_lock WHERE name = ? AND attempt_id = ?").bind("app", attemptId).run();
@@ -277,27 +298,26 @@ async function releaseAttemptLock(db, attemptId) {
277
298
  async function readAttempt(db, attemptId) {
278
299
  return db.prepare("SELECT * FROM _void_migration_attempts WHERE attempt_id = ?").bind(attemptId).first();
279
300
  }
280
- async function reconcileAttempt(db, attemptId) {
301
+ async function reconcileAttempt(db, attemptId, recover = true) {
281
302
  await createAttemptTables(db);
282
303
  await createTrackingTable(db);
283
304
  const row = await readAttempt(db, attemptId);
284
- if (!row) {
285
- await releaseAttemptLock(db, attemptId).catch(() => {});
286
- return {
287
- ok: false,
288
- protocolVersion: 2,
289
- attemptId,
290
- migrations: [],
291
- error: "migration attempt not found"
292
- };
293
- }
305
+ if (!row) return {
306
+ ok: false,
307
+ protocolVersion: 2,
308
+ attemptId,
309
+ migrations: [],
310
+ error: "migration attempt not found"
311
+ };
312
+ const fenced = await db.prepare("SELECT attempt_id FROM _void_migration_fences WHERE attempt_id = ?").bind(attemptId).first();
313
+ if (recover && fenced) await db.batch([attemptUpdate(db, attemptId, "unknown", "migration outcome unknown"), db.prepare("DELETE FROM _void_migration_lock WHERE name = ? AND attempt_id = ?").bind("app", attemptId)]);
294
314
  const plannedNames = JSON.parse(row.planned_names_json);
295
315
  const applied = await readAppliedSet(db);
296
316
  const confirmed = plannedNames.filter((name) => applied.has(name));
297
317
  const complete = confirmed.length === plannedNames.length;
298
318
  if (complete && row.status !== "completed") await markAttempt(db, attemptId, "completed").catch(() => {});
299
- if (!complete && row.status === "running") await markAttempt(db, attemptId, "unknown", row.error ?? "migration outcome unknown").catch(() => {});
300
- await releaseAttemptLock(db, attemptId).catch(() => {});
319
+ const inProgress = !fenced && !complete && (row.status === "running" || row.status === "unknown");
320
+ if (complete || row.status === "completed" || row.status === "failed") await releaseAttemptLock(db, attemptId);
301
321
  return {
302
322
  ok: complete,
303
323
  protocolVersion: 2,
@@ -310,7 +330,7 @@ async function reconcileAttempt(db, attemptId) {
310
330
  name,
311
331
  status: applied.has(name) ? "skipped" : "failed"
312
332
  })),
313
- error: complete ? void 0 : row.error ?? "migration outcome unknown",
333
+ error: complete ? void 0 : inProgress ? `migration already in progress for attempt ${attemptId}; wait for this migration to finish before retrying recovery` : row.error ?? "migration outcome unknown",
314
334
  stability: "stable"
315
335
  };
316
336
  }
@@ -322,7 +342,7 @@ async function verifyPlanBundle(migrations, planBundle) {
322
342
  const migration = migrations[index];
323
343
  const plan = planBundle.plans[index];
324
344
  if (plan.name !== migration.name || plan.dialect !== "sqlite" || plan.classifierVersion !== SUPPORTED_CLASSIFIER_VERSION) throw new Error(`invalid migration execution plan for ${migration.name}`);
325
- const sqlHash = await sha256Hex(canonicalSql(migration.sql));
345
+ const sqlHash = await sha256Hex(canonicalSql$1(migration.sql));
326
346
  if (plan.sqlHash !== sqlHash) throw new Error(`migration SQL hash mismatch for ${migration.name}`);
327
347
  const planHash = await hashPlan(plan);
328
348
  if (plan.planHash !== planHash) throw new Error(`migration plan hash mismatch for ${migration.name}`);
@@ -335,7 +355,7 @@ async function verifyPlanBundle(migrations, planBundle) {
335
355
  if (planBundle.migrationListHash !== migrationListHash) throw new Error("migration list hash mismatch");
336
356
  return planBundle;
337
357
  }
338
- function canonicalSql(sql) {
358
+ function canonicalSql$1(sql) {
339
359
  return (sql.charCodeAt(0) === 65279 ? sql.slice(1) : sql).replace(/\r\n?/g, "\n");
340
360
  }
341
361
  async function sha256Hex(value) {