void 0.10.12 → 0.20.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 (431) hide show
  1. package/AGENTS_TEMPLATE.md +6 -0
  2. package/{skills/void/docs/node_modules/void/node_modules/pglite-server/LICENSE.md → LICENSE} +1 -1
  3. package/README.md +34 -8
  4. package/dist/{auth-qgMlYp7Z.d.mts → auth-DkcFflXV.d.mts} +10 -11
  5. package/dist/auth-W9WII-mN.mjs +630 -0
  6. package/dist/{auth-cmd-BqsdZJp5.mjs → auth-cmd-CYVhSNFy.mjs} +4 -3
  7. package/dist/{auth-migrations-BTZ-ATvQ.mjs → auth-migrations-9vif1uj8.mjs} +53 -12
  8. package/dist/{better-auth-shared-BQooDxbw.mjs → better-auth-shared-CYw1T3k4.mjs} +7 -10
  9. package/dist/{better-auth-shared-DealXecJ.d.mts → better-auth-shared-DSCeohOK.d.mts} +10 -5
  10. package/dist/{build-cmd-Bujrv5q-.mjs → build-cmd-CkVD1uOh.mjs} +6 -4
  11. package/dist/{cache-C11V8Fxq.mjs → cache-QcUfR-ff.mjs} +9 -5
  12. package/dist/{cancel-deploy-fwFYF04b.mjs → cancel-deploy-DsvWKFTe.mjs} +3 -2
  13. package/dist/cf-access-AJ1ehiFR.mjs +42 -0
  14. package/dist/cf-access-DsSsZUPr.mjs +67 -0
  15. package/dist/cli/cli.d.mts +1 -1
  16. package/dist/cli/cli.mjs +1592 -153
  17. package/dist/cli/env-schema-probe.d.mts +48 -61
  18. package/dist/cli/env-schema-probe.mjs +10 -58
  19. package/dist/{client-Gb71-XkG.mjs → client-CyCHWSO_.mjs} +61 -463
  20. package/dist/cloudflare-auth-DRkGe7-s.mjs +170 -0
  21. package/dist/cloudflare-cmd-D3ME2GAe.mjs +62 -0
  22. package/dist/cloudflare-connect-BivMefMA.mjs +56 -0
  23. package/dist/cloudflare-operations-CPTpRW6d.mjs +566 -0
  24. package/dist/{config-BkTvs43g.mjs → config-BQFq7QvD.mjs} +85 -41
  25. package/dist/{config-CutEMNGJ.mjs → config-NOG_U1aK.mjs} +10 -15
  26. package/dist/connect-D9Yr-T5f.mjs +79 -0
  27. package/dist/{create-project-DsYvl3TB.mjs → create-project-DMV-csEm.mjs} +26 -16
  28. package/dist/database-provider.d.mts +21 -0
  29. package/dist/database-provider.mjs +6 -0
  30. package/dist/{db-DOiJMRt2.mjs → db-BxoUWL0F.mjs} +600 -115
  31. package/dist/{delete-mh6p-zkQ.mjs → delete-iJOqxBz1.mjs} +9 -6
  32. package/dist/{deploy-u7Rv9q_q.mjs → deploy-CcDoeBIf.mjs} +3451 -1986
  33. package/dist/dev-inbox-DkgRWLkW.mjs +307 -0
  34. package/dist/{discover-CJHyvYfR.mjs → discover-xvfrgJeo.mjs} +3 -3
  35. package/dist/{magic-string.es-ZQjdJFFn.mjs → dist-BR1quN_w.mjs} +570 -216
  36. package/dist/{dist-DaKKDf8D.mjs → dist-BrsS7cai.mjs} +17 -2
  37. package/dist/{dist-BuiRJkTd.mjs → dist-m40_XgNh.mjs} +48 -33
  38. package/dist/{domain-DiaNQbrl.mjs → domain-gu_iaHmn.mjs} +41 -4
  39. package/dist/dotenv-VQxupEUv.mjs +181 -0
  40. package/dist/edge.d.mts +2 -0
  41. package/dist/edge.mjs +2 -0
  42. package/dist/email-Ce6SQq-i.mjs +182 -0
  43. package/dist/email-r6DHJyAB.mjs +262 -0
  44. package/dist/{entry-D7yy4xVH.mjs → entry-DU3oDoQ3.mjs} +2 -2
  45. package/dist/env-D4Emu-M_.mjs +95 -0
  46. package/dist/env-DmU2To0C.mjs +73 -0
  47. package/dist/env-helpers-CyKtOBpj.d.mts +22 -0
  48. package/dist/env-public-D_6u46fX.d.mts +135 -0
  49. package/dist/{env-types-QBj-ndax.mjs → env-types-BNPhro-M.mjs} +2 -2
  50. package/dist/{env-validation-Dea3v3ej.mjs → env-validation-ENpMy6Ez.mjs} +68 -122
  51. package/dist/{gen-o_w-8yI8.mjs → gen-BKw6qHIg.mjs} +70 -15
  52. package/dist/{github-cmd-DKcGUNsj.mjs → github-cmd-DJS5Ab-H.mjs} +39 -31
  53. package/dist/{handler-Cjh8uM3Y.d.mts → handler-D1hLsObx.d.mts} +124 -122
  54. package/dist/{head-nmvOgFjd.d.mts → head-Do8P4puT.d.mts} +9 -8
  55. package/dist/{headers-nsHIFixA.mjs → headers-D8QfRX9Y.mjs} +12 -10
  56. package/dist/inbound-BJ70in1n.d.mts +354 -0
  57. package/dist/inbound-CNKxb3FY.mjs +694 -0
  58. package/dist/index.d.mts +61 -34
  59. package/dist/index.mjs +1048 -321
  60. package/dist/{init-3rgHKBVi.mjs → init-Dx5cgKqK.mjs} +329 -271
  61. package/dist/link-D_rm5sRH.mjs +52 -0
  62. package/dist/{list-CPwFDZ_c.mjs → list-M8XShti7.mjs} +37 -5
  63. package/dist/{runner-kapo9aPs.mjs → local-d1-BE8KBbMy.mjs} +116 -6
  64. package/dist/{login-BT3H8PN3.mjs → login-C8-UuLnp.mjs} +17 -15
  65. package/dist/{logs-Bt313ax7.mjs → logs-DwFU7dMW.mjs} +16 -2
  66. package/dist/mime-BJD7d_qL.mjs +1216 -0
  67. package/dist/neon-DHwd2zvC.mjs +54 -0
  68. package/dist/{node-Da0UcsGA.mjs → node-BkaXcpAc.mjs} +29 -8
  69. package/dist/operator-cmd-DYWRbWUA.mjs +348 -0
  70. package/dist/{agents-CtgBYqld.mjs → output-tFQLLj26.mjs} +676 -211
  71. package/dist/{package-json-Cx1osYo6.mjs → package-json-CPoWX79C.mjs} +1 -1
  72. package/dist/pages/client.d.mts +43 -41
  73. package/dist/pages/client.mjs +40 -33
  74. package/dist/pages/head-client.d.mts +10 -12
  75. package/dist/pages/head.d.mts +1 -1
  76. package/dist/pages/index.d.mts +37 -14
  77. package/dist/pages/index.mjs +5 -5
  78. package/dist/pages/islands-plugin.d.mts +25 -27
  79. package/dist/pages/islands-plugin.mjs +6 -4
  80. package/dist/pages/prefetch.d.mts +6 -7
  81. package/dist/pages/protocol.d.mts +2 -2
  82. package/dist/pages/protocol.mjs +2 -1
  83. package/dist/pages/serialize.d.mts +7 -8
  84. package/dist/platform-cmd-BEOVv1PN.mjs +123 -0
  85. package/dist/platform-domain-BszUfiS8.mjs +228 -0
  86. package/dist/platform-lifecycle-CjSr6xf0.mjs +4450 -0
  87. package/dist/platform-management-W30iCaTL.mjs +698 -0
  88. package/dist/platform-recovery-pHHv4ZSg.mjs +99 -0
  89. package/dist/{plugin-inference-DMeavIJ6.mjs → plugin-inference-BDRfZngg.mjs} +35 -19
  90. package/dist/prepare-BfJvFUtJ.mjs +14 -0
  91. package/dist/{prepare-BoKHgMNx.mjs → prepare-CBetXvsN.mjs} +15 -24
  92. package/dist/{preset-BjyR3lzz.mjs → preset-lAy0B0BQ.mjs} +25 -212
  93. package/dist/{project-cmd-D_w-4w5B.mjs → project-cmd-DCpk1cDt.mjs} +25 -12
  94. package/dist/{project-paths-BQd7OmIo.mjs → project-paths-SK8nMHPp.mjs} +3 -1
  95. package/dist/{project-tsconfig-B-QtXjLQ.mjs → project-tsconfig-Ql2XsSQp.mjs} +2 -2
  96. package/dist/{protocol-Bnb0LFp3.d.mts → protocol-C-pqYJjE.d.mts} +3 -4
  97. package/dist/{provision-rShh6MKY.mjs → provision-Blnstcm2.mjs} +78 -45
  98. package/dist/r2-conditions-D1Wk8i7b.mjs +30 -0
  99. package/dist/{requests-B8sZxaFM.mjs → requests-Dn8Vheh1.mjs} +5 -3
  100. package/dist/{resolve-project-BBMtLLV9.mjs → resolve-project--Vxawf7z.mjs} +2 -2
  101. package/dist/rollback-CtlPXEBi.mjs +166 -0
  102. package/dist/{rolldown-runtime-DJK8HYOj.mjs → rolldown-runtime-rQ84J-ij.mjs} +1 -1
  103. package/dist/{route-types-COI2DsZv.mjs → route-types-Da-DpyUp.mjs} +85 -26
  104. package/dist/routes-stub.d.mts +22 -23
  105. package/dist/runner-mysql-CgRFl3s6.mjs +61 -0
  106. package/dist/{runner-pg-CHM76xuC.mjs → runner-pg-DCkWPsWS.mjs} +18 -6
  107. package/dist/runtime/ai.d.mts +21 -14
  108. package/dist/runtime/ai.mjs +5 -4
  109. package/dist/runtime/auth-client-react.d.mts +3 -5
  110. package/dist/runtime/auth-client-solid.d.mts +3 -5
  111. package/dist/runtime/auth-client-svelte.d.mts +3 -5
  112. package/dist/runtime/auth-client-vue.d.mts +3 -5
  113. package/dist/runtime/auth-client.d.mts +3 -5
  114. package/dist/runtime/auth.d.mts +1 -1
  115. package/dist/runtime/better-auth-mysql.d.mts +10 -0
  116. package/dist/runtime/better-auth-mysql.mjs +49 -0
  117. package/dist/runtime/better-auth-pg.d.mts +8 -9
  118. package/dist/runtime/better-auth-pg.mjs +2 -2
  119. package/dist/runtime/better-auth.d.mts +8 -9
  120. package/dist/runtime/better-auth.mjs +2 -2
  121. package/dist/runtime/client-react.d.mts +1 -1
  122. package/dist/runtime/client-solid.d.mts +1 -1
  123. package/dist/runtime/client-svelte.d.mts +1 -1
  124. package/dist/runtime/client-vue.d.mts +1 -1
  125. package/dist/runtime/client.d.mts +1 -1
  126. package/dist/runtime/db-mysql.d.mts +2 -0
  127. package/dist/runtime/db-mysql.mjs +1 -0
  128. package/dist/runtime/db.d.mts +10 -11
  129. package/dist/runtime/durable.d.mts +47 -0
  130. package/dist/runtime/durable.mjs +146 -0
  131. package/dist/runtime/email/testing.d.mts +112 -0
  132. package/dist/runtime/email/testing.mjs +283 -0
  133. package/dist/runtime/email.d.mts +30 -0
  134. package/dist/runtime/email.mjs +573 -0
  135. package/dist/runtime/env-helpers.d.mts +2 -2
  136. package/dist/runtime/env-helpers.mjs +5 -42
  137. package/dist/runtime/env-public-client.d.mts +10 -11
  138. package/dist/runtime/env-public-client.mjs +1 -1
  139. package/dist/runtime/env-public.d.mts +2 -2
  140. package/dist/runtime/env-public.mjs +104 -49
  141. package/dist/runtime/env.d.mts +19 -18
  142. package/dist/runtime/env.mjs +15 -2
  143. package/dist/runtime/fetch-stream.d.mts +20 -21
  144. package/dist/runtime/fetch.d.mts +15 -16
  145. package/dist/runtime/handler.d.mts +1 -1
  146. package/dist/runtime/isr.d.mts +21 -22
  147. package/dist/runtime/isr.mjs +26 -8
  148. package/dist/runtime/kv.d.mts +9 -10
  149. package/dist/runtime/live-client.d.mts +5 -7
  150. package/dist/runtime/live-client.mjs +9 -7
  151. package/dist/runtime/live-server.d.mts +4 -5
  152. package/dist/runtime/live.d.mts +22 -24
  153. package/dist/runtime/live.mjs +1 -1
  154. package/dist/runtime/log.d.mts +16 -17
  155. package/dist/runtime/migration-handler-mysql.d.mts +4 -0
  156. package/dist/runtime/migration-handler-mysql.mjs +81 -0
  157. package/dist/runtime/migration-handler-pg.d.mts +2 -4
  158. package/dist/runtime/migration-handler.d.mts +5 -6
  159. package/dist/runtime/migration-handler.mjs +4 -3
  160. package/dist/runtime/queues.d.mts +3 -4
  161. package/dist/runtime/queues.mjs +2 -1
  162. package/dist/runtime/remote/binding-handler.d.mts +10 -12
  163. package/dist/runtime/remote/binding-handler.mjs +24 -3
  164. package/dist/runtime/remote/index.d.mts +5 -6
  165. package/dist/runtime/remote/index.mjs +21 -18
  166. package/dist/runtime/response.d.mts +10 -11
  167. package/dist/runtime/sandbox.d.mts +56 -55
  168. package/dist/runtime/sandbox.mjs +57 -49
  169. package/dist/runtime/schema-mysql.d.mts +1 -0
  170. package/dist/runtime/schema-mysql.mjs +2 -0
  171. package/dist/runtime/seed.d.mts +14 -9
  172. package/dist/runtime/sse-client.d.mts +6 -7
  173. package/dist/runtime/sse.d.mts +11 -12
  174. package/dist/runtime/storage.d.mts +3 -4
  175. package/dist/runtime/validator.d.mts +1 -1
  176. package/dist/runtime/ws-server.d.mts +12 -12
  177. package/dist/runtime/ws-server.mjs +32 -4
  178. package/dist/runtime/ws.d.mts +19 -21
  179. package/dist/{scan-DYXkrasO.mjs → scan-BMH4rzlv.mjs} +53 -31
  180. package/dist/{scan-DEwlM_Xy.mjs → scan-CpK-57ug.mjs} +9 -5
  181. package/dist/{secret-Dt32J6RI.mjs → secret-BqTxGqki.mjs} +62 -5
  182. package/dist/{skills-CLjN0uUO.mjs → skills-Q46GZMO-.mjs} +6 -4
  183. package/dist/{standard-schema-DJ0HW7QP.d.mts → standard-schema-Fo_vCAZh.d.mts} +6 -6
  184. package/dist/{subcommand-prompt-BzV8iQZo.mjs → subcommand-prompt-WfySCQ7S.mjs} +67 -48
  185. package/dist/sveltekit.d.mts +12 -11
  186. package/dist/sveltekit.mjs +1 -1
  187. package/dist/types-BAp5AEBU.d.mts +79 -0
  188. package/dist/types-CKWnYgfy.d.mts +1 -0
  189. package/dist/{validate-Cw_RLeTj.mjs → validate-Bihr8WBi.mjs} +3 -3
  190. package/dist/wrangler--imS8n0d.mjs +1796 -0
  191. package/dist/{yarn-pnp-DJn3SAHF.mjs → yarn-pnp-DxSInkzL.mjs} +1 -1
  192. package/package.json +79 -65
  193. package/schema.json +35 -3
  194. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +1 -1
  195. package/skills/void/SKILL.md +59 -2
  196. package/skills/void/docs/guide/ai.md +32 -14
  197. package/skills/void/docs/guide/app-types.md +6 -6
  198. package/skills/void/docs/guide/auth.md +14 -16
  199. package/skills/void/docs/guide/database/d1.md +6 -0
  200. package/skills/void/docs/guide/database/mysql.md +60 -0
  201. package/skills/void/docs/guide/database/postgresql.md +14 -9
  202. package/skills/void/docs/guide/database.md +39 -26
  203. package/skills/void/docs/guide/deployment.md +163 -22
  204. package/skills/void/docs/guide/durable-state.md +140 -0
  205. package/skills/void/docs/guide/edge/headers.md +5 -5
  206. package/skills/void/docs/guide/edge/prerendering.md +2 -0
  207. package/skills/void/docs/guide/edge/revalidation.md +21 -6
  208. package/skills/void/docs/guide/edge/rewrites.md +18 -14
  209. package/skills/void/docs/guide/edge/static-assets.md +23 -8
  210. package/skills/void/docs/guide/email.md +609 -0
  211. package/skills/void/docs/guide/env-migration.md +109 -0
  212. package/skills/void/docs/guide/env-vars.md +70 -248
  213. package/skills/void/docs/guide/index.md +15 -17
  214. package/skills/void/docs/guide/jobs.md +8 -5
  215. package/skills/void/docs/guide/live.md +7 -15
  216. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +8 -4
  217. package/skills/void/docs/guide/pages-routing/islands.md +3 -3
  218. package/skills/void/docs/guide/pages-routing/loaders.md +6 -4
  219. package/skills/void/docs/guide/pages-routing/overview.md +7 -7
  220. package/skills/void/docs/guide/platform-administration.md +212 -0
  221. package/skills/void/docs/guide/platform-development.md +235 -0
  222. package/skills/void/docs/guide/queues.md +10 -10
  223. package/skills/void/docs/guide/quickstart.md +46 -67
  224. package/skills/void/docs/guide/remote-dev.md +8 -6
  225. package/skills/void/docs/guide/sandboxes.md +33 -16
  226. package/skills/void/docs/guide/self-hosted-platform.md +553 -0
  227. package/skills/void/docs/guide/server-routing.md +25 -5
  228. package/skills/void/docs/guide/sse.md +4 -4
  229. package/skills/void/docs/guide/ssg.md +5 -3
  230. package/skills/void/docs/guide/storage.md +2 -2
  231. package/skills/void/docs/guide/websockets.md +18 -7
  232. package/skills/void/docs/index.md +3 -3
  233. package/skills/void/docs/integrations/agents.md +6 -64
  234. package/skills/void/docs/integrations/cloudflare.md +165 -146
  235. package/skills/void/docs/integrations/frameworks/analog.md +4 -4
  236. package/skills/void/docs/integrations/frameworks/astro.md +5 -5
  237. package/skills/void/docs/integrations/frameworks/nuxt.md +5 -5
  238. package/skills/void/docs/integrations/frameworks/overview.md +3 -3
  239. package/skills/void/docs/integrations/frameworks/react-router.md +3 -3
  240. package/skills/void/docs/integrations/frameworks/sveltekit.md +3 -3
  241. package/skills/void/docs/integrations/frameworks/tanstack-start.md +2 -2
  242. package/skills/void/docs/integrations/nodejs-bun-deno.md +11 -4
  243. package/skills/void/docs/reference/api.md +42 -6
  244. package/skills/void/docs/reference/cli.md +637 -159
  245. package/skills/void/docs/reference/config.md +80 -25
  246. package/skills/void/docs/reference/resource-inference.md +13 -9
  247. package/skills/void/docs/reference/structure.md +10 -11
  248. package/AGENT_PROMPT.md +0 -19
  249. package/dist/cf-access-Bqw81xAf.mjs +0 -22
  250. package/dist/env-CZy5MorI.mjs +0 -299
  251. package/dist/env-helpers-z4stu8uc.d.mts +0 -52
  252. package/dist/env-mask-Dd47NbR6.mjs +0 -90
  253. package/dist/env-public-BfiLcMBk.d.mts +0 -140
  254. package/dist/link-CdGHSIy-.mjs +0 -45
  255. package/dist/mcp-DoM3_nhd.mjs +0 -377
  256. package/dist/project-paths-GpziKeQQ.d.mts +0 -25
  257. package/dist/providers-BNKRacMr.d.mts +0 -7
  258. package/dist/proxy-D-3_D-Gl.mjs +0 -5
  259. package/dist/rollback-CkvTFXx5.mjs +0 -90
  260. package/dist/runtime/isr-cache.d.mts +0 -207
  261. package/dist/runtime/isr-cache.mjs +0 -523
  262. package/dist/types-lLjNE9Qp.d.mts +0 -51
  263. package/getting-started-prompt.txt +0 -28
  264. package/skills/void/command/void.md +0 -7
  265. package/skills/void/docs/integrations/auth-providers.md +0 -0
  266. package/skills/void/docs/integrations/payment-processors.md +0 -0
  267. package/skills/void/docs/node_modules/@iconify/vue/README.md +0 -408
  268. package/skills/void/docs/node_modules/@iconify/vue/offline/readme.md +0 -5
  269. package/skills/void/docs/node_modules/@voidzero-dev/vitepress-theme/README.md +0 -103
  270. package/skills/void/docs/node_modules/oxc-minify/README.md +0 -78
  271. package/skills/void/docs/node_modules/reka-ui/README.md +0 -80
  272. package/skills/void/docs/node_modules/vitepress/README.md +0 -28
  273. package/skills/void/docs/node_modules/vitepress/template/api-examples.md +0 -49
  274. package/skills/void/docs/node_modules/vitepress/template/index.md +0 -28
  275. package/skills/void/docs/node_modules/vitepress/template/markdown-examples.md +0 -85
  276. package/skills/void/docs/node_modules/vitepress-plugin-group-icons/README.md +0 -101
  277. package/skills/void/docs/node_modules/void/AGENT_PROMPT.md +0 -19
  278. package/skills/void/docs/node_modules/void/CLAUDE.md +0 -219
  279. package/skills/void/docs/node_modules/void/README.md +0 -90
  280. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/CHANGELOG.md +0 -685
  281. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/README.md +0 -396
  282. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/sandbox/README.md +0 -219
  283. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/vite-plugin/README.md +0 -37
  284. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/workers-types/README.md +0 -135
  285. package/skills/void/docs/node_modules/void/node_modules/@electric-sql/pglite/README.md +0 -189
  286. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/CHANGELOG.md +0 -143
  287. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/README.md +0 -1272
  288. package/skills/void/docs/node_modules/void/node_modules/@napi-rs/keyring/README.md +0 -19
  289. package/skills/void/docs/node_modules/void/node_modules/@types/better-sqlite3/README.md +0 -15
  290. package/skills/void/docs/node_modules/void/node_modules/@types/node/README.md +0 -15
  291. package/skills/void/docs/node_modules/void/node_modules/@types/pg/README.md +0 -15
  292. package/skills/void/docs/node_modules/void/node_modules/@types/proper-lockfile/README.md +0 -51
  293. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/README.md +0 -22
  294. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/vendor/vscode-jsonrpc/README.md +0 -69
  295. package/skills/void/docs/node_modules/void/node_modules/@void/md/README.md +0 -153
  296. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/engine-javascript/README.md +0 -9
  297. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/transformers/README.md +0 -9
  298. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@types/node/README.md +0 -15
  299. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/CHANGELOG.md +0 -24
  300. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/README.md +0 -565
  301. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-exit/README.md +0 -127
  302. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-anchor/README.md +0 -600
  303. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-attrs/README.md +0 -386
  304. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-container/README.md +0 -95
  305. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-emoji/README.md +0 -101
  306. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-footnote/README.md +0 -135
  307. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/pathslash/README.md +0 -64
  308. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/shiki/README.md +0 -15
  309. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tinyglobby/README.md +0 -25
  310. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/AGENTS.md +0 -16
  311. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/README.md +0 -220
  312. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/build.md +0 -21
  313. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/check.md +0 -35
  314. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/create.md +0 -70
  315. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/fmt.md +0 -20
  316. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/index.md +0 -35
  317. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/lint.md +0 -26
  318. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/pack.md +0 -17
  319. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/run.md +0 -364
  320. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/staged.md +0 -15
  321. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/test.md +0 -18
  322. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/automatic-data-tracking.md +0 -145
  323. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/build.md +0 -40
  324. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/cache.md +0 -107
  325. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/check.md +0 -60
  326. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/ci.md +0 -62
  327. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/commit-hooks.md +0 -60
  328. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/create.md +0 -341
  329. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/dev.md +0 -24
  330. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/docker.md +0 -175
  331. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/env.md +0 -167
  332. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/fmt.md +0 -41
  333. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/github-actions-cache.md +0 -165
  334. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/ide-integration.md +0 -101
  335. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/implode.md +0 -23
  336. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/index.md +0 -134
  337. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/install.md +0 -199
  338. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/lint.md +0 -50
  339. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/migrate-rules.md +0 -347
  340. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/migrate.md +0 -197
  341. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/monorepo.md +0 -176
  342. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/pack.md +0 -69
  343. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/run.md +0 -356
  344. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/test.md +0 -35
  345. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/troubleshooting.md +0 -108
  346. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/upgrade.md +0 -101
  347. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/vpx.md +0 -66
  348. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/why.md +0 -39
  349. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/index.md +0 -12
  350. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/team.md +0 -35
  351. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/templates/generator/README.md +0 -35
  352. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/templates/monorepo/README.md +0 -29
  353. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vue/README.md +0 -58
  354. package/skills/void/docs/node_modules/void/node_modules/arktype/README.md +0 -165
  355. package/skills/void/docs/node_modules/void/node_modules/better-auth/LICENSE.md +0 -20
  356. package/skills/void/docs/node_modules/void/node_modules/better-auth/README.md +0 -32
  357. package/skills/void/docs/node_modules/void/node_modules/better-sqlite3/README.md +0 -99
  358. package/skills/void/docs/node_modules/void/node_modules/blake3-jit/README.md +0 -108
  359. package/skills/void/docs/node_modules/void/node_modules/drizzle-arktype/README.md +0 -51
  360. package/skills/void/docs/node_modules/void/node_modules/drizzle-kit/README.md +0 -79
  361. package/skills/void/docs/node_modules/void/node_modules/drizzle-orm/README.md +0 -44
  362. package/skills/void/docs/node_modules/void/node_modules/drizzle-valibot/README.md +0 -51
  363. package/skills/void/docs/node_modules/void/node_modules/drizzle-zod/README.md +0 -65
  364. package/skills/void/docs/node_modules/void/node_modules/es-module-lexer/README.md +0 -403
  365. package/skills/void/docs/node_modules/void/node_modules/estree-walker/README.md +0 -48
  366. package/skills/void/docs/node_modules/void/node_modules/hono/README.md +0 -85
  367. package/skills/void/docs/node_modules/void/node_modules/ignore/README.md +0 -452
  368. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/CHANGELOG.md +0 -76
  369. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/LICENSE.md +0 -21
  370. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/README.md +0 -364
  371. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/SECURITY.md +0 -41
  372. package/skills/void/docs/node_modules/void/node_modules/magic-string/README.md +0 -325
  373. package/skills/void/docs/node_modules/void/node_modules/ofetch/README.md +0 -398
  374. package/skills/void/docs/node_modules/void/node_modules/pathslash/README.md +0 -64
  375. package/skills/void/docs/node_modules/void/node_modules/pg/README.md +0 -96
  376. package/skills/void/docs/node_modules/void/node_modules/pglite-server/README.md +0 -135
  377. package/skills/void/docs/node_modules/void/node_modules/picocolors/README.md +0 -21
  378. package/skills/void/docs/node_modules/void/node_modules/proper-lockfile/CHANGELOG.md +0 -108
  379. package/skills/void/docs/node_modules/void/node_modules/proper-lockfile/README.md +0 -183
  380. package/skills/void/docs/node_modules/void/node_modules/tinyglobby/README.md +0 -25
  381. package/skills/void/docs/node_modules/void/node_modules/valibot/LICENSE.md +0 -9
  382. package/skills/void/docs/node_modules/void/node_modules/valibot/README.md +0 -94
  383. package/skills/void/docs/node_modules/void/node_modules/vite-plus/AGENTS.md +0 -16
  384. package/skills/void/docs/node_modules/void/node_modules/vite-plus/README.md +0 -220
  385. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/build.md +0 -21
  386. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/check.md +0 -35
  387. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/create.md +0 -70
  388. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/fmt.md +0 -20
  389. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/index.md +0 -35
  390. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/lint.md +0 -26
  391. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/pack.md +0 -17
  392. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/run.md +0 -364
  393. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/staged.md +0 -15
  394. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/test.md +0 -18
  395. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/automatic-data-tracking.md +0 -145
  396. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/build.md +0 -40
  397. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/cache.md +0 -107
  398. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/check.md +0 -60
  399. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/ci.md +0 -62
  400. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/commit-hooks.md +0 -60
  401. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/create.md +0 -341
  402. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/dev.md +0 -24
  403. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/docker.md +0 -175
  404. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/env.md +0 -167
  405. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/fmt.md +0 -41
  406. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/github-actions-cache.md +0 -165
  407. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/ide-integration.md +0 -101
  408. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/implode.md +0 -23
  409. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/index.md +0 -134
  410. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/install.md +0 -199
  411. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/lint.md +0 -50
  412. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/migrate-rules.md +0 -347
  413. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/migrate.md +0 -197
  414. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/monorepo.md +0 -176
  415. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/pack.md +0 -69
  416. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/run.md +0 -356
  417. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/test.md +0 -35
  418. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/troubleshooting.md +0 -108
  419. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/upgrade.md +0 -101
  420. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/vpx.md +0 -66
  421. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/why.md +0 -39
  422. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/index.md +0 -12
  423. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/team.md +0 -35
  424. package/skills/void/docs/node_modules/void/node_modules/vite-plus/templates/generator/README.md +0 -35
  425. package/skills/void/docs/node_modules/void/node_modules/vite-plus/templates/monorepo/README.md +0 -29
  426. package/skills/void/docs/node_modules/void/node_modules/wrangler/README.md +0 -63
  427. package/skills/void/docs/node_modules/void/node_modules/zod/README.md +0 -191
  428. package/skills/void/docs/node_modules/void/skills/migrate-vite-cloudflare-to-void/SKILL.md +0 -175
  429. package/skills/void/docs/node_modules/void/skills/void/SKILL.md +0 -76
  430. package/skills/void/docs/node_modules/void/skills/void/command/void.md +0 -7
  431. package/skills/void/docs/node_modules/void/test/e2e/README.md +0 -85
