stratal 0.0.21 → 0.0.23

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 (296) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/cloudflare-workers-loader.mjs +80 -7
  3. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  4. package/dist/bin/quarry.mjs +84 -160
  5. package/dist/bin/quarry.mjs.map +1 -1
  6. package/dist/cache/index.d.mts +8 -46
  7. package/dist/cache/index.d.mts.map +1 -1
  8. package/dist/cache/index.mjs +134 -97
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-uElmBtdS.d.mts} +29 -39
  11. package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
  12. package/dist/{command-BgSlsS4M.mjs → command-BvmUAPPQ.mjs} +15 -4
  13. package/dist/command-BvmUAPPQ.mjs.map +1 -0
  14. package/dist/{command-Cmmf0oHX.d.mts → command-CPhFHjG3.d.mts} +3 -2
  15. package/dist/command-CPhFHjG3.d.mts.map +1 -0
  16. package/dist/command-not-found.error-ONAZ2Bpk.mjs +14 -0
  17. package/dist/command-not-found.error-ONAZ2Bpk.mjs.map +1 -0
  18. package/dist/config/index.d.mts +24 -11
  19. package/dist/config/index.d.mts.map +1 -1
  20. package/dist/config/index.mjs +32 -57
  21. package/dist/config/index.mjs.map +1 -1
  22. package/dist/{consumer-registry-B7yUNh0q.d.mts → consumer-registry-D3iMTSdy.d.mts} +54 -22
  23. package/dist/consumer-registry-D3iMTSdy.d.mts.map +1 -0
  24. package/dist/container-storage-BmOJ4_Na.mjs +52 -0
  25. package/dist/container-storage-BmOJ4_Na.mjs.map +1 -0
  26. package/dist/{controller.decorator-B9vwn0zK.mjs → controller.decorator-C5UVeJS3.mjs} +8 -8
  27. package/dist/controller.decorator-C5UVeJS3.mjs.map +1 -0
  28. package/dist/cron/index.d.mts +103 -7
  29. package/dist/cron/index.d.mts.map +1 -1
  30. package/dist/cron/index.mjs +2 -2
  31. package/dist/cron-job-NesZRk8F.d.mts +58 -0
  32. package/dist/cron-job-NesZRk8F.d.mts.map +1 -0
  33. package/dist/{cron-manager-DQSK8uoV.mjs → cron.module-Bgzq5hiT.mjs} +47 -17
  34. package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
  35. package/dist/decorate-CuAoSZvs.mjs +16 -0
  36. package/dist/deep-merge-ByiAOZ3r.mjs +18 -0
  37. package/dist/deep-merge-ByiAOZ3r.mjs.map +1 -0
  38. package/dist/di/index.d.mts +2 -2
  39. package/dist/di/index.mjs +4 -3
  40. package/dist/di-DseMn-z9.mjs +524 -0
  41. package/dist/di-DseMn-z9.mjs.map +1 -0
  42. package/dist/email/index.d.mts +40 -122
  43. package/dist/email/index.d.mts.map +1 -1
  44. package/dist/email/index.mjs +446 -131
  45. package/dist/email/index.mjs.map +1 -1
  46. package/dist/en-CDZBMcc1.mjs +202 -0
  47. package/dist/en-CDZBMcc1.mjs.map +1 -0
  48. package/dist/{env-D1rcZ8_r.d.mts → env-ug22bJj7.d.mts} +1 -1
  49. package/dist/env-ug22bJj7.d.mts.map +1 -0
  50. package/dist/errors/index.d.mts +2 -2
  51. package/dist/errors/index.mjs +4 -2
  52. package/dist/errors-mXYxG0XB.mjs +333 -0
  53. package/dist/errors-mXYxG0XB.mjs.map +1 -0
  54. package/dist/events/index.d.mts +14 -3
  55. package/dist/events/index.d.mts.map +1 -1
  56. package/dist/events/index.mjs +2 -2
  57. package/dist/{events-CzCV8jI8.mjs → events-BXJGZjpG.mjs} +23 -13
  58. package/dist/events-BXJGZjpG.mjs.map +1 -0
  59. package/dist/exception-context-kEoMFwze.mjs +429 -0
  60. package/dist/exception-context-kEoMFwze.mjs.map +1 -0
  61. package/dist/{gateway-context-CXmXtaUP.mjs → gateway-context-TMu_AlJt.mjs} +38 -31
  62. package/dist/gateway-context-TMu_AlJt.mjs.map +1 -0
  63. package/dist/guards/index.d.mts +3 -3
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +1 -1
  66. package/dist/{guards-DU1_J9YA.mjs → guards-DALPXy3_.mjs} +6 -5
  67. package/dist/guards-DALPXy3_.mjs.map +1 -0
  68. package/dist/hono-app-CvV3hOfT.mjs +161 -0
  69. package/dist/hono-app-CvV3hOfT.mjs.map +1 -0
  70. package/dist/{http-method.decorator-BrgHMdLQ.mjs → http-method.decorator-ByWZb9DO.mjs} +7 -6
  71. package/dist/http-method.decorator-ByWZb9DO.mjs.map +1 -0
  72. package/dist/i18n/index.d.mts +238 -3
  73. package/dist/i18n/index.d.mts.map +1 -0
  74. package/dist/i18n/index.mjs +39 -3
  75. package/dist/i18n/index.mjs.map +1 -0
  76. package/dist/i18n/messages/en/index.d.mts +2 -2
  77. package/dist/i18n/messages/en/index.mjs +2 -2
  78. package/dist/i18n/utils/index.d.mts +4 -26
  79. package/dist/i18n/utils/index.d.mts.map +1 -1
  80. package/dist/i18n/utils/index.mjs +2 -2
  81. package/dist/i18n/validation/index.d.mts +3 -2
  82. package/dist/i18n/validation/index.mjs +4 -2
  83. package/dist/i18n.module-DRQAZoSZ.mjs +222 -0
  84. package/dist/i18n.module-DRQAZoSZ.mjs.map +1 -0
  85. package/dist/i18n.tokens-CZ_v8oyS.mjs +19 -0
  86. package/dist/i18n.tokens-CZ_v8oyS.mjs.map +1 -0
  87. package/dist/{index-7-hU3GTV.d.mts → index-0ItCjaqw.d.mts} +1 -1
  88. package/dist/index-0ItCjaqw.d.mts.map +1 -0
  89. package/dist/index-B5JBRcWD.d.mts +544 -0
  90. package/dist/index-B5JBRcWD.d.mts.map +1 -0
  91. package/dist/index-BUt92sAE.d.mts +124 -0
  92. package/dist/index-BUt92sAE.d.mts.map +1 -0
  93. package/dist/{index-ByOyTmqf.d.mts → index-B_JoEl3V.d.mts} +751 -2229
  94. package/dist/index-B_JoEl3V.d.mts.map +1 -0
  95. package/dist/index-DtBNIFuP.d.mts +42 -0
  96. package/dist/index-DtBNIFuP.d.mts.map +1 -0
  97. package/dist/{index-C1KvMncZ.d.mts → index-HgOLNruQ.d.mts} +3 -108
  98. package/dist/index-HgOLNruQ.d.mts.map +1 -0
  99. package/dist/index.d.mts +6 -43
  100. package/dist/index.mjs +3 -2
  101. package/dist/{is-command-C6a7WTPw.mjs → is-command-CEPO9n8c.mjs} +2 -2
  102. package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
  103. package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
  104. package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
  105. package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
  106. package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
  107. package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
  108. package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
  109. package/dist/locale-url-nZrZxqJP.mjs +44 -0
  110. package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
  111. package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
  112. package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
  113. package/dist/logger/index.d.mts +2 -2
  114. package/dist/logger/index.mjs +170 -2
  115. package/dist/logger/index.mjs.map +1 -0
  116. package/dist/macroable/index.d.mts +2 -2
  117. package/dist/macroable/index.mjs +1 -1
  118. package/dist/{macroable-BmufBshB.mjs → macroable-cvDTFZ_A.mjs} +1 -1
  119. package/dist/{macroable-BmufBshB.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
  120. package/dist/metadata-DzzprcID.mjs +39 -0
  121. package/dist/metadata-DzzprcID.mjs.map +1 -0
  122. package/dist/module/index.d.mts +7 -24
  123. package/dist/module/index.d.mts.map +1 -1
  124. package/dist/module/index.mjs +10 -2
  125. package/dist/module/index.mjs.map +1 -0
  126. package/dist/module-registry-Dm-pqHd3.mjs +554 -0
  127. package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
  128. package/dist/module.decorator-CYHY6pG5.mjs +19 -0
  129. package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
  130. package/dist/openapi/index.d.mts +44 -8
  131. package/dist/openapi/index.d.mts.map +1 -1
  132. package/dist/openapi/index.mjs +3 -3
  133. package/dist/openapi-CstuTM8S.mjs +309 -0
  134. package/dist/openapi-CstuTM8S.mjs.map +1 -0
  135. package/dist/{openapi-tools.service-Zs-Ewv7F.mjs → openapi-tools.service-BC5EC3R3.mjs} +8 -2
  136. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
  137. package/dist/{openapi.service-Bt9bCIrd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
  138. package/dist/openapi.service-YhTiJ1bO.d.mts.map +1 -0
  139. package/dist/quarry/index.d.mts +14 -163
  140. package/dist/quarry/index.d.mts.map +1 -1
  141. package/dist/quarry/index.mjs +6 -5
  142. package/dist/quarry/runner.d.mts +184 -0
  143. package/dist/quarry/runner.d.mts.map +1 -0
  144. package/dist/quarry/runner.mjs +945 -0
  145. package/dist/quarry/runner.mjs.map +1 -0
  146. package/dist/quarry-registry-CXg0RFXq.d.mts +69 -0
  147. package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
  148. package/dist/quarry.module-BuRPGMDm.mjs +312 -0
  149. package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
  150. package/dist/queue/index.d.mts +3 -3
  151. package/dist/queue/index.mjs +57 -48
  152. package/dist/queue/index.mjs.map +1 -1
  153. package/dist/queue.module-nddvxzCB.mjs +613 -0
  154. package/dist/queue.module-nddvxzCB.mjs.map +1 -0
  155. package/dist/queue.tokens-DjHnFmre.mjs +11 -0
  156. package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
  157. package/dist/{r2-storage.provider-DuonKeYm.mjs → r2-storage.provider-DCxQt9dD.mjs} +6 -6
  158. package/dist/r2-storage.provider-DCxQt9dD.mjs.map +1 -0
  159. package/dist/{rate-limit.decorator-6qzNcSOt.mjs → rate-limit.decorator-BPAie_p3.mjs} +6 -11
  160. package/dist/rate-limit.decorator-BPAie_p3.mjs.map +1 -0
  161. package/dist/rate-limiter/index.d.mts +11 -50
  162. package/dist/rate-limiter/index.d.mts.map +1 -1
  163. package/dist/rate-limiter/index.mjs +33 -42
  164. package/dist/rate-limiter/index.mjs.map +1 -1
  165. package/dist/route-name-DGoBOfPg.mjs +171 -0
  166. package/dist/route-name-DGoBOfPg.mjs.map +1 -0
  167. package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
  168. package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
  169. package/dist/route-registry-CYqLp2Nj.mjs +123 -0
  170. package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
  171. package/dist/router/index.d.mts +2 -2
  172. package/dist/router/index.mjs +18 -7
  173. package/dist/router-CWGBD-Bg.mjs +78 -0
  174. package/dist/router-CWGBD-Bg.mjs.map +1 -0
  175. package/dist/router-resolver-D4YlPNlm.mjs +88 -0
  176. package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
  177. package/dist/seeder/index.d.mts +16 -11
  178. package/dist/seeder/index.d.mts.map +1 -1
  179. package/dist/seeder/index.mjs +5 -3
  180. package/dist/seeder-7ubkms-Y.mjs +81 -0
  181. package/dist/seeder-7ubkms-Y.mjs.map +1 -0
  182. package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
  183. package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
  184. package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
  185. package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
  186. package/dist/{signed-url-BQPbv2In.mjs → signed-url-DIU0sK_6.mjs} +1 -1
  187. package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
  188. package/dist/storage/index.d.mts +15 -39
  189. package/dist/storage/index.d.mts.map +1 -1
  190. package/dist/storage/index.mjs +3 -3
  191. package/dist/storage/providers/index.d.mts +2 -2
  192. package/dist/storage/providers/index.d.mts.map +1 -1
  193. package/dist/storage/providers/index.mjs +1 -1
  194. package/dist/{storage-D8CBP72Z.mjs → storage-MDZypIE9.mjs} +66 -59
  195. package/dist/storage-MDZypIE9.mjs.map +1 -0
  196. package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -3
  197. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
  198. package/dist/storage.error-Dnib4VHc.mjs +8 -0
  199. package/dist/storage.error-Dnib4VHc.mjs.map +1 -0
  200. package/dist/stratal-DL9M38_s.mjs +383 -0
  201. package/dist/stratal-DL9M38_s.mjs.map +1 -0
  202. package/dist/stratal-DwDJPY9N.d.mts +43 -0
  203. package/dist/stratal-DwDJPY9N.d.mts.map +1 -0
  204. package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
  205. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
  206. package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
  207. package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
  208. package/dist/{types-cySNS_lp.d.mts → types-CmV_9xBD.d.mts} +1 -1
  209. package/dist/types-CmV_9xBD.d.mts.map +1 -0
  210. package/dist/uri-h7Q8Jug9.mjs +251 -0
  211. package/dist/uri-h7Q8Jug9.mjs.map +1 -0
  212. package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DAWYasuP.mjs} +7 -4
  213. package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
  214. package/dist/validation-CpOjviyT.mjs +49 -0
  215. package/dist/validation-CpOjviyT.mjs.map +1 -0
  216. package/dist/validation.context-CRvmrhq7.mjs +117 -0
  217. package/dist/validation.context-CRvmrhq7.mjs.map +1 -0
  218. package/dist/versioning.service-C6aHky8-.mjs +36 -0
  219. package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
  220. package/dist/websocket/index.d.mts +16 -14
  221. package/dist/websocket/index.d.mts.map +1 -1
  222. package/dist/websocket/index.mjs +2 -2
  223. package/dist/workers/index.d.mts +2 -2
  224. package/dist/workers/index.d.mts.map +1 -1
  225. package/dist/workers/index.mjs +3 -2
  226. package/dist/workers/index.mjs.map +1 -1
  227. package/dist/zod-eKqqhZ5_.mjs +72 -0
  228. package/dist/zod-eKqqhZ5_.mjs.map +1 -0
  229. package/dist/{index-Bnpfq6uk.d.mts → zod-wecrEVAs.d.mts} +63 -133
  230. package/dist/zod-wecrEVAs.d.mts.map +1 -0
  231. package/package.json +28 -39
  232. package/dist/base-email.provider-CfQCA08m.mjs +0 -42
  233. package/dist/base-email.provider-CfQCA08m.mjs.map +0 -1
  234. package/dist/cache.service-DsnKuNyO.d.mts.map +0 -1
  235. package/dist/cache.tokens-B7Rw1C9Q.mjs +0 -6
  236. package/dist/cache.tokens-B7Rw1C9Q.mjs.map +0 -1
  237. package/dist/colors-DJaRDXoS.mjs +0 -16
  238. package/dist/colors-DJaRDXoS.mjs.map +0 -1
  239. package/dist/command-BgSlsS4M.mjs.map +0 -1
  240. package/dist/command-Cmmf0oHX.d.mts.map +0 -1
  241. package/dist/consumer-registry-B7yUNh0q.d.mts.map +0 -1
  242. package/dist/controller.decorator-B9vwn0zK.mjs.map +0 -1
  243. package/dist/cron-manager-CmTimEjf.d.mts +0 -131
  244. package/dist/cron-manager-CmTimEjf.d.mts.map +0 -1
  245. package/dist/cron-manager-DQSK8uoV.mjs.map +0 -1
  246. package/dist/en-DSH_bhh6.mjs +0 -308
  247. package/dist/en-DSH_bhh6.mjs.map +0 -1
  248. package/dist/env-D1rcZ8_r.d.mts.map +0 -1
  249. package/dist/errors-COW9-Mar.mjs +0 -1739
  250. package/dist/errors-COW9-Mar.mjs.map +0 -1
  251. package/dist/errors-ORxu1-Bb.mjs +0 -74
  252. package/dist/errors-ORxu1-Bb.mjs.map +0 -1
  253. package/dist/events-CzCV8jI8.mjs.map +0 -1
  254. package/dist/gateway-context-CXmXtaUP.mjs.map +0 -1
  255. package/dist/guards-DU1_J9YA.mjs.map +0 -1
  256. package/dist/http-method.decorator-BrgHMdLQ.mjs.map +0 -1
  257. package/dist/i18n.module-CzXLW9Hy.mjs +0 -2532
  258. package/dist/i18n.module-CzXLW9Hy.mjs.map +0 -1
  259. package/dist/index-7-hU3GTV.d.mts.map +0 -1
  260. package/dist/index-Bnpfq6uk.d.mts.map +0 -1
  261. package/dist/index-ByOyTmqf.d.mts.map +0 -1
  262. package/dist/index-C1KvMncZ.d.mts.map +0 -1
  263. package/dist/index-DBd_2wv8.d.mts +0 -263
  264. package/dist/index-DBd_2wv8.d.mts.map +0 -1
  265. package/dist/index-DUzWs0z7.d.mts +0 -494
  266. package/dist/index-DUzWs0z7.d.mts.map +0 -1
  267. package/dist/index.d.mts.map +0 -1
  268. package/dist/logger-DlV7NtvD.mjs +0 -440
  269. package/dist/logger-DlV7NtvD.mjs.map +0 -1
  270. package/dist/module-BzLg57FK.mjs +0 -866
  271. package/dist/module-BzLg57FK.mjs.map +0 -1
  272. package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
  273. package/dist/openapi.service-Bt9bCIrd.d.mts.map +0 -1
  274. package/dist/quarry-registry-BwY2hOxm.mjs +0 -699
  275. package/dist/quarry-registry-BwY2hOxm.mjs.map +0 -1
  276. package/dist/queue.module-BhCjZp6H.mjs +0 -409
  277. package/dist/queue.module-BhCjZp6H.mjs.map +0 -1
  278. package/dist/r2-storage.provider-DuonKeYm.mjs.map +0 -1
  279. package/dist/rate-limit.decorator-6qzNcSOt.mjs.map +0 -1
  280. package/dist/resend.provider-DB4IlFjG.mjs +0 -68
  281. package/dist/resend.provider-DB4IlFjG.mjs.map +0 -1
  282. package/dist/seeder-zoEfEw9i.mjs +0 -138
  283. package/dist/seeder-zoEfEw9i.mjs.map +0 -1
  284. package/dist/setup-CefZKV_e.mjs +0 -37
  285. package/dist/setup-CefZKV_e.mjs.map +0 -1
  286. package/dist/smtp.provider-B6D7zuWX.mjs +0 -76
  287. package/dist/smtp.provider-B6D7zuWX.mjs.map +0 -1
  288. package/dist/storage-D8CBP72Z.mjs.map +0 -1
  289. package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
  290. package/dist/stratal-CNwpbSZl.mjs +0 -535
  291. package/dist/stratal-CNwpbSZl.mjs.map +0 -1
  292. package/dist/types-cySNS_lp.d.mts.map +0 -1
  293. package/dist/usage-generator-BUdlhnCK.mjs.map +0 -1
  294. package/dist/validation-DtJwAv7O.mjs +0 -248
  295. package/dist/validation-DtJwAv7O.mjs.map +0 -1
  296. /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
@@ -1,12 +1,18 @@
1
- import { H as ApplicationError, k as ERROR_CODES } from "../errors-COW9-Mar.mjs";
2
- import { a as __decorate, o as __decorateParam, p as Transient, s as __decorateMetadata, u as LOGGER_TOKENS } from "../logger-DlV7NtvD.mjs";
3
- import { k as Module } from "../module-BzLg57FK.mjs";
4
- import { i as z, s as withI18n } from "../validation-DtJwAv7O.mjs";
5
- import { c as QUEUE_TOKENS } from "../queue.module-BhCjZp6H.mjs";
1
+ import { c as Transient, d as inject } from "../di-DseMn-z9.mjs";
2
+ import { a as ApplicationError } from "../container-storage-BmOJ4_Na.mjs";
3
+ import { n as __decorateParam, t as __decorate } from "../decorate-CuAoSZvs.mjs";
4
+ import { LOGGER_TOKENS } from "../logger/index.mjs";
5
+ import "../errors-mXYxG0XB.mjs";
6
+ import { n as Module } from "../module.decorator-CYHY6pG5.mjs";
7
+ import "../module/index.mjs";
8
+ import { t as QUEUE_TOKENS } from "../queue.tokens-DjHnFmre.mjs";
6
9
  import "../queue/index.mjs";
7
- import { u as STORAGE_TOKENS } from "../storage-D8CBP72Z.mjs";
8
- import { inject } from "tsyringe";
9
- import { render } from "@react-email/render";
10
+ import { p as STORAGE_TOKENS } from "../storage-MDZypIE9.mjs";
11
+ import { r as z } from "../zod-eKqqhZ5_.mjs";
12
+ import { t as withZodI18n } from "../validation-CpOjviyT.mjs";
13
+ //#region src/email/email.error.ts
14
+ var EmailError = class extends ApplicationError {};
15
+ //#endregion
10
16
  //#region src/email/email.tokens.ts
11
17
  /**
12
18
  * Dependency Injection Tokens for Email Module
@@ -36,12 +42,24 @@ const EMAIL_TOKENS = {
36
42
  EmailProvider: Symbol.for("stratal:email:provider"),
37
43
  /**
38
44
  * Queue sender for email dispatch.
39
- * Bound via EmailModule.forRoot({ queue: 'queue-name' })
45
+ * Bound via EmailModule.forRoot({ queue: 'QUEUE_BINDING_NAME' })
40
46
  */
41
47
  EmailQueue: Symbol.for("stratal:email:queue")
42
48
  };
