void 0.10.13 → 0.20.1

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