@@ -0,0 +1,694 @@
1
+ import { i as normalizeEmail, n as MimeError, o as validateAddressParts, r as buildMime, t as MAX_MESSAGE_BYTES } from "./mime-BJD7d_qL.mjs";
2
+ import { a as getRawRuntimeEnv } from "./env-raw-Cx8ElDdj.mjs";
3
+ //#region src/runtime/email/inbound.ts
4
+ const VALID_SLUG = /^[a-z0-9](?:[a-z0-9-]{0,54}[a-z0-9])?$/;
5
+ /**
6
+ * Guardrails on what one handler may queue.
7
+ *
8
+ * These are NOT the security boundary. Recording happens inside the tenant's
9
+ * own worker, and on the platform a Workers-for-Platforms tenant can ship any
10
+ * `WorkerEntrypoint` whose `email()` returns any array at all, bypassing this
11
+ * file entirely — so the load-bearing caps are the matching ones in the
12
+ * platform router (`MAX_ACTIONS` / `MAX_ACTION_ADDRESS_LENGTH` in
13
+ * `email-router.ts`). What these buy is a fast, precise failure at the call
14
+ * that went wrong, instead of a whole action list silently dropped at the
15
+ * router with only a platform-side log to show for it.
16
+ */
17
+ const MAX_ACTIONS = 100;
18
+ const MAX_ACTION_ADDRESS_LENGTH = 320;
19
+ const MAX_FORWARD_HEADER_LENGTH = 1024;
20
+ /**
21
+ * Cap on a reject reason, restated from the router's
22
+ * `MAX_REJECT_REASON_LENGTH` in `email-router.ts` for the same reason as
23
+ * above, and pinned by the same test. See `normalizeRejectReason`.
24
+ */
25
+ const MAX_REJECT_REASON_LENGTH = 1e3;
26
+ /**
27
+ * The router's ADMISSION bounds — what it refuses BEFORE the handler runs
28
+ * (`MAX_INBOUND_BYTES` / `MAX_INBOUND_HEADERS` in `email-router.ts`,
29
+ * restated for the same reason as above and pinned by the same test).
30
+ * `routeInbound` rejects a message over either one and never dispatches it,
31
+ * so a handler's behaviour on such a message is unreachable after a managed
32
+ * deploy; the test harness applies both before it invokes the handler.
33
+ *
34
+ * `MAX_INBOUND_BYTES` is NOT `MAX_MESSAGE_BYTES`, though the numbers agree
35
+ * today. That one is Cloudflare's cap on an OUTBOUND message (and the
36
+ * `parseEmail` guard); this one is the router's own heap headroom on an
37
+ * inbound one, set well under Cloudflare's ~25 MB inbound ceiling, and the
38
+ * two can move independently.
39
+ */
40
+ const MAX_INBOUND_BYTES = 10485760;
41
+ const MAX_INBOUND_HEADERS = 1024;
42
+ /**
43
+ * Cumulative reply-byte budget for ONE dispatch.
44
+ *
45
+ * `MAX_MESSAGE_BYTES` bounds a single `reply()` call, not the queue: N replies
46
+ * at the cap is N x 10 MiB of `Uint8Array` riding one RPC response. workerd
47
+ * caps a serialized RPC payload at 32 MiB, so the queue that clears our
48
+ * per-reply check still fails at the boundary — opaquely. The router cannot
49
+ * tell that failure from any other dispatch error, so the whole message comes
50
+ * back to the sender as a generic "project handler error" reject with nothing
51
+ * in it a handler author could act on. Two full-size replies is already well
52
+ * past any legitimate use, and failing here names the exact call that
53
+ * overran.
54
+ */
55
+ const MAX_REPLY_BYTES_TOTAL = 2 * MAX_MESSAGE_BYTES;
56
+ function readRawProjectSlug() {
57
+ let raw;
58
+ try {
59
+ raw = getRawRuntimeEnv()?.__VOID_PROJECT_SLUG;
60
+ } catch {
61
+ return;
62
+ }
63
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
64
+ }
65
+ function tryReadProjectSlug() {
66
+ const raw = readRawProjectSlug();
67
+ return raw !== void 0 && VALID_SLUG.test(raw) ? raw : void 0;
68
+ }
69
+ function tryReadEmailDomain() {
70
+ let raw;
71
+ try {
72
+ raw = getRawRuntimeEnv()?.__VOID_EMAIL_DOMAIN;
73
+ } catch {
74
+ return;
75
+ }
76
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
77
+ }
78
+ /**
79
+ * Identity helper that types the inbound email handler. Use as the default
80
+ * export of `email/<address>.ts` or `email/_default.ts`.
81
+ */
82
+ function defineEmail(handler) {
83
+ return handler;
84
+ }
85
+ /**
86
+ * Typed error thrown by `parseEmail`. Lets handler authors distinguish
87
+ * "too big" from "malformed body" without string-matching error messages.
88
+ */
89
+ var ParseEmailError = class extends Error {
90
+ code;
91
+ constructor(code, message, options) {
92
+ super(message, options);
93
+ this.name = "ParseEmailError";
94
+ this.code = code;
95
+ }
96
+ };
97
+ /**
98
+ * Parse a `ForwardableEmailMessage` into structured fields. postal-mime is
99
+ * loaded lazily so workers that never call this don't bundle it.
100
+ *
101
+ * For proxy messages (built via `createMessageProxy`) the raw bytes are
102
+ * cached on first read so subsequent `parseEmail`/`message.raw` accesses
103
+ * still work. For real CF `ForwardableEmailMessage`s the raw stream is
104
+ * one-shot.
105
+ */
106
+ async function parseEmail(message) {
107
+ if (message.rawSize > 10485760) throw new ParseEmailError("INBOUND_TOO_LARGE", `parseEmail: message size ${message.rawSize} bytes exceeds maximum of ${MAX_MESSAGE_BYTES} bytes.`);
108
+ const { default: PostalMime } = await import("postal-mime");
109
+ const cached = proxyRawCache.get(message);
110
+ try {
111
+ const source = cached ? await cached.read() : message.raw;
112
+ return await PostalMime.parse(source);
113
+ } catch (cause) {
114
+ throw new ParseEmailError("PARSE_FAILED", `parseEmail: could not parse the message body. ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
115
+ }
116
+ }
117
+ const proxyRawCache = /* @__PURE__ */ new WeakMap();
118
+ /**
119
+ * Remove the platform-injected `<slug>+` prefix from a recipient address.
120
+ * The platform's shared sender (e.g. `mail.void.cloud`) rewrites every recipient to
121
+ * `<slug>+<tag>@<domain>`; user handlers expect `<tag>@<domain>`. If the
122
+ * slug is unknown, missing, or doesn't match the local-part prefix, the
123
+ * address is returned unchanged so callers without slug context (e.g. the
124
+ * test harness when no slug is set) don't accidentally mangle the address.
125
+ */
126
+ function stripSlugFromAddress(address, slug) {
127
+ if (!slug) return address;
128
+ const atIdx = address.indexOf("@");
129
+ if (atIdx <= 0) return address;
130
+ const localPart = address.slice(0, atIdx);
131
+ const domain = address.slice(atIdx);
132
+ const prefix = `${slug.toLowerCase()}+`;
133
+ if (localPart.toLowerCase().startsWith(prefix)) return localPart.slice(prefix.length) + domain;
134
+ return address;
135
+ }
136
+ function replyTooLarge(size) {
137
+ return new MimeError("MIME_ERROR", `reply: message size ${size} bytes exceeds Cloudflare limit of ${MAX_MESSAGE_BYTES} bytes.`);
138
+ }
139
+ function replyBudgetExhausted(size) {
140
+ return new MimeError("MIME_ERROR", `reply: cumulative reply size ${size} bytes exceeds this delivery's budget of ${MAX_REPLY_BYTES_TOTAL} bytes.`);
141
+ }
142
+ function queueFull() {
143
+ return new MimeError("MIME_ERROR", `email: handler queued more than ${MAX_ACTIONS} actions for one message.`);
144
+ }
145
+ function addressTooLong(field, length) {
146
+ return new MimeError(field === "from" ? "INVALID_FROM" : "INVALID_TO", `${field} address is ${length} characters, over the ${MAX_ACTION_ADDRESS_LENGTH}-character limit.`);
147
+ }
148
+ function invalidForwardHeaders(cause) {
149
+ const detail = cause instanceof Error ? cause.message.slice(0, 320) : "not a valid header set";
150
+ return new MimeError("MIME_ERROR", `forward: invalid header — ${detail}`);
151
+ }
152
+ /**
153
+ * The router's `forwardHeadersWithinBounds`, as a throw. It runs on the
154
+ * record about to be recorded — the very object the router receives, so the
155
+ * count is the router's count: a `Headers` folded its duplicate names before
156
+ * it got here, and a record keeps `X-A` and `x-a` as two, both there and
157
+ * here. Runs after the `new Headers()` validity check, so every name is a
158
+ * token and every value is header-safe; what is left is size. The router
159
+ * drops the WHOLE list on any of these — a handler that passed here and
160
+ * failed there deployed as one whose managed delivery performed no actions.
161
+ */
162
+ function assertForwardHeadersWithinBounds(headers) {
163
+ const names = Object.keys(headers);
164
+ if (names.length > 32) throw new MimeError("MIME_ERROR", `forward: ${names.length} headers, over the 32-header limit.`);
165
+ for (const name of names) {
166
+ if (name.length > 1024) throw new MimeError("MIME_ERROR", `forward: header name is ${name.length} characters, over the ${MAX_FORWARD_HEADER_LENGTH}-character limit.`);
167
+ const value = headers[name];
168
+ if (typeof value !== "string") throw new MimeError("MIME_ERROR", `forward: header "${name.slice(0, 64)}" value is not a string.`);
169
+ if (value.length > 1024) throw new MimeError("MIME_ERROR", `forward: header "${name.slice(0, 64)}" value is ${value.length} characters, over the ${MAX_FORWARD_HEADER_LENGTH}-character limit.`);
170
+ }
171
+ }
172
+ /**
173
+ * The router's rule for a reject reason (`validateActions` in
174
+ * `email-router.ts`: `sanitize(raw, MAX_REJECT_REASON_LENGTH)`, and
175
+ * `'rejected by handler'` for an empty one), applied when the reason is
176
+ * RECORDED so the native replay carries the string the managed one does.
177
+ *
178
+ * The reason goes into the SMTP reply to the connecting client, and a
179
+ * handler may build it from the inbound message: a remote sender's CRLF is
180
+ * then a line injected into that reply, and a multi-megabyte reason is a
181
+ * transient-heap amplifier. The router already refuses both, but on your
182
+ * own account `enactEmailActions` handed the recorded string to the native
183
+ * `setReject()` untouched, so the same handler injected there and was
184
+ * clean here. NORMALIZED rather than refused, unlike the forward bounds
185
+ * above: a reject is the handler's terminal decision, and throwing out of
186
+ * it would drop that decision and bounce the message as a dispatch error
187
+ * (see the `MAX_ACTIONS` note in `setReject`). Slice FIRST, then replace: a
188
+ * global replace materializes ~66 bytes per match, so the slice is what
189
+ * bounds the work (see `prefixReplySubject`). The result can be SHORTER
190
+ * than the cap: a run of controls inside the window collapses to one space
191
+ * and the window is not refilled from beyond it — the router's own trade,
192
+ * and it is DSN text.
193
+ */
194
+ function normalizeRejectReason(reason) {
195
+ const raw = typeof reason === "string" ? reason : "";
196
+ if (raw.length === 0) return "rejected by handler";
197
+ return raw.slice(0, MAX_REJECT_REASON_LENGTH).replace(/[\x00-\x1f\x7f]+/g, " ");
198
+ }
199
+ async function readStreamToBytes(stream, limit = Infinity, onOverflow = replyTooLarge) {
200
+ const reader = stream.getReader();
201
+ const chunks = [];
202
+ let total = 0;
203
+ for (;;) {
204
+ const { value, done } = await reader.read();
205
+ if (done) break;
206
+ total += value.byteLength;
207
+ if (total > limit) {
208
+ await reader.cancel().catch(() => {});
209
+ throw onOverflow(total);
210
+ }
211
+ chunks.push(value);
212
+ }
213
+ const out = new Uint8Array(total);
214
+ let offset = 0;
215
+ for (const c of chunks) {
216
+ out.set(c, offset);
217
+ offset += c.byteLength;
218
+ }
219
+ return out;
220
+ }
221
+ function bytesToReadableStream(bytes) {
222
+ return new ReadableStream({ start(controller) {
223
+ controller.enqueue(bytes);
224
+ controller.close();
225
+ } });
226
+ }
227
+ /**
228
+ * Build a proxy `ForwardableEmailMessage` from an envelope. The proxy's
229
+ * `setReject` / `forward` / `reply` methods don't dispatch directly — they
230
+ * record `EmailAction` entries that the router (which holds the real
231
+ * message) enacts after the handler returns.
232
+ *
233
+ * `reply()` accepts a duck-typed `{ from, to, raw }` with `raw` a
234
+ * `Uint8Array` or `ReadableStream` — what `replyEmail()` passes. It does NOT
235
+ * accept a native `EmailMessage` from `cloudflare:email`: that class exposes
236
+ * only `from` and `to` (workers-types declares nothing else, and the body
237
+ * has no public accessor), so its bytes cannot be recorded here, and nothing
238
+ * could carry them over RPC to the platform router. The reply MIME bytes are
239
+ * buffered before being recorded so the action is fully self-contained.
240
+ *
241
+ * When `opts.slug` is provided, `message.to` is rewritten to remove the
242
+ * platform-injected `<slug>+` prefix so handlers see `<tag>@<domain>`
243
+ * instead of `<slug>+<tag>@<domain>`. The original wire-form recipient is
244
+ * preserved on a non-enumerable `__voidPlatformTo` property.
245
+ */
246
+ function createMessageProxy(envelope, opts = {}) {
247
+ const actions = [];
248
+ const headers = new Headers(envelope.headers);
249
+ const userVisibleTo = stripSlugFromAddress(envelope.to, opts.slug);
250
+ let cachedRaw;
251
+ let bufferingPromise;
252
+ function readRawOnce() {
253
+ if (cachedRaw) return Promise.resolve(cachedRaw);
254
+ if (bufferingPromise) return bufferingPromise;
255
+ const source = envelope.raw;
256
+ if (source instanceof Uint8Array) {
257
+ cachedRaw = source;
258
+ return Promise.resolve(cachedRaw);
259
+ }
260
+ bufferingPromise = readStreamToBytes(source).then((bytes) => {
261
+ cachedRaw = bytes;
262
+ return bytes;
263
+ });
264
+ return bufferingPromise;
265
+ }
266
+ if (envelope.raw instanceof Uint8Array) cachedRaw = envelope.raw;
267
+ let rejected = false;
268
+ let replyBytesUsed = 0;
269
+ function assertQueueHasRoom() {
270
+ if (actions.length >= MAX_ACTIONS) throw queueFull();
271
+ }
272
+ const message = {
273
+ from: envelope.from,
274
+ to: userVisibleTo,
275
+ headers,
276
+ get raw() {
277
+ if (cachedRaw) return bytesToReadableStream(cachedRaw);
278
+ const pending = readRawOnce();
279
+ return new ReadableStream({ async start(controller) {
280
+ const bytes = await pending;
281
+ controller.enqueue(bytes);
282
+ controller.close();
283
+ } });
284
+ },
285
+ rawSize: envelope.rawSize,
286
+ setReject(reason) {
287
+ if (rejected) return;
288
+ rejected = true;
289
+ let dropped = 0;
290
+ for (let i = actions.length - 1; i >= 0; i--) {
291
+ const a = actions[i];
292
+ if (a.type === "forward" || a.type === "reply") {
293
+ actions.splice(i, 1);
294
+ dropped++;
295
+ }
296
+ }
297
+ if (dropped > 0) console.warn(`[void/email] setReject() after ${dropped} forward/reply call(s) — those actions were dropped. CF rejects are terminal: anything queued before setReject() never runs. Move the reject earlier in the handler.`);
298
+ actions.push({
299
+ type: "reject",
300
+ reason: normalizeRejectReason(reason)
301
+ });
302
+ },
303
+ async forward(to, fwdHeaders) {
304
+ if (rejected) {
305
+ console.warn("[void/email] forward() called after setReject() — ignored. CF rejects are terminal: nothing else runs once setReject fires.");
306
+ return;
307
+ }
308
+ assertQueueHasRoom();
309
+ if (to.length > MAX_ACTION_ADDRESS_LENGTH) throw addressTooLong("to", to.length);
310
+ validateAddressParts("to", to);
311
+ let headersObj;
312
+ if (fwdHeaders instanceof Headers) headersObj = Object.fromEntries(fwdHeaders.entries());
313
+ else if (fwdHeaders) {
314
+ try {
315
+ new Headers(fwdHeaders);
316
+ } catch (e) {
317
+ throw invalidForwardHeaders(e);
318
+ }
319
+ headersObj = { ...fwdHeaders };
320
+ }
321
+ if (headersObj) assertForwardHeadersWithinBounds(headersObj);
322
+ actions.push({
323
+ type: "forward",
324
+ to,
325
+ ...headersObj ? { headers: headersObj } : {}
326
+ });
327
+ },
328
+ async reply(reply) {
329
+ if (rejected) {
330
+ console.warn("[void/email] reply() called after setReject() — ignored. CF rejects are terminal: nothing else runs once setReject fires.");
331
+ return;
332
+ }
333
+ assertQueueHasRoom();
334
+ if (reply.from.length > MAX_ACTION_ADDRESS_LENGTH) throw addressTooLong("from", reply.from.length);
335
+ if (reply.to.length > MAX_ACTION_ADDRESS_LENGTH) throw addressTooLong("to", reply.to.length);
336
+ validateAddressParts("from", reply.from);
337
+ validateAddressParts("to", reply.to);
338
+ const remaining = MAX_REPLY_BYTES_TOTAL - replyBytesUsed;
339
+ let rawBytes;
340
+ if (reply.raw instanceof Uint8Array) {
341
+ if (reply.raw.byteLength > 10485760) throw replyTooLarge(reply.raw.byteLength);
342
+ if (reply.raw.byteLength > remaining) throw replyBudgetExhausted(replyBytesUsed + reply.raw.byteLength);
343
+ rawBytes = reply.raw;
344
+ } else {
345
+ const raw = reply.raw;
346
+ if (typeof raw !== "object" || raw === null || typeof raw.getReader !== "function") throw new MimeError("MIME_ERROR", "reply: expected { from, to, raw } with raw as a Uint8Array or ReadableStream. A native EmailMessage cannot be replayed from a Void handler — its body has no public accessor. Use replyEmail() from void/email, or pass the MIME bytes as raw.");
347
+ const limit = Math.min(MAX_MESSAGE_BYTES, remaining);
348
+ rawBytes = await readStreamToBytes(reply.raw, limit, (total) => limit === 10485760 ? replyTooLarge(total) : replyBudgetExhausted(replyBytesUsed + total));
349
+ }
350
+ replyBytesUsed += rawBytes.byteLength;
351
+ actions.push({
352
+ type: "reply",
353
+ from: reply.from,
354
+ to: reply.to,
355
+ raw: rawBytes
356
+ });
357
+ }
358
+ };
359
+ if (envelope.to !== userVisibleTo) Object.defineProperty(message, "__voidPlatformTo", {
360
+ value: envelope.to,
361
+ enumerable: false,
362
+ writable: false,
363
+ configurable: false
364
+ });
365
+ proxyRawCache.set(message, { read: readRawOnce });
366
+ return {
367
+ message,
368
+ getActions: () => [...actions]
369
+ };
370
+ }
371
+ /**
372
+ * Whether `Name: value` can be emitted without breaking RFC 5322 §2.1.1.
373
+ *
374
+ * Folding only happens at whitespace (§3.2.2), so the widest unbreakable run
375
+ * is what decides it — a `References` chain of ordinary ids folds fine however
376
+ * long, while one oversized id inside it does not.
377
+ */
378
+ function fitsHeaderLine(name, value) {
379
+ if (!value) return false;
380
+ const budget = 998 - (name.length + 2);
381
+ let run = 0;
382
+ for (let i = 0; i < value.length; i++) {
383
+ const c = value.charCodeAt(i);
384
+ if (c === 32 || c === 9) {
385
+ run = 0;
386
+ continue;
387
+ }
388
+ if (c < 128) run += 1;
389
+ else if (c < 2048) run += 2;
390
+ else if (c >= 55296 && c <= 56319 && i + 1 < value.length && (value.charCodeAt(i + 1) & 64512) === 56320) {
391
+ run += 4;
392
+ i++;
393
+ } else run += 3;
394
+ if (run > budget) return false;
395
+ }
396
+ return true;
397
+ }
398
+ /**
399
+ * Whether `value` carries a C0 control other than HTAB, or DEL. The
400
+ * sibling of `fitsHeaderLine` for the other way a remote-controlled id can
401
+ * be unrepresentable: a threading value is emitted verbatim, so a control
402
+ * inside it reached the reply's `In-Reply-To` / `References` line raw —
403
+ * `\x01` and DEL pass a WHATWG `Headers`, which refuses only CR, LF and
404
+ * NUL — and an RFC 5322 §3.6.4 `msg-id` is `dot-atom-text`, which admits no
405
+ * control at all. HTAB is not one here: it is the whitespace that separates
406
+ * ids (§3.2.2 FWS), the same break `fitsHeaderLine` and `replyReferences`
407
+ * cut at. One pass, no allocation, so it costs nothing a hostile header can
408
+ * multiply; never a throw, for the same reason as the line guard.
409
+ */
410
+ function hasControl(value) {
411
+ for (let i = 0; i < value.length; i++) {
412
+ const c = value.charCodeAt(i);
413
+ if (c < 32 && c !== 9 || c === 127) return true;
414
+ }
415
+ return false;
416
+ }
417
+ /**
418
+ * `chain` without any id that `hasControl` refuses, the rest in their order
419
+ * and joined by single spaces; the chain itself when there is nothing to
420
+ * drop, without allocating. Only ONE id is lost — the others still thread —
421
+ * whereas an id no line can carry drops the whole chain for the parent's id
422
+ * (`replyReferences`), because that guard is about the rendered line and
423
+ * this one is about one token. Called only on a chain already cut to
424
+ * `MAX_REPLY_REFERENCES_CHARS`, so the per-id slices in the rare bad case
425
+ * are bounded by that budget, not by the header a remote sender delivered.
426
+ */
427
+ function dropControlIds(chain) {
428
+ if (!hasControl(chain)) return chain;
429
+ const kept = [];
430
+ let start = -1;
431
+ let tainted = false;
432
+ for (let i = 0; i <= chain.length; i++) {
433
+ const c = i < chain.length ? chain.charCodeAt(i) : 32;
434
+ if (c === 32 || c === 9) {
435
+ if (start >= 0 && !tainted) kept.push(chain.slice(start, i));
436
+ start = -1;
437
+ tainted = false;
438
+ } else {
439
+ if (start < 0) start = i;
440
+ if (c < 32 || c === 127) tainted = true;
441
+ }
442
+ }
443
+ return kept.join(" ");
444
+ }
445
+ /**
446
+ * Longest decoded inbound `Subject` the default reply subject is built from;
447
+ * anything longer falls back to a bare `Re:`.
448
+ *
449
+ * RFC 5322 §2.1.1 caps a header LINE at 998 octets, and only folding lets a
450
+ * header run past it — so a subject is something that fits on a line or
451
+ * two. Real ones are tens to hundreds of characters; the longest automated
452
+ * ones (a ticket title under a stack of list tags) reach a few hundred, and
453
+ * Exchange rejects past 255. Four thousand keeps every one of those with an
454
+ * order of magnitude to spare and refuses the shape that is only a subject
455
+ * in name. What the bound buys is proportional cost: the control-character
456
+ * replacements below cost 66 bytes of heap per match, so at this size they
457
+ * cost at most 135 KB, and the reply's own `Subject` line is at most ~20 KB
458
+ * — 4096 code units x 3 UTF-8 octets, base64'd in 45-octet encoded-words
459
+ * with their framing — against a `MAX_MESSAGE_BYTES` of 10 MiB, so the
460
+ * subject alone can never push the reply over the limit.
461
+ */
462
+ const MAX_REPLY_SUBJECT_CHARS = 4096;
463
+ function prefixReplySubject(original) {
464
+ const decoded = decodeRfc2047(original);
465
+ if (decoded.length > MAX_REPLY_SUBJECT_CHARS) return "Re:";
466
+ const cleaned = decoded.replace(/[\x00-\x1f\x7f]+/g, " ").replace(/ {2,}/g, " ").trim();
467
+ if (!cleaned) return "Re:";
468
+ const prefixed = /^re:/i.test(cleaned) ? cleaned : `Re: ${cleaned}`;
469
+ if (/^[\x20-\x7e]*$/.test(prefixed) && !fitsHeaderLine("Subject", prefixed)) return "Re:";
470
+ return prefixed;
471
+ }
472
+ /**
473
+ * Longest `References` value a reply carries, in UTF-16 code units — the
474
+ * measure `MAX_REPLY_SUBJECT_CHARS` uses. It is checked on `length` alone,
475
+ * so a chain the size of the inbound message costs one property read before
476
+ * anything is scanned or sliced.
477
+ *
478
+ * RFC 5322 puts no limit on the field, but everything downstream does. RFC
479
+ * 5537 §3.4.4 has a followup agent trim it to 998 characters, and Postfix's
480
+ * `header_size_limit` discards header bytes past 100 KiB. A message-id is
481
+ * tens of characters, so 8 KiB carries a chain over a hundred replies deep
482
+ * with every id intact — an order of magnitude past any conversation — and
483
+ * a value this size, folded and encoded, is at most ~25 KB of a 10 MiB
484
+ * reply, so the chain alone can never push the reply over the limit.
485
+ * Unbounded, it could: the inbound header can be the whole 10 MiB message,
486
+ * and 10 MiB of short ids passes the line guard — every id folds — yet
487
+ * `foldHeader`'s continuations put the rendered reply over
488
+ * `MAX_MESSAGE_BYTES`, and `buildMime` threw (measured: 10,777,129 bytes
489
+ * from a 10,485,557-character chain) for a reply the guide promises is sent.
490
+ *
491
+ * Past the bound the NEWEST ids are kept, whole, and the parent's id still
492
+ * ends the chain. That is what a mail client threads on: it links the reply
493
+ * under any id it recognises, and the parent is also `In-Reply-To`. The
494
+ * root id RFC 5537 keeps is a Netnews convention (a newsreader identifies a
495
+ * thread by it); in mail it would spend the budget on an id older than
496
+ * every client in the conversation.
497
+ */
498
+ const MAX_REPLY_REFERENCES_CHARS = 8192;
499
+ /**
500
+ * The `References` value a reply carries, or `''` when nothing can be
501
+ * threaded. In order: the whole inbound chain continued by the parent's
502
+ * `messageId` when it fits `MAX_REPLY_REFERENCES_CHARS`; otherwise the
503
+ * newest ids of the chain that fit, none of them split; and the parent's id
504
+ * alone (which may be empty) when even those hold an id no line can carry.
505
+ */
506
+ function replyReferences(originalReferences, messageId) {
507
+ const parent = messageId ? ` ${messageId}` : "";
508
+ let chain = originalReferences;
509
+ const budget = MAX_REPLY_REFERENCES_CHARS - parent.length;
510
+ if (chain.length > budget) {
511
+ let cut = chain.length - budget;
512
+ while (cut < chain.length) {
513
+ const c = chain.charCodeAt(cut);
514
+ if (c === 32 || c === 9) break;
515
+ cut++;
516
+ }
517
+ chain = chain.slice(cut);
518
+ }
519
+ chain = dropControlIds(chain);
520
+ chain = `${chain}${parent}`.trim();
521
+ return fitsHeaderLine("References", chain) ? chain : messageId;
522
+ }
523
+ /**
524
+ * Minimal RFC 2047 encoded-word decoder. Handles `=?charset?B?base64?=`
525
+ * and `=?charset?Q?quoted-printable?=` segments separated by optional
526
+ * whitespace. Unknown charsets pass through (best-effort UTF-8 decode);
527
+ * malformed inputs return the original.
528
+ *
529
+ * Scope is intentionally narrow — used only for cosmetic subject
530
+ * normalization in `prefixReplySubject`. Anything that needs robust
531
+ * decoding (e.g. searching subject text) should use postal-mime's
532
+ * parsed view via `parseEmail`.
533
+ */
534
+ function decodeRfc2047(value) {
535
+ if (!value.includes("=?")) return value;
536
+ try {
537
+ const parts = [];
538
+ let last = 0;
539
+ for (const m of value.matchAll(/=\?([\w-]+)\?([BbQq])\?([^?]*)\?=(?:\s+(?==\?))?/g)) {
540
+ const [match, charset, enc, payload] = m;
541
+ const bytes = enc.toUpperCase() === "B" ? base64Decode(payload) : quotedPrintableDecode(payload);
542
+ let decoder;
543
+ try {
544
+ decoder = new TextDecoder(charset || "utf-8", { fatal: false });
545
+ } catch {
546
+ decoder = new TextDecoder("utf-8", { fatal: false });
547
+ }
548
+ parts.push(value.slice(last, m.index), decoder.decode(bytes));
549
+ last = m.index + match.length;
550
+ }
551
+ parts.push(value.slice(last));
552
+ return parts.join("");
553
+ } catch {
554
+ return value;
555
+ }
556
+ }
557
+ function base64Decode(b64) {
558
+ const binary = atob(b64);
559
+ const out = new Uint8Array(binary.length);
560
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
561
+ return out;
562
+ }
563
+ function quotedPrintableDecode(qp) {
564
+ const out = new Uint8Array(qp.length);
565
+ let kept = 0;
566
+ for (let i = 0; i < qp.length; i++) {
567
+ const ch = qp.charCodeAt(i);
568
+ if (ch === 95) out[kept++] = 32;
569
+ else if (ch === 61 && i + 2 < qp.length) {
570
+ const hex = qp.slice(i + 1, i + 3);
571
+ if (/^[0-9A-Fa-f]{2}$/.test(hex)) {
572
+ out[kept++] = parseInt(hex, 16);
573
+ i += 2;
574
+ } else out[kept++] = ch;
575
+ } else out[kept++] = ch;
576
+ }
577
+ return out.subarray(0, kept);
578
+ }
579
+ /**
580
+ * Pure helper: build the reply MIME from an inbound message + reply opts,
581
+ * with `Subject: Re: …` (no double-prefix), `In-Reply-To`, and `References`
582
+ * threaded from the original. Threading is best-effort (the inbound values
583
+ * are remote-sender controlled): an id no header line can carry is dropped,
584
+ * and a `References` chain over `MAX_REPLY_REFERENCES_CHARS` is trimmed to
585
+ * its newest ids. Exposed separately so the dispatch step (`message.reply`)
586
+ * can be tested without `cloudflare:email`.
587
+ */
588
+ async function buildReplyMessage(message, opts) {
589
+ const headers = message.headers;
590
+ const originalSubject = headers.get("Subject") ?? "";
591
+ const originalMessageId = headers.get("Message-ID") ?? "";
592
+ const originalReferences = headers.get("References") ?? "";
593
+ let fromAddr;
594
+ if (opts.from !== void 0) fromAddr = opts.from;
595
+ else {
596
+ const slug = tryReadProjectSlug();
597
+ if (slug) {
598
+ const domain = tryReadEmailDomain();
599
+ if (!domain) throw new Error("replyEmail: 'from' is required when __VOID_PROJECT_SLUG is set but __VOID_EMAIL_DOMAIN is not. Set `from` explicitly, or deploy via Void so the platform-injected __VOID_PROJECT_SLUG and __VOID_EMAIL_DOMAIN can default it to <slug>+noreply@<domain>.");
600
+ fromAddr = `${slug}+noreply@${domain}`;
601
+ } else if (readRawProjectSlug() !== void 0) throw new Error("replyEmail: 'from' is required — this project's slug cannot build a default reply sender (`<slug>+noreply@<domain>` must stay within the 64-octet local part, so the slug must be at most 56 characters). Set `from` explicitly.");
602
+ else fromAddr = message.to;
603
+ }
604
+ const toAddr = opts.to ?? message.from;
605
+ const subject = opts.subject ?? prefixReplySubject(originalSubject);
606
+ const threading = {};
607
+ const messageId = fitsHeaderLine("In-Reply-To", originalMessageId) && !hasControl(originalMessageId) ? originalMessageId : "";
608
+ if (messageId) threading.inReplyTo = messageId;
609
+ const references = replyReferences(originalReferences, messageId);
610
+ if (references) threading.references = references;
611
+ const normalized = await normalizeEmail({
612
+ from: fromAddr,
613
+ to: toAddr,
614
+ subject,
615
+ text: opts.text,
616
+ html: opts.html,
617
+ headers: opts.headers,
618
+ attachments: opts.attachments,
619
+ threading: threading.inReplyTo || threading.references ? threading : void 0
620
+ });
621
+ const { raw } = buildMime(normalized);
622
+ return {
623
+ from: normalized.from.email,
624
+ to: normalized.to[0].email,
625
+ raw,
626
+ subject
627
+ };
628
+ }
629
+ /**
630
+ * Send a threading-aware reply to an inbound message. Builds the reply MIME
631
+ * (correct `In-Reply-To` / `References` / `Subject: Re: …`) and records a
632
+ * reply intent on the message proxy. The platform router enacts the reply
633
+ * via the real `ForwardableEmailMessage.reply()` once the handler returns.
634
+ *
635
+ * The threading headers are best-effort, since the inbound values they are
636
+ * built from are remote-sender controlled: an id no header line can carry
637
+ * is dropped, and a `References` chain over 8 KiB keeps only its newest
638
+ * ids. The reply is sent either way.
639
+ */
640
+ async function replyEmail(message, opts) {
641
+ const { from, to, raw } = await buildReplyMessage(message, opts);
642
+ await message.reply({
643
+ from,
644
+ to,
645
+ raw
646
+ });
647
+ }
648
+ /**
649
+ * Whether `value` is a real `ForwardableEmailMessage` — one Cloudflare
650
+ * delivered to this worker's `email()` directly — rather than an
651
+ * `EmailEnvelope` from the platform router. Functions do not survive RPC,
652
+ * so their presence is the discriminator.
653
+ */
654
+ function isForwardableEmailMessage(value) {
655
+ if (typeof value !== "object" || value === null) return false;
656
+ const m = value;
657
+ return typeof m.setReject === "function" && typeof m.forward === "function" && typeof m.reply === "function";
658
+ }
659
+ /**
660
+ * Replay recorded `EmailAction`s on a real `ForwardableEmailMessage`, in
661
+ * order. The proxy already made `setReject` terminal (earlier forward/reply
662
+ * entries are purged, later ones dropped), so a reject is never followed by
663
+ * anything. `reply` needs a genuine `EmailMessage` — Cloudflare rejects a
664
+ * duck-typed object — so `cloudflare:email` is loaded here, and only when
665
+ * a reply was recorded.
666
+ *
667
+ * The `new Headers()` below is the one step this loop constructs from
668
+ * handler input, and it cannot fail on a recorded action: the proxy's
669
+ * `forward()` already ran the record through that constructor, so a bad
670
+ * record failed inside the handler, before any replay. (`EmailMessage`
671
+ * construction neither validates nor reads its stream — measured under
672
+ * workerd.) A reject's reason reaches the native `setReject()` as the proxy
673
+ * recorded it — already sliced and stripped the way the platform router
674
+ * would (`normalizeRejectReason`), so the SMTP reply is the same in both
675
+ * deployments. What Cloudflare itself refuses at `forward()` / `reply()`
676
+ * still throws out of the loop, as any native call would.
677
+ */
678
+ async function enactEmailActions(message, actions) {
679
+ for (const action of actions) switch (action.type) {
680
+ case "reject":
681
+ message.setReject(action.reason);
682
+ break;
683
+ case "forward":
684
+ await message.forward(action.to, action.headers ? new Headers(action.headers) : void 0);
685
+ break;
686
+ case "reply": {
687
+ const { EmailMessage } = await import("cloudflare:email");
688
+ await message.reply(new EmailMessage(action.from, action.to, bytesToReadableStream(action.raw)));
689
+ break;
690
+ }
691
+ }
692
+ }
693
+ //#endregion
694
+ export { defineEmail as a, parseEmail as c, createMessageProxy as i, replyEmail as l, MAX_INBOUND_HEADERS as n, enactEmailActions as o, ParseEmailError as r, isForwardableEmailMessage as s, MAX_INBOUND_BYTES as t };