43
49
  //#endregion
44
50
  //#region src/email/consumers/email.consumer.ts
51
+ /**
52
+ * Strictly decode a base64 attachment payload. `Buffer.from(_, 'base64')` is
53
+ * lenient and silently drops invalid characters, which would ship a corrupt
54
+ * attachment. We re-encode and compare (modulo canonical padding) to reject
55
+ * malformed input loudly instead.
56
+ */
57
+ function decodeBase64Attachment(content, filename) {
58
+ const buffer = Buffer.from(content, "base64");
59
+ const normalize = (value) => value.replace(/=+$/, "");
60
+ if (normalize(buffer.toString("base64")) !== normalize(content)) throw new EmailError(`Invalid base64 content for attachment "${filename}"`);
61
+ return buffer;
62
+ }
45
63
  let EmailConsumer = class EmailConsumer {
46
64
  logger;
47
65
  providerFactory;
@@ -64,7 +82,7 @@ let EmailConsumer = class EmailConsumer {
64
82
  });
65
83
  try {
66
84
  const resolvedAttachments = await this.resolveAttachments(payload.attachments);
67
- const result = await (await this.providerFactory.create()).send({
85
+ const result = await this.providerFactory.create().send({
68
86
  ...payload,
69
87
  attachments: resolvedAttachments
70
88
  });
@@ -103,7 +121,7 @@ let EmailConsumer = class EmailConsumer {
103
121
  return Promise.all(attachments.map(async (attachment) => {
104
122
  if ("content" in attachment) return {
105
123
  filename: attachment.filename,
106
- content: Buffer.from(attachment.content, "base64"),
124
+ content: decodeBase64Attachment(attachment.content, attachment.filename),
107
125
  contentType: attachment.contentType
108
126
  };
109
127
  const result = await this.storage.download(attachment.storageKey, attachment.disk);
@@ -119,12 +137,7 @@ EmailConsumer = __decorate([
119
137
  Transient(),
120
138
  __decorateParam(0, inject(LOGGER_TOKENS.LoggerService)),
121
139
  __decorateParam(1, inject(EMAIL_TOKENS.EmailProviderFactory)),
122
- __decorateParam(2, inject(STORAGE_TOKENS.StorageService)),
123
- __decorateMetadata("design:paramtypes", [
124
- Object,
125
- Object,
126
- Object
127
- ])
140
+ __decorateParam(2, inject(STORAGE_TOKENS.StorageService))
128
141
  ], EmailConsumer);
129
142
  //#endregion
130
143
  //#region src/email/services/email.service.ts
@@ -142,11 +155,16 @@ let EmailService = class EmailService {
142
155
  * @param input - Email message details
143
156
  */
144
157
  async send({ template, ...input }) {
158
+ let html;
159
+ if (template) {
160
+ const { render } = await import("@react-email/render");
161
+ html = await render(template);
162
+ }
145
163
  await this.queue.dispatch({
146
164
  type: "email.send",
147
165
  payload: {
148
166
  ...input,
149
- html: template ? await render(template) : void 0
167
+ html
150
168
  }
151
169
  });
152
170
  }
@@ -162,102 +180,424 @@ let EmailService = class EmailService {
162
180
  for (const message of input.messages) await this.send(message);
163
181
  }
164
182
  };
165
- EmailService = __decorate([
166
- Transient(EMAIL_TOKENS.EmailService),
167
- __decorateParam(0, inject(EMAIL_TOKENS.EmailQueue)),
168
- __decorateMetadata("design:paramtypes", [Object])
169
- ], EmailService);
183
+ EmailService = __decorate([Transient(EMAIL_TOKENS.EmailService), __decorateParam(0, inject(EMAIL_TOKENS.EmailQueue))], EmailService);
170
184
  //#endregion
171
- //#region src/email/errors/resend-api-key-missing.error.ts
172
- /**
173
- * ResendApiKeyMissingError
174
- *
175
- * Thrown when the Resend API key is not configured in environment variables.
176
- * This prevents the Resend email provider from initializing.
177
- *
178
- * Resolution: Set the RESEND_EMAIL_API_KEY environment variable.
179
- */
180
- var ResendApiKeyMissingError = class extends ApplicationError {
181
- constructor() {
182
- super("errors.email.resendApiKeyMissing", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR);
185
+ //#region src/email/smtp/smtp-client.ts
186
+ /** Abort a server read if it stalls, so a hung endpoint can't wedge the Worker. */
187
+ const RESPONSE_TIMEOUT_MS = 3e4;
188
+ function parseSmtpUrl(config) {
189
+ try {
190
+ const parsed = new URL(config.url);
191
+ const secure = parsed.protocol === "smtps:";
192
+ return {
193
+ host: parsed.hostname,
194
+ port: parsed.port ? parseInt(parsed.port, 10) : secure ? 465 : 587,
195
+ secure,
196
+ username: parsed.username ? decodeURIComponent(parsed.username) : void 0,
197
+ password: parsed.password ? decodeURIComponent(parsed.password) : void 0
198
+ };
199
+ } catch {
200
+ throw new EmailError(`Invalid SMTP URL: ${config.url}`);
201
+ }
202
+ }
203
+ /** Parse an EHLO reply into the capabilities/mechanisms it advertises. */
204
+ function parseCapabilities(ehloText) {
205
+ const auth = /* @__PURE__ */ new Set();
206
+ let startTls = false;
207
+ for (const rawLine of ehloText.split("\r\n")) {
208
+ const line = rawLine.slice(4).trim().toUpperCase();
209
+ if (!line) continue;
210
+ const [keyword, ...rest] = line.split(/\s+/);
211
+ if (keyword === "STARTTLS") startTls = true;
212
+ if (keyword === "AUTH") rest.forEach((m) => auth.add(m));
213
+ }
214
+ return {
215
+ startTls,
216
+ auth
217
+ };
218
+ }
219
+ var SmtpClient = class {
220
+ parsed;
221
+ constructor(config) {
222
+ this.parsed = parseSmtpUrl(config);
223
+ }
224
+ async send(mimeRaw, options) {
225
+ const { connect } = await import("cloudflare:sockets");
226
+ const { host, port, secure, username, password } = this.parsed;
227
+ const implicitTls = secure || port === 465;
228
+ const socket = connect({
229
+ hostname: host,
230
+ port
231
+ }, {
232
+ secureTransport: implicitTls ? "on" : "starttls",
233
+ allowHalfOpen: false
234
+ });
235
+ let activeSocket = socket;
236
+ let reader = socket.readable.getReader();
237
+ let writer = socket.writable.getWriter();
238
+ const decoder = new TextDecoder();
239
+ const encoder = new TextEncoder();
240
+ const readChunk = async () => {
241
+ const read = reader.read();
242
+ read.catch(() => {});
243
+ let timer;
244
+ const timeout = new Promise((_, reject) => {
245
+ timer = setTimeout(() => reject(new EmailError(`SMTP timeout: no response within ${RESPONSE_TIMEOUT_MS}ms`)), RESPONSE_TIMEOUT_MS);
246
+ });
247
+ try {
248
+ return await Promise.race([read, timeout]);
249
+ } finally {
250
+ clearTimeout(timer);
251
+ }
252
+ };
253
+ let leftover = "";
254
+ const readResponse = async () => {
255
+ let buffer = leftover;
256
+ leftover = "";
257
+ while (true) {
258
+ if (buffer.indexOf("\r\n") !== -1) {
259
+ const lines = buffer.split("\r\n");
260
+ let consumed = 0;
261
+ for (let i = 0; i < lines.length - 1; i++) {
262
+ const line = lines[i];
263
+ consumed += line.length + 2;
264
+ if (line[3] === " ") {
265
+ const code = parseInt(line.slice(0, 3), 10);
266
+ leftover = buffer.slice(consumed);
267
+ return {
268
+ code,
269
+ text: buffer.slice(0, consumed)
270
+ };
271
+ }
272
+ }
273
+ }
274
+ const result = await readChunk();
275
+ if (result.done) throw new EmailError("SMTP connection closed unexpectedly");
276
+ buffer += decoder.decode(result.value, { stream: true });
277
+ }
278
+ };
279
+ const sendCommand = async (command) => {
280
+ await writer.write(encoder.encode(command + "\r\n"));
281
+ return readResponse();
282
+ };
283
+ const expectCode = async (command, expected) => {
284
+ const response = await sendCommand(command);
285
+ if (response.code !== expected) throw new EmailError(`SMTP error: expected ${expected}, got ${response.code}: ${response.text.trim()}`);
286
+ return response.text;
287
+ };
288
+ try {
289
+ const greeting = await readResponse();
290
+ if (greeting.code !== 220) throw new EmailError(`SMTP server rejected connection: ${greeting.text.trim()}`);
291
+ let capabilities = parseCapabilities(await expectCode(`EHLO ${host}`, 250));
292
+ let encrypted = implicitTls;
293
+ if (!implicitTls && capabilities.startTls) {
294
+ await expectCode("STARTTLS", 220);
295
+ reader.releaseLock();
296
+ writer.releaseLock();
297
+ activeSocket = socket.startTls();
298
+ reader = activeSocket.readable.getReader();
299
+ writer = activeSocket.writable.getWriter();
300
+ leftover = "";
301
+ capabilities = parseCapabilities(await expectCode(`EHLO ${host}`, 250));
302
+ encrypted = true;
303
+ }
304
+ if (username && password) {
305
+ if (!encrypted) throw new EmailError("Refusing to send SMTP credentials over an unencrypted connection: the server did not offer STARTTLS. Use an smtps:// URL or a server that supports STARTTLS.");
306
+ await this.authenticate(expectCode, capabilities, username, password);
307
+ }
308
+ await expectCode(`MAIL FROM:<${options.from}>`, 250);
309
+ for (const recipient of options.to) await expectCode(`RCPT TO:<${recipient}>`, 250);
310
+ await expectCode("DATA", 354);
311
+ const dotStuffed = (mimeRaw.startsWith(".") ? "." + mimeRaw : mimeRaw).replace(/\r\n\./g, "\r\n..");
312
+ await writer.write(encoder.encode(dotStuffed + "\r\n.\r\n"));
313
+ const dataResponse = await readResponse();
314
+ if (dataResponse.code !== 250) throw new EmailError(`SMTP DATA rejected: ${dataResponse.text.trim()}`);
315
+ const messageId = dataResponse.text.match(/<([^>]+)>/)?.[1] ?? `${Date.now()}@${host}`;
316
+ await sendCommand("QUIT").catch(() => {});
317
+ return { messageId };
318
+ } finally {
319
+ reader.releaseLock();
320
+ writer.releaseLock();
321
+ await activeSocket.close().catch(() => {});
322
+ }
323
+ }
324
+ /** Authenticate using a server-advertised SASL mechanism (PLAIN or LOGIN). */
325
+ async authenticate(expectCode, capabilities, username, password) {
326
+ if (capabilities.auth.has("PLAIN")) {
327
+ await expectCode(`AUTH PLAIN ${Buffer.from(`\0${username}\0${password}`).toString("base64")}`, 235);
328
+ return;
329
+ }
330
+ if (capabilities.auth.has("LOGIN")) {
331
+ await expectCode("AUTH LOGIN", 334);
332
+ await expectCode(Buffer.from(username).toString("base64"), 334);
333
+ await expectCode(Buffer.from(password).toString("base64"), 235);
334
+ return;
335
+ }
336
+ throw new EmailError(capabilities.auth.size === 0 ? "SMTP credentials were provided but the server does not advertise AUTH." : `SMTP server does not support a known AUTH mechanism (offered: ${[...capabilities.auth].join(", ")}). Supported: PLAIN, LOGIN.`);
183
337
  }
184
338
  };
185
339
  //#endregion
186
- //#region src/email/errors/smtp-configuration-missing.error.ts
340
+ //#region src/email/smtp/mime.ts
187
341
  /**
188
- * SmtpConfigurationMissingError
189
- *
190
- * Thrown when SMTP configuration is not found in environment variables.
191
- * This prevents the SMTP email provider from initializing.
192
- *
193
- * Resolution: Set the SMTP_URL environment variable with format: smtp://user:pass@host:port
342
+ * Hard cap on a single attachment's resolved size (20 MB). Attachments are fully
343
+ * buffered into memory before base64 encoding, so an unbounded attachment would
344
+ * let a single message exhaust the Worker's memory. Exceeding this throws.
194
345
  */
195
- var SmtpConfigurationMissingError = class extends ApplicationError {
196
- constructor() {
197
- super("errors.email.smtpConfigurationMissing", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR);
198
- }
199
- };
200
- //#endregion
201
- //#region src/email/errors/smtp-host-missing.error.ts
346
+ const MAX_ATTACHMENT_SIZE_BYTES = 20 * 1024 * 1024;
347
+ function generateBoundary() {
348
+ return `----=_Part_${crypto.randomUUID().replace(/-/g, "")}`;
349
+ }
350
+ function generateMessageId(fromEmail) {
351
+ const domain = fromEmail.split("@")[1] || "localhost";
352
+ return `<${crypto.randomUUID()}@${domain}>`;
353
+ }
354
+ function isAscii(str) {
355
+ return /^[ -~]*$/.test(str);
356
+ }
357
+ /** Remove CR/LF so a value can't inject extra headers (header smuggling). */
358
+ function stripCrlf(value) {
359
+ return value.replace(/[\r\n]/g, "");
360
+ }
202
361
  /**
203
- * SmtpHostMissingError
204
- *
205
- * Thrown when SMTP host could not be parsed from SMTP_URL or is empty.
206
- * This prevents the SMTP email provider from initializing.
207
- *
208
- * Resolution: Ensure SMTP_URL is correctly formatted: smtp://user:pass@host:port
362
+ * Encode a header value as one or more RFC 2047 base64 encoded-words, folding so
363
+ * no produced line exceeds the 76-char limit strict MTAs enforce. The UTF-8 byte
364
+ * stream is chunked at <=45 source bytes per encoded-word (<=60 base64 chars,
365
+ * keeping `=?UTF-8?B?...?=` <=75 chars) WITHOUT splitting a multibyte sequence.
366
+ * Multiple encoded-words are folded with CRLF + a single space.
209
367
  */
210
- var SmtpHostMissingError = class extends ApplicationError {
211
- constructor() {
212
- super("errors.email.smtpHostMissing", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR);
368
+ function encodeEncodedWords(clean) {
369
+ const bytes = Buffer.from(clean, "utf-8");
370
+ const MAX_SOURCE_BYTES = 45;
371
+ const words = [];
372
+ let i = 0;
373
+ while (i < bytes.length) {
374
+ let end = Math.min(i + MAX_SOURCE_BYTES, bytes.length);
375
+ while (end > i && end < bytes.length && (bytes[end] & 192) === 128) end--;
376
+ const slice = bytes.subarray(i, end);
377
+ words.push(`=?UTF-8?B?${slice.toString("base64")}?=`);
378
+ i = end;
213
379
  }
214
- };
215
- //#endregion
216
- //#region src/email/errors/email-smtp-connection-failed.error.ts
380
+ return words.join("\r\n ");
381
+ }
382
+ function encodeHeaderValue(value) {
383
+ const clean = stripCrlf(value);
384
+ if (isAscii(clean)) return clean;
385
+ return encodeEncodedWords(clean);
386
+ }
217
387
  /**
218
- * EmailSmtpConnectionFailedError
219
- *
220
- * Thrown when connection to SMTP server fails during email sending.
221
- * This is a runtime error that may be temporary.
222
- *
223
- * Resolution: Check SMTP server availability, network connectivity, or wait and retry.
388
+ * Validate an envelope address (used verbatim in `MAIL FROM`/`RCPT TO` SMTP
389
+ * commands). Raw CR/LF would allow SMTP command injection, so we throw rather
390
+ * than silently strip a corrupted envelope must never reach the wire.
224
391
  */
225
- var EmailSmtpConnectionFailedError = class extends ApplicationError {
226
- constructor(smtpHost, smtpPort) {
227
- super("errors.email.smtpConnectionFailed", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, {
228
- smtpHost,
229
- smtpPort
230
- });
392
+ function assertNoCrlf(address) {
393
+ if (/[\r\n]/.test(address)) throw new EmailError("Email envelope address contains CR/LF, which would allow SMTP command injection");
394
+ }
395
+ /**
396
+ * Escape a value for an RFC 5322 quoted-string: backslash MUST be escaped first
397
+ * (so the escapes added for `"` aren't themselves re-escaped), then `"`.
398
+ */
399
+ function escapeQuotedString(value) {
400
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
401
+ }
402
+ /**
403
+ * Encode a MIME parameter (e.g. `name`/`filename`) safely. ASCII values are
404
+ * emitted as a quoted-string with `"`/`\` escaped; non-ASCII values use the
405
+ * RFC 2231 extended syntax (`param*=UTF-8''…`). CR/LF are always stripped so a
406
+ * crafted filename can't inject headers or break the MIME structure.
407
+ */
408
+ function encodeMimeParam(param, value) {
409
+ const clean = stripCrlf(value);
410
+ if (isAscii(clean)) return `${param}="${escapeQuotedString(clean)}"`;
411
+ return `${param}*=UTF-8''${Array.from(Buffer.from(clean, "utf-8")).map((b) => /[A-Za-z0-9!#$&+\-.^_`|~]/.test(String.fromCharCode(b)) ? String.fromCharCode(b) : `%${b.toString(16).toUpperCase().padStart(2, "0")}`).join("")}`;
412
+ }
413
+ /**
414
+ * Extract the bare address for the SMTP envelope and validate it has no raw
415
+ * CR/LF before it is written into a `MAIL FROM`/`RCPT TO` command.
416
+ */
417
+ function extractEmail(address) {
418
+ assertNoCrlf(address);
419
+ const match = address.match(/<([^>]+)>/);
420
+ const email = (match ? match[1] : address).trim();
421
+ if (/[<>\s]/.test(email)) throw new EmailError(`Invalid email address for SMTP envelope: ${JSON.stringify(address)}`);
422
+ return email;
423
+ }
424
+ function formatAddress(email, name) {
425
+ const cleanEmail = stripCrlf(email);
426
+ if (!name) return cleanEmail;
427
+ const cleanName = stripCrlf(name);
428
+ return `${isAscii(cleanName) ? `"${escapeQuotedString(cleanName)}"` : encodeHeaderValue(cleanName)} <${cleanEmail}>`;
429
+ }
430
+ function formatDate(date) {
431
+ return date.toUTCString().replace("GMT", "+0000");
432
+ }
433
+ function wrapBase64(base64) {
434
+ const lines = [];
435
+ for (let i = 0; i < base64.length; i += 76) lines.push(base64.slice(i, i + 76));
436
+ return lines.join("\r\n");
437
+ }
438
+ async function resolveContent(content) {
439
+ const buffer = Buffer.isBuffer(content) ? content : Buffer.from(await new Response(content).arrayBuffer());
440
+ if (buffer.byteLength > 20971520) throw new EmailError(`Email attachment exceeds the maximum size of ${MAX_ATTACHMENT_SIZE_BYTES} bytes (got ${buffer.byteLength} bytes)`);
441
+ return buffer;
442
+ }
443
+ /** Base64-encode a text body so arbitrary content (long lines, leading dots,
444
+ * 8-bit data) is transported safely regardless of line length or SMTP escaping. */
445
+ function encodeTextBody(content) {
446
+ return wrapBase64(Buffer.from(content, "utf-8").toString("base64"));
447
+ }
448
+ function buildBodyPart(text, html) {
449
+ if (text && html) {
450
+ const boundary = generateBoundary();
451
+ return {
452
+ content: [
453
+ `--${boundary}`,
454
+ "Content-Type: text/plain; charset=utf-8",
455
+ "Content-Transfer-Encoding: base64",
456
+ "",
457
+ encodeTextBody(text),
458
+ `--${boundary}`,
459
+ "Content-Type: text/html; charset=utf-8",
460
+ "Content-Transfer-Encoding: base64",
461
+ "",
462
+ encodeTextBody(html),
463
+ `--${boundary}--`
464
+ ].join("\r\n"),
465
+ contentType: `multipart/alternative; boundary="${boundary}"`
466
+ };
231
467
  }
232
- };
468
+ if (html) return {
469
+ content: encodeTextBody(html),
470
+ contentType: "text/html; charset=utf-8",
471
+ cte: "base64"
472
+ };
473
+ return {
474
+ content: encodeTextBody(text ?? ""),
475
+ contentType: "text/plain; charset=utf-8",
476
+ cte: "base64"
477
+ };
478
+ }
479
+ async function buildAttachmentPart(attachment) {
480
+ const base64 = wrapBase64((await resolveContent(attachment.content)).toString("base64"));
481
+ return [
482
+ `Content-Type: ${attachment.contentType || "application/octet-stream"}; ${encodeMimeParam("name", attachment.filename)}`,
483
+ "Content-Transfer-Encoding: base64",
484
+ `Content-Disposition: attachment; ${encodeMimeParam("filename", attachment.filename)}`,
485
+ "",
486
+ base64
487
+ ].join("\r\n");
488
+ }
489
+ async function buildMimeMessage(message, defaultFrom) {
490
+ const fromAddr = message.from ? formatAddress(message.from.email, message.from.name) : formatAddress(defaultFrom.email, defaultFrom.name);
491
+ const fromEmail = extractEmail(message.from?.email ?? defaultFrom.email);
492
+ const toList = Array.isArray(message.to) ? message.to : [message.to];
493
+ const headers = [
494
+ `From: ${fromAddr}`,
495
+ `To: ${toList.map(stripCrlf).join(", ")}`,
496
+ `Subject: ${encodeHeaderValue(message.subject)}`,
497
+ `Date: ${formatDate(/* @__PURE__ */ new Date())}`,
498
+ `Message-ID: ${generateMessageId(fromEmail)}`,
499
+ "MIME-Version: 1.0"
500
+ ];
501
+ if (message.replyTo) headers.push(`Reply-To: ${stripCrlf(message.replyTo)}`);
502
+ if (message.cc?.length) headers.push(`Cc: ${message.cc.map(stripCrlf).join(", ")}`);
503
+ const allRecipients = [
504
+ ...toList,
505
+ ...message.cc ?? [],
506
+ ...message.bcc ?? []
507
+ ].map(extractEmail);
508
+ const body = buildBodyPart(message.text, message.html);
509
+ if (!(message.attachments && message.attachments.length > 0)) {
510
+ headers.push(`Content-Type: ${body.contentType}`);
511
+ if (body.cte) headers.push(`Content-Transfer-Encoding: ${body.cte}`);
512
+ return {
513
+ raw: headers.join("\r\n") + "\r\n\r\n" + body.content,
514
+ envelope: {
515
+ from: fromEmail,
516
+ to: allRecipients
517
+ }
518
+ };
519
+ }
520
+ const mixedBoundary = generateBoundary();
521
+ headers.push(`Content-Type: multipart/mixed; boundary="${mixedBoundary}"`);
522
+ const parts = [`--${mixedBoundary}`, `Content-Type: ${body.contentType}`];
523
+ if (body.cte) parts.push(`Content-Transfer-Encoding: ${body.cte}`);
524
+ parts.push("", body.content);
525
+ for (const attachment of message.attachments) {
526
+ parts.push(`--${mixedBoundary}`);
527
+ parts.push(await buildAttachmentPart(attachment));
528
+ }
529
+ parts.push(`--${mixedBoundary}--`);
530
+ return {
531
+ raw: headers.join("\r\n") + "\r\n\r\n" + parts.join("\r\n"),
532
+ envelope: {
533
+ from: fromEmail,
534
+ to: allRecipients
535
+ }
536
+ };
537
+ }
233
538
  //#endregion
234
- //#region src/email/errors/email-resend-api-failed.error.ts
539
+ //#region src/email/providers/base-email.provider.ts
235
540
  /**
236
- * EmailResendApiFailedError
237
- *
238
- * Thrown when Resend API returns an error during email sending.
239
- * This is a runtime error from the Resend service.
541
+ * Base Email Provider
240
542
  *
241
- * Resolution: Check Resend API status, API key validity, or wait and retry.
543
+ * Abstract base class for email providers.
544
+ * Provides shared implementation of sendBatch() to reduce code duplication.
242
545
  */
243
- var EmailResendApiFailedError = class extends ApplicationError {
244
- constructor() {
245
- super("errors.email.resendApiFailed", ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR);
546
+ var BaseEmailProvider = class {
547
+ /**
548
+ * Send multiple emails in a batch
549
+ *
550
+ * Default implementation sends emails sequentially.
551
+ * Concrete providers can override for optimized batch sending.
552
+ */
553
+ async sendBatch(messages) {
554
+ const results = [];
555
+ let successful = 0;
556
+ let failed = 0;
557
+ for (const message of messages) try {
558
+ const result = await this.send(message);
559
+ results.push(result);
560
+ successful++;
561
+ } catch (error) {
562
+ results.push({
563
+ messageId: "",
564
+ accepted: false,
565
+ metadata: { error: error instanceof Error ? error.message : "Unknown error" }
566
+ });
567
+ failed++;
568
+ }
569
+ return {
570
+ total: messages.length,
571
+ successful,
572
+ failed,
573
+ results
574
+ };
246
575
  }
247
576
  };
248
577
  //#endregion
249
- //#region src/email/errors/email-provider-not-supported.error.ts
250
- /**
251
- * EmailProviderNotSupportedError
252
- *
253
- * Thrown when an unsupported email provider is configured.
254
- * Only 'resend' and 'smtp' providers are currently supported.
255
- *
256
- * Resolution: Set EMAIL_PROVIDER to either 'resend' or 'smtp'.
257
- */
258
- var EmailProviderNotSupportedError = class extends ApplicationError {
259
- constructor(provider) {
260
- super("errors.email.providerNotSupported", ERROR_CODES.SYSTEM.CONFIGURATION_ERROR, { provider });
578
+ //#region src/email/providers/smtp.provider.ts
579
+ var SmtpProvider = class extends BaseEmailProvider {
580
+ options;
581
+ constructor(options) {
582
+ super();
583
+ this.options = options;
584
+ if (!this.options.smtp?.url) throw new EmailError("SMTP URL is required");
585
+ }
586
+ async send(message) {
587
+ const mime = await buildMimeMessage(message, this.options.from);
588
+ try {
589
+ return {
590
+ messageId: (await new SmtpClient(this.options.smtp).send(mime.raw, {
591
+ from: mime.envelope.from,
592
+ to: mime.envelope.to
593
+ })).messageId,
594
+ accepted: true,
595
+ metadata: { provider: "smtp" }
596
+ };
597
+ } catch (error) {
598
+ if (error instanceof EmailError) throw error;
599
+ throw new EmailError(`SMTP send failed: ${error.message}`);
600
+ }
261
601
  }
262
602
  };
263
603
  //#endregion
@@ -267,57 +607,35 @@ let EmailProviderFactory = class EmailProviderFactory {
267
607
  constructor(options) {
268
608
  this.options = options;
269
609
  }
270
- /**
271
- * Create email provider instance based on configuration
272
- *
273
- * @returns Email provider implementation
274
- * @throws EmailProviderNotSupportedError if provider is not supported
275
- */
276
- async create() {
277
- switch (this.options.provider) {
278
- case "resend": {
279
- const { ResendProvider } = await import("../resend.provider-DB4IlFjG.mjs");
280
- return new ResendProvider(this.options);
281
- }
282
- case "smtp": {
283
- const { SmtpProvider } = await import("../smtp.provider-B6D7zuWX.mjs");
284
- return new SmtpProvider(this.options);
285
- }
286
- default: throw new EmailProviderNotSupportedError(this.options.provider);
287
- }
610
+ create() {
611
+ return new SmtpProvider(this.options);
288
612
  }
289
613
  };
290
- EmailProviderFactory = __decorate([
291
- Transient(EMAIL_TOKENS.EmailProviderFactory),
292
- __decorateParam(0, inject(EMAIL_TOKENS.Options)),
293
- __decorateMetadata("design:paramtypes", [Object])
294
- ], EmailProviderFactory);
614
+ EmailProviderFactory = __decorate([Transient(EMAIL_TOKENS.EmailProviderFactory), __decorateParam(0, inject(EMAIL_TOKENS.Options))], EmailProviderFactory);
295
615
  //#endregion
296
616
  //#region src/email/email.module.ts
297
617
  /**
298
618
  * Email Module
299
619
  *
300
620
  * Provides email sending capabilities with provider abstraction.
301
- * Supports multiple email providers (Resend, SMTP) with automatic provider selection.
621
+ * Sends email via SMTP. Emails are dispatched asynchronously via Cloudflare Queues.
302
622
  * Emails are sent asynchronously via Cloudflare Queues.
303
623
  *
304
624
  * **Usage:**
305
625
  * ```typescript
306
626
  * // In AppModule imports with static options
307
627
  * EmailModule.forRoot({
308
- * provider: 'resend',
309
- * apiKey: 'your-api-key',
310
628
  * from: { name: 'App', email: 'noreply@example.com' },
311
- * queue: 'notifications-queue',
629
+ * smtp: { url: 'smtp://user:pass@smtp.example.com:587' },
630
+ * queue: 'NOTIFICATIONS_QUEUE',
312
631
  * })
313
632
  *
314
633
  * // Or with async options from config namespaces
315
634
  * EmailModule.forRootAsync({
316
635
  * inject: [emailConfig.KEY],
317
636
  * useFactory: (email) => ({
318
- * provider: email.provider,
319
- * apiKey: email.apiKey,
320
637
  * from: email.from,
638
+ * smtp: email.smtp,
321
639
  * queue: email.queue,
322
640
  * }),
323
641
  * })
@@ -344,10 +662,9 @@ let EmailModule = _EmailModule = class EmailModule {
344
662
  * @example
345
663
  * ```typescript
346
664
  * EmailModule.forRoot({
347
- * provider: 'resend',
348
- * apiKey: env.RESEND_API_KEY,
349
665
  * from: { name: 'App', email: 'noreply@example.com' },
350
- * queue: 'notifications-queue',
666
+ * smtp: { url: 'smtp://user:pass@smtp.example.com:587' },
667
+ * queue: 'NOTIFICATIONS_QUEUE',
351
668
  * })
352
669
  * ```
353
670
  */
@@ -376,8 +693,6 @@ let EmailModule = _EmailModule = class EmailModule {
376
693
  * EmailModule.forRootAsync({
377
694
  * inject: [emailConfig.KEY],
378
695
  * useFactory: (email) => ({
379
- * provider: email.provider,
380
- * apiKey: email.apiKey,
381
696
  * from: email.from,
382
697
  * smtp: email.smtp,
383
698
  * queue: email.queue,
@@ -523,7 +838,7 @@ const emailMessageSchema = z.object({
523
838
  * Email attachments
524
839
  */
525
840
  attachments: z.array(emailAttachmentSchema).optional()
526
- }).refine((data) => data.html ?? data.text, withI18n("zodI18n.errors.custom.emailOrTextRequired"));
841
+ }).refine((data) => data.html ?? data.text, withZodI18n("zodI18n.errors.custom.emailOrTextRequired"));
527
842
  //#endregion
528
843
  //#region src/email/contracts/send-email.input.ts
529
844
  /**
@@ -550,6 +865,6 @@ const sendBatchEmailInputSchema = z.object({
550
865
  */
551
866
  messages: z.array(sendEmailInputSchema).min(1).max(100) });
552
867
  //#endregion
553
- export { EMAIL_TOKENS, EmailModule, EmailProviderFactory, EmailProviderNotSupportedError, EmailResendApiFailedError, EmailService, EmailSmtpConnectionFailedError, ResendApiKeyMissingError, SmtpConfigurationMissingError, SmtpHostMissingError, emailAddressSchema, emailAttachmentSchema, emailMessageSchema, inlineEmailAttachmentSchema, sendBatchEmailInputSchema, sendEmailInputSchema, storageEmailAttachmentSchema };
868
+ export { BaseEmailProvider, EMAIL_TOKENS, EmailError, EmailModule, EmailProviderFactory, EmailService, emailAddressSchema, emailAttachmentSchema, emailMessageSchema, inlineEmailAttachmentSchema, sendBatchEmailInputSchema, sendEmailInputSchema, storageEmailAttachmentSchema };
554
869
 
555
870
  //# sourceMappingURL=index.mjs.map