sently 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +46 -0
  3. package/README.md +18 -16
  4. package/dist/adapters/bun.js +1 -1
  5. package/dist/adapters/cf.js +2 -2
  6. package/dist/adapters/cf.js.map +1 -1
  7. package/dist/adapters/deno.js +1 -1
  8. package/dist/adapters/node.js +1 -1
  9. package/dist/auth/oauth2.js +2 -2
  10. package/dist/auth/oauth2.js.map +1 -1
  11. package/dist/channel-result.d.ts +6 -0
  12. package/dist/channel-result.js +1 -0
  13. package/dist/{chunk-skqhj0rm.js → chunk-1ke3nmyg.js} +3 -3
  14. package/dist/{chunk-skqhj0rm.js.map → chunk-1ke3nmyg.js.map} +1 -1
  15. package/dist/{chunk-7gy2q9sh.js → chunk-5es0v1j7.js} +2 -2
  16. package/dist/{chunk-7gy2q9sh.js.map → chunk-5es0v1j7.js.map} +1 -1
  17. package/dist/{chunk-0qxws3kj.js → chunk-7wtfjx0d.js} +2 -2
  18. package/dist/{chunk-0qxws3kj.js.map → chunk-7wtfjx0d.js.map} +1 -1
  19. package/dist/chunk-8kpgbrba.js +4 -0
  20. package/dist/{chunk-93vqxxj2.js.map → chunk-8kpgbrba.js.map} +2 -2
  21. package/dist/{chunk-vjpds2pf.js → chunk-a057jzsy.js} +2 -2
  22. package/dist/{chunk-vjpds2pf.js.map → chunk-a057jzsy.js.map} +1 -1
  23. package/dist/{chunk-8njyga62.js → chunk-bhr7w3gg.js} +2 -2
  24. package/dist/{chunk-8njyga62.js.map → chunk-bhr7w3gg.js.map} +1 -1
  25. package/dist/chunk-cs1tvehn.js +4 -0
  26. package/dist/chunk-cs1tvehn.js.map +10 -0
  27. package/dist/{chunk-29z7fkzy.js → chunk-d5aw5vag.js} +3 -3
  28. package/dist/{chunk-29z7fkzy.js.map → chunk-d5aw5vag.js.map} +1 -1
  29. package/dist/chunk-f5x8vesr.js +4 -0
  30. package/dist/{chunk-b602dhck.js.map → chunk-f5x8vesr.js.map} +2 -2
  31. package/dist/chunk-fv0bemgf.js +4 -0
  32. package/dist/{chunk-yp311efr.js.map → chunk-fv0bemgf.js.map} +3 -3
  33. package/dist/{chunk-ywq6s10g.js → chunk-hnzmn4s4.js} +2 -2
  34. package/dist/{chunk-ywq6s10g.js.map → chunk-hnzmn4s4.js.map} +1 -1
  35. package/dist/chunk-htdg075t.js +4 -0
  36. package/dist/{chunk-qtkd5bak.js.map → chunk-htdg075t.js.map} +4 -3
  37. package/dist/{chunk-0gqy32pe.js → chunk-q2mahnb7.js} +3 -3
  38. package/dist/chunk-q2mahnb7.js.map +10 -0
  39. package/dist/chunk-sbgt4165.js +4 -0
  40. package/dist/chunk-sbgt4165.js.map +10 -0
  41. package/dist/{chunk-6npp3x3c.js → chunk-th4cwrpb.js} +2 -2
  42. package/dist/{chunk-6npp3x3c.js.map → chunk-th4cwrpb.js.map} +1 -1
  43. package/dist/{chunk-tamww15j.js → chunk-ttbwyxmh.js} +2 -2
  44. package/dist/{chunk-tamww15j.js.map → chunk-ttbwyxmh.js.map} +1 -1
  45. package/dist/chunk-w4c9kj70.js +13 -0
  46. package/dist/{chunk-n0qeyzqm.js.map → chunk-w4c9kj70.js.map} +2 -2
  47. package/dist/chunk-w9sabmb0.js +4 -0
  48. package/dist/chunk-w9sabmb0.js.map +10 -0
  49. package/dist/{chunk-8dty8c4p.js → chunk-yg3kj723.js} +3 -3
  50. package/dist/{chunk-8dty8c4p.js.map → chunk-yg3kj723.js.map} +2 -2
  51. package/dist/chunk-z1589fjk.js +4 -0
  52. package/dist/chunk-z1589fjk.js.map +10 -0
  53. package/dist/core/channel-result.d.ts +36 -0
  54. package/dist/core/channel-result.js +3 -0
  55. package/dist/core/channel-result.js.map +10 -0
  56. package/dist/core/decorated-transport.d.ts +30 -0
  57. package/dist/core/decorator-hooks.d.ts +17 -0
  58. package/dist/core/errors.js +2 -2
  59. package/dist/core/errors.js.map +1 -1
  60. package/dist/core/provider-label.d.ts +7 -3
  61. package/dist/core/push-endpoint.d.ts +5 -0
  62. package/dist/core/push-types.d.ts +48 -14
  63. package/dist/core/sms-types.d.ts +12 -0
  64. package/dist/core/smtp.js +2 -2
  65. package/dist/core/smtp.js.map +1 -1
  66. package/dist/core/whatsapp-types.d.ts +12 -0
  67. package/dist/detect.js +2 -2
  68. package/dist/detect.js.map +1 -1
  69. package/dist/dkim.js +2 -2
  70. package/dist/dkim.js.map +2 -2
  71. package/dist/idempotency.js +2 -2
  72. package/dist/idempotency.js.map +1 -1
  73. package/dist/index.d.ts +4 -0
  74. package/dist/index.js +5 -0
  75. package/dist/mailer.js +2 -2
  76. package/dist/mailer.js.map +1 -1
  77. package/dist/observability/console.js +1 -1
  78. package/dist/plugins/react.js +2 -2
  79. package/dist/plugins/react.js.map +1 -1
  80. package/dist/plugins/template.js +1 -1
  81. package/dist/pool/pool.js +2 -2
  82. package/dist/pool/pool.js.map +1 -1
  83. package/dist/push.d.ts +1 -0
  84. package/dist/push.js +2 -2
  85. package/dist/push.js.map +3 -3
  86. package/dist/sms.d.ts +1 -0
  87. package/dist/sms.js +2 -2
  88. package/dist/sms.js.map +3 -3
  89. package/dist/smtp-mailer.js +2 -2
  90. package/dist/smtp-mailer.js.map +1 -1
  91. package/dist/transports/brevo.js +2 -2
  92. package/dist/transports/brevo.js.map +2 -2
  93. package/dist/transports/cloudflare-email.js +2 -2
  94. package/dist/transports/cloudflare-email.js.map +2 -2
  95. package/dist/transports/fallback.d.ts +32 -6
  96. package/dist/transports/fallback.js +2 -2
  97. package/dist/transports/fallback.js.map +1 -1
  98. package/dist/transports/fcm.d.ts +55 -0
  99. package/dist/transports/fcm.js +4 -0
  100. package/dist/transports/fcm.js.map +10 -0
  101. package/dist/transports/loops.js +2 -2
  102. package/dist/transports/loops.js.map +1 -1
  103. package/dist/transports/mailersend.js +2 -2
  104. package/dist/transports/mailersend.js.map +2 -2
  105. package/dist/transports/mailgun.js +2 -2
  106. package/dist/transports/mailgun.js.map +2 -2
  107. package/dist/transports/mailtrap.js +2 -2
  108. package/dist/transports/mailtrap.js.map +2 -2
  109. package/dist/transports/msegat.js +2 -2
  110. package/dist/transports/msegat.js.map +1 -1
  111. package/dist/transports/plunk.js +2 -2
  112. package/dist/transports/plunk.js.map +1 -1
  113. package/dist/transports/postmark.js +2 -2
  114. package/dist/transports/postmark.js.map +2 -2
  115. package/dist/transports/preview.js +2 -2
  116. package/dist/transports/preview.js.map +1 -1
  117. package/dist/transports/resend.js +2 -2
  118. package/dist/transports/resend.js.map +2 -2
  119. package/dist/transports/retry.d.ts +28 -9
  120. package/dist/transports/retry.js +2 -2
  121. package/dist/transports/retry.js.map +3 -3
  122. package/dist/transports/sendgrid.js +2 -2
  123. package/dist/transports/sendgrid.js.map +2 -2
  124. package/dist/transports/ses.js +2 -2
  125. package/dist/transports/ses.js.map +2 -2
  126. package/dist/transports/smtp.js +2 -2
  127. package/dist/transports/smtp.js.map +1 -1
  128. package/dist/transports/sndr.js +2 -2
  129. package/dist/transports/sndr.js.map +1 -1
  130. package/dist/transports/sparkpost.js +2 -2
  131. package/dist/transports/sparkpost.js.map +2 -2
  132. package/dist/transports/taqnyat-mail.js +2 -2
  133. package/dist/transports/taqnyat-mail.js.map +1 -1
  134. package/dist/transports/taqnyat-sms.js +2 -2
  135. package/dist/transports/taqnyat-sms.js.map +1 -1
  136. package/dist/transports/taqnyat-whatsapp.js +2 -2
  137. package/dist/transports/taqnyat-whatsapp.js.map +1 -1
  138. package/dist/transports/twilio-sms.js +2 -2
  139. package/dist/transports/twilio-sms.js.map +2 -2
  140. package/dist/transports/unifonic.d.ts +81 -0
  141. package/dist/transports/unifonic.js +3 -0
  142. package/dist/transports/unifonic.js.map +10 -0
  143. package/dist/transports/webpush.js +2 -2
  144. package/dist/transports/webpush.js.map +3 -3
  145. package/dist/transports/weighted-fallback.d.ts +11 -9
  146. package/dist/transports/weighted-fallback.js +2 -2
  147. package/dist/transports/weighted-fallback.js.map +3 -3
  148. package/dist/transports/whatsapp-cloud.js +2 -2
  149. package/dist/transports/whatsapp-cloud.js.map +1 -1
  150. package/dist/webhooks/brevo.js +2 -2
  151. package/dist/webhooks/brevo.js.map +1 -1
  152. package/dist/webhooks/mailgun.js +2 -2
  153. package/dist/webhooks/mailgun.js.map +1 -1
  154. package/dist/webhooks/postmark.js +2 -2
  155. package/dist/webhooks/postmark.js.map +1 -1
  156. package/dist/webhooks/resend.js +2 -2
  157. package/dist/webhooks/resend.js.map +1 -1
  158. package/dist/webhooks/sendgrid.js +2 -2
  159. package/dist/webhooks/sendgrid.js.map +1 -1
  160. package/dist/webhooks/ses.js +2 -2
  161. package/dist/webhooks/ses.js.map +1 -1
  162. package/dist/webhooks/sndr.js +2 -2
  163. package/dist/webhooks/sndr.js.map +1 -1
  164. package/dist/webhooks/timing-safe-equal.js +1 -1
  165. package/dist/webhooks/twilio-sms.d.ts +20 -0
  166. package/dist/webhooks/twilio-sms.js +3 -0
  167. package/dist/webhooks/twilio-sms.js.map +10 -0
  168. package/dist/webhooks/types.d.ts +37 -3
  169. package/dist/webhooks/types.js +3 -0
  170. package/dist/webhooks/types.js.map +9 -0
  171. package/dist/webhooks/unifonic.d.ts +13 -0
  172. package/dist/webhooks/unifonic.js +3 -0
  173. package/dist/webhooks/unifonic.js.map +10 -0
  174. package/dist/webhooks/whatsapp-cloud.d.ts +14 -0
  175. package/dist/webhooks/whatsapp-cloud.js +3 -0
  176. package/dist/webhooks/whatsapp-cloud.js.map +10 -0
  177. package/dist/webhooks.d.ts +10 -5
  178. package/dist/webhooks.js +11 -0
  179. package/dist/whatsapp.d.ts +1 -0
  180. package/dist/whatsapp.js +2 -2
  181. package/dist/whatsapp.js.map +3 -3
  182. package/package.json +25 -1
  183. package/site/content/docs/channels/hooks.mdx +6 -5
  184. package/site/content/docs/channels/index.mdx +2 -2
  185. package/site/content/docs/channels/push.mdx +27 -21
  186. package/site/content/docs/channels/sms.mdx +4 -1
  187. package/site/content/docs/decorators/fallback.mdx +41 -14
  188. package/site/content/docs/decorators/index.mdx +29 -12
  189. package/site/content/docs/decorators/retry.mdx +32 -9
  190. package/site/content/docs/decorators/weighted-fallback.mdx +27 -6
  191. package/site/content/docs/get-started/entrypoints.mdx +6 -5
  192. package/site/content/docs/get-started/installation.mdx +3 -2
  193. package/site/content/docs/get-started/introduction.mdx +1 -1
  194. package/site/content/docs/guides/webhooks.mdx +35 -20
  195. package/site/content/docs/index.mdx +1 -1
  196. package/site/content/docs/quick-start/push.mdx +22 -5
  197. package/site/content/docs/reference/channel-result.mdx +82 -0
  198. package/site/content/docs/reference/exports.mdx +5 -3
  199. package/site/content/docs/reference/meta.json +1 -0
  200. package/site/content/docs/reference/push-options.mdx +44 -3
  201. package/site/content/docs/reference/sms-options.mdx +18 -2
  202. package/site/content/docs/reference/webhook-events.mdx +38 -14
  203. package/site/content/docs/reference/whatsapp-options.mdx +19 -1
  204. package/site/content/docs/transports/fcm.mdx +80 -0
  205. package/site/content/docs/transports/index.mdx +3 -1
  206. package/site/content/docs/transports/meta.json +3 -1
  207. package/site/content/docs/transports/unifonic.mdx +85 -0
  208. package/dist/chunk-0gqy32pe.js.map +0 -10
  209. package/dist/chunk-5915vbcj.js +0 -4
  210. package/dist/chunk-5915vbcj.js.map +0 -10
  211. package/dist/chunk-93vqxxj2.js +0 -4
  212. package/dist/chunk-b602dhck.js +0 -4
  213. package/dist/chunk-gp4fwrs8.js +0 -4
  214. package/dist/chunk-gp4fwrs8.js.map +0 -10
  215. package/dist/chunk-n0qeyzqm.js +0 -13
  216. package/dist/chunk-q8k3m6qe.js +0 -4
  217. package/dist/chunk-q8k3m6qe.js.map +0 -10
  218. package/dist/chunk-qtkd5bak.js +0 -4
  219. package/dist/chunk-yp311efr.js +0 -4
@@ -5,6 +5,6 @@
5
5
  "// src/core/base64.ts\n\nconst BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst BASE64_LINE_LENGTH = 76;\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encode a Uint8Array or string to Base64.\n * Uses TextEncoder + manual base64 to support binary data correctly.\n */\nexport function encodeBase64(data: Uint8Array | string): string {\n const bytes = typeof data === \"string\" ? encoder.encode(data) : data;\n let result = \"\";\n let i = 0;\n\n while (i < bytes.length) {\n const b0 = bytes[i] ?? 0;\n const b1 = bytes[i + 1];\n const b2 = bytes[i + 2];\n\n if (b1 === undefined) {\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[(b0 & 0x03) << 4];\n result += \"==\";\n break;\n }\n\n if (b2 === undefined) {\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[((b0 & 0x03) << 4) | (b1 >> 4)];\n result += BASE64_CHARS[(b1 & 0x0f) << 2];\n result += \"=\";\n break;\n }\n\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[((b0 & 0x03) << 4) | (b1 >> 4)];\n result += BASE64_CHARS[((b1 & 0x0f) << 2) | (b2 >> 6)];\n result += BASE64_CHARS[b2 & 0x3f];\n i += 3;\n }\n\n return wrapBase64Lines(result);\n}\n\n/**\n * Decode a Base64 string to Uint8Array.\n */\nexport function decodeBase64(data: string): Uint8Array {\n const cleaned = data.replace(/\\s/g, \"\");\n const len = cleaned.length;\n\n if (len === 0) {\n return new Uint8Array(0);\n }\n\n if (len % 4 !== 0) {\n throw new Error(\"Invalid base64 string length\");\n }\n\n const padding = cleaned.endsWith(\"==\") ? 2 : cleaned.endsWith(\"=\") ? 1 : 0;\n const outputLen = (len * 3) / 4 - padding;\n const output = new Uint8Array(outputLen);\n\n let outIndex = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = base64CharToValue(cleaned[i] ?? \"=\");\n const c1 = base64CharToValue(cleaned[i + 1] ?? \"=\");\n const c2 = base64CharToValue(cleaned[i + 2] ?? \"=\");\n const c3 = base64CharToValue(cleaned[i + 3] ?? \"=\");\n const triple = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;\n\n if (outIndex < outputLen) {\n output[outIndex++] = (triple >> 16) & 0xff;\n }\n if (outIndex < outputLen) {\n output[outIndex++] = (triple >> 8) & 0xff;\n }\n if (outIndex < outputLen) {\n output[outIndex++] = triple & 0xff;\n }\n }\n\n return output;\n}\n\n/**\n * Encode text using Quoted-Printable (RFC 2045).\n */\nexport function encodeQP(text: string): string {\n const bytes = encoder.encode(text);\n const lines: string[] = [];\n let line = \"\";\n\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i] ?? 0;\n\n if (byte === 0x0a) {\n lines.push(line);\n line = \"\";\n continue;\n }\n\n if (byte === 0x0d) {\n continue;\n }\n\n let encoded: string;\n if (\n (byte >= 33 && byte <= 60) ||\n (byte >= 62 && byte <= 126) ||\n byte === 0x09 ||\n byte === 0x20\n ) {\n encoded = String.fromCharCode(byte);\n } else {\n encoded = `=${byte.toString(16).toUpperCase().padStart(2, \"0\")}`;\n }\n\n if (line.length + encoded.length > 75) {\n lines.push(`${line}=`);\n line = encoded;\n } else {\n line += encoded;\n }\n }\n\n if (line.length > 0) {\n lines.push(line);\n }\n\n return lines.join(\"\\r\\n\");\n}\n\n/**\n * Encode an email header value per RFC 2047.\n * Non-ASCII values become: =?UTF-8?B?<base64>?=\n */\nexport function encodeHeader(value: string): string {\n if (!needsEncoding(value)) {\n return value;\n }\n\n const encoded = encodeBase64(value).replace(/\\r\\n/g, \"\");\n return `=?UTF-8?B?${encoded}?=`;\n}\n\n/**\n * Returns true if the string contains non-ASCII characters\n * and therefore requires RFC 2047 encoding in headers.\n */\nexport function needsEncoding(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 127) {\n return true;\n }\n }\n return false;\n}\n\nfunction base64CharToValue(char: string): number {\n if (char === \"=\") {\n return 0;\n }\n const index = BASE64_CHARS.indexOf(char);\n if (index === -1) {\n throw new Error(`Invalid base64 character: ${char}`);\n }\n return index;\n}\n\nfunction wrapBase64Lines(base64: string): string {\n const lines: string[] = [];\n for (let i = 0; i < base64.length; i += BASE64_LINE_LENGTH) {\n lines.push(base64.slice(i, i + BASE64_LINE_LENGTH));\n }\n return lines.join(\"\\r\\n\");\n}\n\n/**\n * Encode bytes to Base64url (RFC 4648 §5) without padding.\n * Used by Web Push (VAPID / RFC 8291) and similar protocols.\n */\nexport function encodeBase64Url(data: Uint8Array | string): string {\n const encoded = encodeBase64(data).replace(/\\r\\n/g, \"\");\n return encoded.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/u, \"\");\n}\n\n/**\n * Decode a Base64url (RFC 4648 §5) string to bytes.\n * Accepts both padded and unpadded input.\n */\nexport function decodeBase64Url(data: string): Uint8Array {\n const normalized = data.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padding = normalized.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (normalized.length % 4));\n return decodeBase64(normalized + padding);\n}\n\n/** Decode bytes to UTF-8 string. */\nexport function decodeUtf8(bytes: Uint8Array): string {\n return decoder.decode(bytes);\n}\n\n/** Encode string to UTF-8 bytes. */\nexport function encodeUtf8(text: string): Uint8Array {\n return encoder.encode(text);\n}\n"
6
6
  ],
7
7
  "mappings": "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",
8
- "debugId": "2107CB27BCD4972964756E2164756E21",
8
+ "debugId": "E49F32817A0DBBB964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,4 @@
1
+ function s(e){return typeof e==="object"&&e!==null&&typeof e.setMailerOnRetry==="function"}function r(e){return typeof e==="object"&&e!==null&&typeof e.setMailerOnFallback==="function"}async function l(e,...n){if(e===void 0)return;try{await e(...n)}catch(o){if(!(typeof process<"u"&&process.env?.NODE_ENV==="production"))console.warn("[sently] hook threw; send continues:",o)}}async function a(e,n){if(!n||n.length===0)return e;let o=e;for(let i of n)o=await i(o);return o}
2
+ export{s as $,r as aa,l as ba,a as ca};
3
+
4
+ //# debugId=30D46F81F122ED7E64756E2164756E21
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/core/hooks.ts", "../src/core/plugin.ts"],
3
+ "sources": ["../src/core/decorator-hooks.ts", "../src/core/hooks.ts", "../src/core/plugin.ts"],
4
4
  "sourcesContent": [
5
+ "/**\n * @module\n * Duck-typed wiring for RetryTransport / FallbackTransport sender hooks.\n * Kept separate so channel senders do not import the decorator modules.\n */\n\n/** Transport that accepts per-send retry callbacks. */\nexport interface RetryHookTransport {\n setMailerOnRetry(callback: ((attempt: number, error: unknown) => void) | undefined): void;\n}\n\n/** Transport that accepts per-send fallback callbacks. */\nexport interface FallbackHookTransport {\n setMailerOnFallback(\n callback: ((failedProvider: string, nextProvider: string, error: unknown) => void) | undefined,\n ): void;\n}\n\n/** True when the transport exposes {@link RetryHookTransport.setMailerOnRetry}. */\nexport function isRetryHookTransport(transport: unknown): transport is RetryHookTransport {\n return (\n typeof transport === \"object\" &&\n transport !== null &&\n typeof (transport as RetryHookTransport).setMailerOnRetry === \"function\"\n );\n}\n\n/** True when the transport exposes {@link FallbackHookTransport.setMailerOnFallback}. */\nexport function isFallbackHookTransport(transport: unknown): transport is FallbackHookTransport {\n return (\n typeof transport === \"object\" &&\n transport !== null &&\n typeof (transport as FallbackHookTransport).setMailerOnFallback === \"function\"\n );\n}\n",
5
6
  "/**\n * @module\n * Shared lifecycle hook invocation for mailer and channel senders.\n * Hook failures are swallowed so they never break the send path.\n */\n\n/**\n * Invoke a lifecycle hook without letting hook failures break the send.\n * In non-production environments, hook errors are logged with `console.warn`.\n *\n * @typeParam T - Hook argument tuple types.\n * @param hook - Optional sync or async hook callback.\n * @param args - Arguments forwarded to the hook.\n */\nexport async function invokeHook<T extends unknown[]>(\n hook: ((...args: T) => void | Promise<void>) | undefined,\n ...args: T\n): Promise<void> {\n if (hook === undefined) {\n return;\n }\n try {\n await hook(...args);\n } catch (hookError) {\n const isProduction = typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n if (!isProduction) {\n console.warn(\"[sently] hook threw; send continues:\", hookError);\n }\n }\n}\n",
6
7
  "/**\n * @module\n * Plugin pipeline for sently channel senders.\n * Plugins transform channel options before the transport sends.\n * They run sequentially — each receives the previous plugin's output.\n *\n * @example\n * ```ts\n * import { runPlugins } from \"sently/core/plugin\";\n * const result = await runPlugins(options, [pluginA, pluginB]);\n * ```\n */\n\n/**\n * Run a list of plugins sequentially over channel options.\n * If plugins is empty or undefined, returns options unchanged.\n * Each plugin may be sync or async.\n *\n * @typeParam T - Channel options type (e.g. MailOptions, SmsOptions).\n * @param options - the original options\n * @param plugins - ordered list of plugins to apply\n * @returns transformed options after all plugins have run\n */\nexport async function runPlugins<T>(\n options: T,\n plugins: Array<(o: T) => T | Promise<T>> | undefined,\n): Promise<T> {\n if (!plugins || plugins.length === 0) {\n return options;\n }\n\n let current = options;\n for (const plugin of plugins) {\n current = await plugin(current);\n }\n return current;\n}\n"
7
8
  ],
8
- "mappings": "AAcA,eAAsB,CAA+B,CACnD,KACG,EACY,CACf,GAAI,IAAS,OACX,OAEF,GAAI,CACF,MAAM,EAAK,GAAG,CAAI,EAClB,MAAO,EAAW,CAElB,GAAI,EADiB,OAAO,QAAY,KAAe,QAAQ,KAAK,WAAa,cAE/E,QAAQ,KAAK,uCAAwC,CAAS,GCHpE,eAAsB,CAAa,CACjC,EACA,EACY,CACZ,GAAI,CAAC,GAAW,EAAQ,SAAW,EACjC,OAAO,EAGT,IAAI,EAAU,EACd,QAAW,KAAU,EACnB,EAAU,MAAM,EAAO,CAAO,EAEhC,OAAO",
9
- "debugId": "675428B56EEB607264756E2164756E21",
9
+ "mappings": "AAmBO,SAAS,CAAoB,CAAC,EAAqD,CACxF,OACE,OAAO,IAAc,UACrB,IAAc,MACd,OAAQ,EAAiC,mBAAqB,WAK3D,SAAS,CAAuB,CAAC,EAAwD,CAC9F,OACE,OAAO,IAAc,UACrB,IAAc,MACd,OAAQ,EAAoC,sBAAwB,WClBxE,eAAsB,CAA+B,CACnD,KACG,EACY,CACf,GAAI,IAAS,OACX,OAEF,GAAI,CACF,MAAM,EAAK,GAAG,CAAI,EAClB,MAAO,EAAW,CAElB,GAAI,EADiB,OAAO,QAAY,KAAe,QAAQ,KAAK,WAAa,cAE/E,QAAQ,KAAK,uCAAwC,CAAS,GCHpE,eAAsB,CAAa,CACjC,EACA,EACY,CACZ,GAAI,CAAC,GAAW,EAAQ,SAAW,EACjC,OAAO,EAGT,IAAI,EAAU,EACd,QAAW,KAAU,EACnB,EAAU,MAAM,EAAO,CAAO,EAEhC,OAAO",
10
+ "debugId": "30D46F81F122ED7E64756E2164756E21",
10
11
  "names": []
11
12
  }
@@ -1,4 +1,4 @@
1
- import{N as J}from"./chunk-gp4fwrs8.js";import{ca as Q}from"./chunk-tamww15j.js";class K extends Error{attempts;constructor(w){super(`All ${w.length} transports failed`);this.name="FallbackError",this.attempts=w}}var X=J;function T(w){if(w instanceof Q&&w.sentlyCode==="SMTP_AUTH_FAILED")return!1;let q=w?.statusCode;if(typeof q==="number"){if(q===400||q===401||q===403)return!1;return!0}if(w?.code===535)return!1;return!0}class U{transports;provider="fallback";shouldFallback;onFallback;cooldownMs;now;unhealthyUntil;mailerOnFallback;constructor(w,q){this.transports=w;if(w.length===0)throw Error("FallbackTransport requires at least one transport");this.shouldFallback=q?.shouldFallback??T,this.onFallback=q?.onFallback,this.cooldownMs=q?.cooldownMs??0,this.now=q?.now??(()=>Date.now()),this.unhealthyUntil=q?.cooldownState??new Map}setMailerOnFallback(w){this.mailerOnFallback=w}isCoolingDown(w){let q=this.unhealthyUntil.get(w);if(q===void 0)return!1;if(this.now()>=q)return this.unhealthyUntil.delete(w),!1;return!0}markUnhealthy(w){if(this.cooldownMs>0)this.unhealthyUntil.set(w,this.now()+this.cooldownMs)}async send(w){let q=[],z=[];for(let G=0;G<this.transports.length;G++){let M=this.transports[G],D=J(M);if(this.isCoolingDown(D)){z.push({provider:D,error:Error(`Provider ${D} is in cooldown`)});continue}try{return{...await M.send(w),provider:D,providerIndex:G}}catch(H){q.push({provider:D,error:H}),this.markUnhealthy(D);let N=this.findNextTryIndex(G);if(N===-1)break;if(this.shouldFallback(H)===!1)throw H;let R=J(this.transports[N]);if(this.onFallback?.(G,H),this.mailerOnFallback!==void 0)await this.mailerOnFallback(D,R,H)}}let B=[...q,...z];if(B.length===0)throw new K([{provider:"fallback",error:Error("All providers are in cooldown")}]);throw new K(B)}findNextTryIndex(w){for(let q=w+1;q<this.transports.length;q++){let z=J(this.transports[q]);if(!this.isCoolingDown(z))return q}return-1}async verify(){let q=(await this.verifyAll()).providers.find((z)=>z.ok);if(q!==void 0)return{ok:!0,provider:q.provider,...q.message!==void 0?{message:q.message}:{}};return{ok:!1,provider:"fallback",message:"no transport verified"}}async verifyAll(){let w=[];for(let q of this.transports){let z=J(q);if(q.verify===void 0){w.push({provider:z,ok:!1,message:"no verify() method"});continue}try{let B=await q.verify();w.push({provider:z,ok:B.ok,...B.message!==void 0?{message:B.message}:{}})}catch(B){w.push({provider:z,ok:!1,message:B instanceof Error?B.message:String(B)})}}return{ok:w.some((q)=>q.ok),providers:w}}async close(){await Promise.allSettled(this.transports.map((w)=>w.close?.()))}}
2
- export{K as i,X as j,U as k};
1
+ import{P as J}from"./chunk-cs1tvehn.js";import{ja as Q}from"./chunk-ttbwyxmh.js";class K extends Error{attempts;constructor(w){super(`All ${w.length} transports failed`);this.name="FallbackError",this.attempts=w}}var X=J;function T(w){if(w instanceof Q&&w.sentlyCode==="SMTP_AUTH_FAILED")return!1;let q=w?.statusCode;if(typeof q==="number"){if(q===400||q===401||q===403)return!1;return!0}if(w?.code===535)return!1;return!0}class U{transports;provider="fallback";shouldFallback;onFallback;cooldownMs;now;unhealthyUntil;mailerOnFallback;constructor(w,q){this.transports=w;if(w.length===0)throw Error("FallbackTransport requires at least one transport");this.shouldFallback=q?.shouldFallback??T,this.onFallback=q?.onFallback,this.cooldownMs=q?.cooldownMs??0,this.now=q?.now??(()=>Date.now()),this.unhealthyUntil=q?.cooldownState??new Map}setMailerOnFallback(w){this.mailerOnFallback=w}isCoolingDown(w){let q=this.unhealthyUntil.get(w);if(q===void 0)return!1;if(this.now()>=q)return this.unhealthyUntil.delete(w),!1;return!0}markUnhealthy(w){if(this.cooldownMs>0)this.unhealthyUntil.set(w,this.now()+this.cooldownMs)}async send(w){let q=[],z=[];for(let G=0;G<this.transports.length;G++){let M=this.transports[G],D=J(M);if(this.isCoolingDown(D)){z.push({provider:D,error:Error(`Provider ${D} is in cooldown`)});continue}try{return{...await M.send(w),provider:D,providerIndex:G}}catch(H){q.push({provider:D,error:H}),this.markUnhealthy(D);let N=this.findNextTryIndex(G);if(N===-1)break;if(this.shouldFallback(H)===!1)throw H;let R=J(this.transports[N]);if(this.onFallback?.(G,H),this.mailerOnFallback!==void 0)await this.mailerOnFallback(D,R,H)}}let B=[...q,...z];if(B.length===0)throw new K([{provider:"fallback",error:Error("All providers are in cooldown")}]);throw new K(B)}findNextTryIndex(w){for(let q=w+1;q<this.transports.length;q++){let z=J(this.transports[q]);if(!this.isCoolingDown(z))return q}return-1}async verify(){let q=(await this.verifyAll()).providers.find((z)=>z.ok);if(q!==void 0)return{ok:!0,provider:q.provider,...q.message!==void 0?{message:q.message}:{}};return{ok:!1,provider:"fallback",message:"no transport verified"}}async verifyAll(){let w=[];for(let q of this.transports){let z=J(q);if(q.verify===void 0){w.push({provider:z,ok:!1,message:"no verify() method"});continue}try{let B=await q.verify();w.push({provider:z,ok:B.ok,...B.message!==void 0?{message:B.message}:{}})}catch(B){w.push({provider:z,ok:!1,message:B instanceof Error?B.message:String(B)})}}return{ok:w.some((q)=>q.ok),providers:w}}async close(){await Promise.allSettled(this.transports.map((w)=>w.close?.()))}}
2
+ export{K as k,X as l,U as m};
3
3
 
4
- //# debugId=833078D22947C91264756E2164756E21
4
+ //# debugId=269E988AAA7AF83164756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/transports/fallback.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @module\n * FallbackTransport — routes through an ordered list of transports,\n * advancing to the next when the current one fails. Use for provider\n * failover across email, SMS, WhatsApp, or push. Composes with\n * RetryTransport — wrap each entry in RetryTransport to retry within a\n * provider before failing over to the next.\n *\n * @example\n * ```ts\n * import { FallbackTransport } from \"sently/transports/fallback\";\n * import { RetryTransport } from \"sently/transports/retry\";\n * import { ResendTransport } from \"sently/transports/resend\";\n * import { SESTransport } from \"sently/transports/ses\";\n *\n * const transport = new FallbackTransport(\n * [\n * new RetryTransport(new ResendTransport({ apiKey })),\n * new RetryTransport(new SESTransport({ accessKeyId, secretAccessKey })),\n * ],\n * { cooldownMs: 300_000 },\n * );\n * ```\n */\nimport type { DecoratedTransport, FallbackAugmentedResult } from \"../core/decorated-transport.js\";\nimport { SentlyError } from \"../core/errors.js\";\nimport { getProviderLabel } from \"../core/provider-label.js\";\nimport type { MailOptions, SendResult, VerifyResult } from \"../core/types.js\";\n\n/** One failed provider attempt collected during failover. */\nexport interface FallbackAttempt {\n /** Provider label (e.g. `\"resend\"`, `\"ses\"`). */\n provider: string;\n /** Error thrown by that transport. */\n error: unknown;\n}\n\n/** Per-provider result from {@link FallbackTransport.verifyAll}. */\nexport interface FallbackProviderVerifyResult {\n /** Provider label. */\n provider: string;\n /** Whether this provider verified successfully. */\n ok: boolean;\n /** Human-readable status from the provider verify call. */\n message?: string;\n}\n\n/** Result of verifying every transport in a fallback chain. */\nexport interface FallbackVerifyAllResult {\n /** True when at least one provider in the chain verified successfully. */\n ok: boolean;\n /** Per-provider verify results in chain order. */\n providers: FallbackProviderVerifyResult[];\n}\n\n/** Options for {@link FallbackTransport} failover behavior. */\nexport interface FallbackOptions {\n /**\n * Decide whether a given error should trigger failover to the next\n * transport. Default: fail over on everything EXCEPT permanent client\n * errors (HTTP 400/401/403, SMTP permanent 5xx auth failures), since\n * those will fail identically on every provider.\n */\n shouldFallback?: (error: unknown) => boolean;\n /** Optional callback fired before advancing to the next transport. */\n onFallback?: (failedIndex: number, error: unknown) => void;\n /**\n * After a failed send, skip this provider until the cooldown expires (ms).\n * Prevents hammering a failing provider during an outage.\n */\n cooldownMs?: number;\n /** Injectable clock for cooldown and testing. Default: `Date.now`. */\n now?: () => number;\n /**\n * Shared cooldown state across fallback instances (e.g. {@link WeightedFallbackTransport}).\n * @internal\n */\n cooldownState?: Map<string, number>;\n}\n\n/**\n * Thrown when every transport in the chain fails.\n * {@link FallbackAttempt} entries record which provider failed and why.\n */\nexport class FallbackError extends Error {\n /** All failed attempts in order — which provider failed and why. */\n readonly attempts: FallbackAttempt[];\n\n /** Creates an error summarizing every failed transport attempt. */\n constructor(attempts: FallbackAttempt[]) {\n super(`All ${attempts.length} transports failed`);\n this.name = \"FallbackError\";\n this.attempts = attempts;\n }\n}\n\n/** @deprecated Use {@link getProviderLabel} from `sently/core` patterns. */\nexport const inferProviderLabel = getProviderLabel;\n\nfunction defaultShouldFallback(error: unknown): boolean {\n if (error instanceof SentlyError && error.sentlyCode === \"SMTP_AUTH_FAILED\") {\n return false;\n }\n\n const status = (error as { statusCode?: number })?.statusCode;\n if (typeof status === \"number\") {\n if (status === 400 || status === 401 || status === 403) {\n return false;\n }\n return true;\n }\n\n const code = (error as { code?: number })?.code;\n if (code === 535) {\n return false;\n }\n\n return true;\n}\n\ntype MailerOnFallback = (\n failedProvider: string,\n nextProvider: string,\n error: unknown,\n) => void | Promise<void>;\n\n/**\n * Decorator transport that fails over through an ordered list of transports.\n * Defaults preserve email {@link Transport} compatibility.\n */\nexport class FallbackTransport<TOptions = MailOptions, TResult = SendResult>\n implements DecoratedTransport<TOptions, FallbackAugmentedResult<TResult>>\n{\n readonly provider = \"fallback\";\n\n private readonly shouldFallback: (error: unknown) => boolean;\n private readonly onFallback?: FallbackOptions[\"onFallback\"];\n private readonly cooldownMs: number;\n private readonly now: () => number;\n private readonly unhealthyUntil: Map<string, number>;\n private mailerOnFallback: MailerOnFallback | undefined;\n\n /**\n * Creates a failover transport over an ordered list of backends.\n * @throws {Error} When the transports array is empty.\n */\n constructor(\n private readonly transports: DecoratedTransport<TOptions, TResult>[],\n options?: FallbackOptions,\n ) {\n if (transports.length === 0) {\n throw new Error(\"FallbackTransport requires at least one transport\");\n }\n this.shouldFallback = options?.shouldFallback ?? defaultShouldFallback;\n this.onFallback = options?.onFallback;\n this.cooldownMs = options?.cooldownMs ?? 0;\n this.now = options?.now ?? (() => Date.now());\n this.unhealthyUntil = options?.cooldownState ?? new Map<string, number>();\n }\n\n /**\n * Register a per-send onFallback callback from sender lifecycle hooks.\n * @internal Cleared after each send.\n */\n setMailerOnFallback(callback: MailerOnFallback | undefined): void {\n this.mailerOnFallback = callback;\n }\n\n private isCoolingDown(provider: string): boolean {\n const until = this.unhealthyUntil.get(provider);\n if (until === undefined) {\n return false;\n }\n if (this.now() >= until) {\n this.unhealthyUntil.delete(provider);\n return false;\n }\n return true;\n }\n\n private markUnhealthy(provider: string): void {\n if (this.cooldownMs > 0) {\n this.unhealthyUntil.set(provider, this.now() + this.cooldownMs);\n }\n }\n\n /** Sends through transports in order until one succeeds. */\n async send(message: TOptions): Promise<FallbackAugmentedResult<TResult>> {\n const attempts: FallbackAttempt[] = [];\n const skipped: FallbackAttempt[] = [];\n\n for (let i = 0; i < this.transports.length; i++) {\n const transport = this.transports[i] as DecoratedTransport<TOptions, TResult>;\n const provider = getProviderLabel(transport);\n\n if (this.isCoolingDown(provider)) {\n skipped.push({\n provider,\n error: new Error(`Provider ${provider} is in cooldown`),\n });\n continue;\n }\n\n try {\n const result = await transport.send(message);\n return {\n ...result,\n provider,\n providerIndex: i,\n };\n } catch (err) {\n attempts.push({ provider, error: err });\n this.markUnhealthy(provider);\n\n const nextIndex = this.findNextTryIndex(i);\n if (nextIndex === -1) {\n break;\n }\n if (this.shouldFallback(err) === false) {\n throw err;\n }\n\n const nextProvider = getProviderLabel(\n this.transports[nextIndex] as DecoratedTransport<TOptions, TResult>,\n );\n this.onFallback?.(i, err);\n if (this.mailerOnFallback !== undefined) {\n await this.mailerOnFallback(provider, nextProvider, err);\n }\n }\n }\n\n const allAttempts = [...attempts, ...skipped];\n if (allAttempts.length === 0) {\n throw new FallbackError([\n { provider: \"fallback\", error: new Error(\"All providers are in cooldown\") },\n ]);\n }\n\n throw new FallbackError(allAttempts);\n }\n\n private findNextTryIndex(currentIndex: number): number {\n for (let j = currentIndex + 1; j < this.transports.length; j++) {\n const provider = getProviderLabel(\n this.transports[j] as DecoratedTransport<TOptions, TResult>,\n );\n if (!this.isCoolingDown(provider)) {\n return j;\n }\n }\n return -1;\n }\n\n /**\n * Returns the result of the first transport whose verify() returns `ok: true`.\n * Use {@link verifyAll} for full-chain visibility.\n */\n async verify(): Promise<VerifyResult> {\n const all = await this.verifyAll();\n const firstOk = all.providers.find((entry) => entry.ok);\n if (firstOk !== undefined) {\n return {\n ok: true,\n provider: firstOk.provider,\n ...(firstOk.message !== undefined ? { message: firstOk.message } : {}),\n };\n }\n\n return {\n ok: false,\n provider: \"fallback\",\n message: \"no transport verified\",\n };\n }\n\n /** Verifies every transport in the chain and returns per-provider results. */\n async verifyAll(): Promise<FallbackVerifyAllResult> {\n const providers: FallbackProviderVerifyResult[] = [];\n\n for (const transport of this.transports) {\n const provider = getProviderLabel(transport);\n if (transport.verify === undefined) {\n providers.push({ provider, ok: false, message: \"no verify() method\" });\n continue;\n }\n\n try {\n const result = await transport.verify();\n providers.push({\n provider,\n ok: result.ok,\n ...(result.message !== undefined ? { message: result.message } : {}),\n });\n } catch (err) {\n providers.push({\n provider,\n ok: false,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return {\n ok: providers.some((entry) => entry.ok),\n providers,\n };\n }\n\n /** Calls close() on every transport; one failure does not block the others. */\n async close(): Promise<void> {\n await Promise.allSettled(this.transports.map((transport) => transport.close?.()));\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "269E988AAA7AF83164756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,4 @@
1
+ function q(b){return j({channel:"email",provider:b.provider,type:b.type,raw:b.raw,...b.messageId!==void 0?{messageId:b.messageId}:{},...b.recipient!==void 0?{recipient:b.recipient}:{},...b.timestamp!==void 0?{timestamp:b.timestamp}:{}})}function j(b){let f={channel:b.channel,provider:b.provider,type:b.type,raw:b.raw};if(b.messageId!==void 0)f.messageId=b.messageId;if(b.recipient!==void 0)f.recipient=b.recipient;if(b.timestamp!==void 0)f.timestamp=b.timestamp;return f}function w(b,f){return f[b]??"unknown"}function z(b){if(typeof b==="number"){let f=b<1000000000000?b*1000:b,h=new Date(f);return Number.isNaN(h.getTime())?void 0:h}if(typeof b==="string"){let f=new Date(b);return Number.isNaN(f.getTime())?void 0:f}return}function A(b){return Array.isArray(b)?b:[b]}function C(b){let f={provider:b.provider,type:b.type,raw:b.raw};if(b.messageId!==void 0)f.messageId=b.messageId;if(b.recipient!==void 0)f.recipient=b.recipient;if(b.timestamp!==void 0)f.timestamp=b.timestamp;return f}
2
+ export{q as d,j as e,w as f,z as g,A as h,C as i};
3
+
4
+ //# debugId=1AD8065310A8C23164756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/webhooks/types.ts"],
4
+ "sourcesContent": [
5
+ "/** Messaging channel for normalized delivery events. */\nexport type DeliveryChannel = \"email\" | \"sms\" | \"whatsapp\" | \"push\";\n\n/**\n * Cross-channel delivery / lifecycle event for ingest pipelines.\n * Email webhooks still return {@link EmailEvent}; map with {@link toDeliveryEvent}.\n */\nexport interface DeliveryEvent {\n /** Channel this event belongs to. */\n channel: DeliveryChannel;\n /** Provider identifier (e.g. `\"twilio-sms\"`, `\"whatsapp-cloud\"`). */\n provider: string;\n /** Normalized lifecycle type. */\n type:\n | \"queued\"\n | \"sent\"\n | \"delivered\"\n | \"failed\"\n | \"read\"\n | \"bounced\"\n | \"complained\"\n | \"opened\"\n | \"clicked\"\n | \"deferred\"\n | \"unknown\";\n /** Provider message identifier when available. */\n messageId?: string;\n /** Recipient address or phone when available. */\n recipient?: string;\n /** Event timestamp when available. */\n timestamp?: Date;\n /** Original provider payload for debugging or custom handling. */\n raw: unknown;\n}\n\n/** Normalized email lifecycle event from any provider webhook. */\nexport interface EmailEvent {\n /** Provider identifier (e.g. `\"resend\"`, `\"sendgrid\"`). */\n provider: string;\n /** Normalized event type. */\n type: \"delivered\" | \"bounced\" | \"complained\" | \"opened\" | \"clicked\" | \"deferred\" | \"unknown\";\n /** Provider message identifier when available. */\n messageId?: string;\n /** Recipient email address when available. */\n recipient?: string;\n /** Event timestamp when available. */\n timestamp?: Date;\n /** Original provider payload for debugging or custom handling. */\n raw: unknown;\n}\n\n/** Map an {@link EmailEvent} into the shared {@link DeliveryEvent} shape. */\nexport function toDeliveryEvent(event: EmailEvent): DeliveryEvent {\n return deliveryEvent({\n channel: \"email\",\n provider: event.provider,\n type: event.type,\n raw: event.raw,\n ...(event.messageId !== undefined ? { messageId: event.messageId } : {}),\n ...(event.recipient !== undefined ? { recipient: event.recipient } : {}),\n ...(event.timestamp !== undefined ? { timestamp: event.timestamp } : {}),\n });\n}\n\n/** Build a {@link DeliveryEvent} respecting exact optional property types. */\nexport function deliveryEvent(input: {\n channel: DeliveryChannel;\n provider: string;\n type: DeliveryEvent[\"type\"];\n raw: unknown;\n messageId?: string | undefined;\n recipient?: string | undefined;\n timestamp?: Date | undefined;\n}): DeliveryEvent {\n const event: DeliveryEvent = {\n channel: input.channel,\n provider: input.provider,\n type: input.type,\n raw: input.raw,\n };\n\n if (input.messageId !== undefined) {\n event.messageId = input.messageId;\n }\n if (input.recipient !== undefined) {\n event.recipient = input.recipient;\n }\n if (input.timestamp !== undefined) {\n event.timestamp = input.timestamp;\n }\n\n return event;\n}\n\n/** Map a provider-specific event string to a normalized event type. */\nexport type EventTypeMapper = (event: string) => EmailEvent[\"type\"] | DeliveryEvent[\"type\"];\n\n/** Default mapper — returns `\"unknown\"` for unrecognized events. */\nexport function mapEventType<T extends string>(\n event: string,\n mapping: Record<string, T>,\n): T | \"unknown\" {\n return mapping[event] ?? (\"unknown\" as const);\n}\n\n/** Parse an ISO or Unix timestamp into a Date, or undefined when invalid. */\nexport function parseTimestamp(value: unknown): Date | undefined {\n if (typeof value === \"number\") {\n const ms = value < 1_000_000_000_000 ? value * 1000 : value;\n const date = new Date(ms);\n return Number.isNaN(date.getTime()) ? undefined : date;\n }\n if (typeof value === \"string\") {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? undefined : date;\n }\n return undefined;\n}\n\n/** Ensure payload is an array (for providers that batch events). */\nexport function asArray(payload: unknown): unknown[] {\n return Array.isArray(payload) ? payload : [payload];\n}\n\n/** Build an {@link EmailEvent} respecting exact optional property types. */\nexport function emailEvent(input: {\n provider: string;\n type: EmailEvent[\"type\"];\n raw: unknown;\n messageId?: string | undefined;\n recipient?: string | undefined;\n timestamp?: Date | undefined;\n}): EmailEvent {\n const event: EmailEvent = {\n provider: input.provider,\n type: input.type,\n raw: input.raw,\n };\n\n if (input.messageId !== undefined) {\n event.messageId = input.messageId;\n }\n if (input.recipient !== undefined) {\n event.recipient = input.recipient;\n }\n if (input.timestamp !== undefined) {\n event.timestamp = input.timestamp;\n }\n\n return event;\n}\n"
6
+ ],
7
+ "mappings": "AAoDO,SAAS,CAAe,CAAC,EAAkC,CAChE,OAAO,EAAc,CACnB,QAAS,QACT,SAAU,EAAM,SAChB,KAAM,EAAM,KACZ,IAAK,EAAM,OACP,EAAM,YAAc,OAAY,CAAE,UAAW,EAAM,SAAU,EAAI,CAAC,KAClE,EAAM,YAAc,OAAY,CAAE,UAAW,EAAM,SAAU,EAAI,CAAC,KAClE,EAAM,YAAc,OAAY,CAAE,UAAW,EAAM,SAAU,EAAI,CAAC,CACxE,CAAC,EAII,SAAS,CAAa,CAAC,EAQZ,CAChB,IAAM,EAAuB,CAC3B,QAAS,EAAM,QACf,SAAU,EAAM,SAChB,KAAM,EAAM,KACZ,IAAK,EAAM,GACb,EAEA,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAE1B,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAE1B,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAG1B,OAAO,EAOF,SAAS,CAA8B,CAC5C,EACA,EACe,CACf,OAAO,EAAQ,IAAW,UAIrB,SAAS,CAAc,CAAC,EAAkC,CAC/D,GAAI,OAAO,IAAU,SAAU,CAC7B,IAAM,EAAK,EAAQ,cAAoB,EAAQ,KAAO,EAChD,EAAO,IAAI,KAAK,CAAE,EACxB,OAAO,OAAO,MAAM,EAAK,QAAQ,CAAC,EAAI,OAAY,EAEpD,GAAI,OAAO,IAAU,SAAU,CAC7B,IAAM,EAAO,IAAI,KAAK,CAAK,EAC3B,OAAO,OAAO,MAAM,EAAK,QAAQ,CAAC,EAAI,OAAY,EAEpD,OAIK,SAAS,CAAO,CAAC,EAA6B,CACnD,OAAO,MAAM,QAAQ,CAAO,EAAI,EAAU,CAAC,CAAO,EAI7C,SAAS,CAAU,CAAC,EAOZ,CACb,IAAM,EAAoB,CACxB,SAAU,EAAM,SAChB,KAAM,EAAM,KACZ,IAAK,EAAM,GACb,EAEA,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAE1B,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAE1B,GAAI,EAAM,YAAc,OACtB,EAAM,UAAY,EAAM,UAG1B,OAAO",
8
+ "debugId": "1AD8065310A8C23164756E2164756E21",
9
+ "names": []
10
+ }
@@ -1,4 +1,4 @@
1
1
  import{createRequire as a}from"node:module";var c=a(import.meta.url);
2
- export{c as fa};
2
+ export{c as ma};
3
3
 
4
- //# debugId=F5214889C34ECFAA64756E2164756E21
4
+ //# debugId=F99FFA99A76AA45264756E2164756E21
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "F5214889C34ECFAA64756E2164756E21",
7
+ "debugId": "F99FFA99A76AA45264756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -1,4 +1,4 @@
1
1
  class v extends Error{sentlyCode;statusCode;provider;code;constructor(j,k,q){super(j,q?.cause!==void 0?{cause:q.cause}:void 0);if(this.name="SentlyError",this.sentlyCode=k,this.code=k,q?.statusCode!==void 0)this.statusCode=q.statusCode;if(q?.provider!==void 0)this.provider=q.provider}}function w(j){if(j===429)return"RATE_LIMITED";if(j>=500)return"PROVIDER_ERROR";if(j>=400)return"BAD_REQUEST";return"PROVIDER_ERROR"}function x(j,k){if(j===535||j===534)return"SMTP_AUTH_FAILED";if(j===421||j===450||j===451)return"TIMEOUT";if(j===0){if(k==="CONNECT"||k==="READ"||k==="MX")return"CONNECTION_FAILED";return"PROVIDER_ERROR"}if(j>=500)return"PROVIDER_ERROR";if(j>=400)return"BAD_REQUEST";return"PROVIDER_ERROR"}
2
- export{v as ca,w as da,x as ea};
2
+ export{v as ja,w as ka,x as la};
3
3
 
4
- //# debugId=A59A134E1BF4550C64756E2164756E21
4
+ //# debugId=817117CA04D178B564756E2164756E21
@@ -5,6 +5,6 @@
5
5
  "/**\n * @module\n * Unified error hierarchy for sently transports and SMTP.\n */\n\n/** Stable machine-readable error codes shared across providers. */\nexport type SentlyErrorCode =\n | \"INVALID_CONFIG\"\n | \"SMTP_AUTH_FAILED\"\n | \"RATE_LIMITED\"\n | \"TIMEOUT\"\n | \"CONNECTION_FAILED\"\n | \"PROVIDER_ERROR\"\n | \"BAD_REQUEST\";\n\n/** Options for constructing a {@link SentlyError}. */\nexport interface SentlyErrorOptions {\n /** HTTP status code when the failure originated from an HTTP transport. */\n statusCode?: number;\n /** Original error or response payload. */\n cause?: unknown;\n /** Provider identifier (e.g. `\"smtp\"`, `\"resend\"`). */\n provider?: string;\n}\n\n/**\n * Base error class for all sently transport and protocol failures.\n *\n * Subclasses may shadow {@link code} with provider-specific or numeric values\n * (e.g. SMTP response codes). Use {@link sentlyCode} for the stable machine-readable\n * code in those cases.\n */\nexport class SentlyError extends Error {\n /**\n * Stable machine-readable error code.\n * Preserved even when a subclass shadows {@link code}.\n */\n readonly sentlyCode: SentlyErrorCode;\n\n /** HTTP status code when applicable. */\n readonly statusCode?: number;\n\n /** Provider identifier when applicable. */\n readonly provider?: string;\n\n /**\n * Error code — machine-readable string on {@link SentlyError}, or a legacy\n * provider/SMTP-specific value on subclasses (numeric SMTP codes, Brevo/SES API codes).\n */\n code: string | number;\n\n /** Creates a sently error with a machine-readable code and optional metadata. */\n constructor(message: string, sentlyCode: SentlyErrorCode, options?: SentlyErrorOptions) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n this.name = \"SentlyError\";\n this.sentlyCode = sentlyCode;\n this.code = sentlyCode;\n if (options?.statusCode !== undefined) {\n this.statusCode = options.statusCode;\n }\n if (options?.provider !== undefined) {\n this.provider = options.provider;\n }\n }\n}\n\n/**\n * Map an HTTP status code to a stable sently error code.\n *\n * @param status - HTTP response status code\n * @returns Machine-readable error code\n */\nexport function httpStatusToSentlyCode(status: number): SentlyErrorCode {\n if (status === 429) {\n return \"RATE_LIMITED\";\n }\n if (status >= 500) {\n return \"PROVIDER_ERROR\";\n }\n if (status >= 400) {\n return \"BAD_REQUEST\";\n }\n return \"PROVIDER_ERROR\";\n}\n\n/**\n * Map an SMTP response code and command to a stable sently error code.\n *\n * @param smtpCode - Three-digit SMTP response code (0 for local/parse errors)\n * @param command - SMTP command that failed\n * @returns Machine-readable error code\n */\nexport function smtpCodeToSentlyCode(smtpCode: number, command: string): SentlyErrorCode {\n if (smtpCode === 535 || smtpCode === 534) {\n return \"SMTP_AUTH_FAILED\";\n }\n if (smtpCode === 421 || smtpCode === 450 || smtpCode === 451) {\n return \"TIMEOUT\";\n }\n if (smtpCode === 0) {\n if (command === \"CONNECT\" || command === \"READ\" || command === \"MX\") {\n return \"CONNECTION_FAILED\";\n }\n return \"PROVIDER_ERROR\";\n }\n if (smtpCode >= 500) {\n return \"PROVIDER_ERROR\";\n }\n if (smtpCode >= 400) {\n return \"BAD_REQUEST\";\n }\n return \"PROVIDER_ERROR\";\n}\n"
6
6
  ],
7
7
  "mappings": "AAgCO,MAAM,UAAoB,KAAM,CAK5B,WAGA,WAGA,SAMT,KAGA,WAAW,CAAC,EAAiB,EAA6B,EAA8B,CACtF,MAAM,EAAS,GAAS,QAAU,OAAY,CAAE,MAAO,EAAQ,KAAM,EAAI,MAAS,EAIlF,GAHA,KAAK,KAAO,cACZ,KAAK,WAAa,EAClB,KAAK,KAAO,EACR,GAAS,aAAe,OAC1B,KAAK,WAAa,EAAQ,WAE5B,GAAI,GAAS,WAAa,OACxB,KAAK,SAAW,EAAQ,SAG9B,CAQO,SAAS,CAAsB,CAAC,EAAiC,CACtE,GAAI,IAAW,IACb,MAAO,eAET,GAAI,GAAU,IACZ,MAAO,iBAET,GAAI,GAAU,IACZ,MAAO,cAET,MAAO,iBAUF,SAAS,CAAoB,CAAC,EAAkB,EAAkC,CACvF,GAAI,IAAa,KAAO,IAAa,IACnC,MAAO,mBAET,GAAI,IAAa,KAAO,IAAa,KAAO,IAAa,IACvD,MAAO,UAET,GAAI,IAAa,EAAG,CAClB,GAAI,IAAY,WAAa,IAAY,QAAU,IAAY,KAC7D,MAAO,oBAET,MAAO,iBAET,GAAI,GAAY,IACd,MAAO,iBAET,GAAI,GAAY,IACd,MAAO,cAET,MAAO",
8
- "debugId": "A59A134E1BF4550C64756E2164756E21",
8
+ "debugId": "817117CA04D178B564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,13 @@
1
+ import{da as O,ea as K,ia as H}from"./chunk-hnzmn4s4.js";import{ja as v,la as B}from"./chunk-ttbwyxmh.js";var j=64;function X(q){return q>>>0}function U(q){let z=g(q),G=1732584193,Q=4023233417,N=2562383102,J=271733878;for(let F=0;F<z.length;F+=64){let $=z.subarray(F,F+64),w=new Uint32Array(16);for(let W=0;W<16;W++){let A=W*4;w[W]=X(($[A]??0)|($[A+1]??0)<<8|($[A+2]??0)<<16|($[A+3]??0)<<24)}let x=G,D=Q,I=N,R=J;for(let W=0;W<64;W++){let A,_;if(W<16)A=X(D&I|~D&R),_=W;else if(W<32)A=X(D&R|I&~R),_=X((5*W+1)%16);else if(W<48)A=X(D^I^R),_=X((3*W+5)%16);else A=X(I^(D|~R)),_=X(7*W%16);let y=R;R=I,I=D,D=X(D+T(X(x+A+X((P[W]??0)+(w[_]??0))),L[W]??0)),x=y}G=X(G+x),Q=X(Q+D),N=X(N+I),J=X(J+R)}let Y=new Uint8Array(16),V=new DataView(Y.buffer);return V.setUint32(0,G,!0),V.setUint32(4,Q,!0),V.setUint32(8,N,!0),V.setUint32(12,J,!0),Y}var L=[7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21],P=new Uint32Array([3614090360,3905402710,606105819,3250441966,4118548399,1200080426,2821735955,4249261313,1770035416,2336552879,4294925233,2304563134,1804603682,4254626195,2792965006,1236535329,4129170786,3225465664,643717713,3921069994,3593408605,38016083,3634488961,3889429448,568446438,3275163606,4107603335,1163531501,2850285829,4243563512,1735328473,2368359562,4294588738,2272392833,1839030562,4259657740,2763975236,1272893353,4139469664,3200236656,681279174,3936430074,3572445317,76029189,3654602809,3873151461,530742520,3299628645,4096336452,1126891415,2878612391,4237533241,1700485571,2399980690,4293915773,2240044497,1873313359,4264355552,2734768916,1309151649,4149444226,3174756917,718787259,3951481745]);function T(q,z){return X(q<<z|q>>>32-z)}function g(q){let z=q.length*8,G=(56-(q.length+1)%64+64)%64,Q=q.length+1+G+8,N=new Uint8Array(Q);N.set(q),N[q.length]=128;let J=new DataView(N.buffer);return J.setUint32(Q-8,z>>>0,!0),J.setUint32(Q-4,Math.floor(z/4294967296),!0),N}function C(q,z){let G=q;if(G.length>j)G=U(G);let Q=new Uint8Array(j);Q.set(G);let N=new Uint8Array(j),J=new Uint8Array(j);for(let $=0;$<j;$++)N[$]=(Q[$]??0)^54,J[$]=(Q[$]??0)^92;let Y=new Uint8Array(N.length+z.length);Y.set(N),Y.set(z,N.length);let V=U(Y),F=new Uint8Array(J.length+V.length);return F.set(J),F.set(V,J.length),U(F)}function E(q){return Array.from(q,(z)=>z.toString(16).padStart(2,"0")).join("")}async function M(q,z,G){let Q=K(q.trim()),N=H(G),J=C(N,Q),Y=E(J);return O(`${z} ${Y}`).replace(/\r\n/g,"")}class Z extends v{command;response;constructor(q,z,G,Q){super(q,B(z,G),{provider:"smtp"});this.command=G;this.response=Q;this.name="SMTPError",this.code=z}}function u(q){let z;switch(q.type){case"EHLO":{z=`EHLO ${q.domain.replace(/[\r\n]/g,"")}`;break}case"STARTTLS":z="STARTTLS";break;case"AUTH_LOGIN":z="AUTH LOGIN";break;case"AUTH_PLAIN":z=`AUTH PLAIN ${O(`\x00${q.user}\x00${q.pass}`).replace(/\r\n/g,"")}`;break;case"AUTH_CRAM_MD5_INIT":z="AUTH CRAM-MD5";break;case"AUTH_CRAM_MD5_RESPONSE":return H(`${q.response}\r
2
+ `);case"AUTH_XOAUTH2":z=`AUTH XOAUTH2 ${q.xoauth2String}`;break;case"MAIL_FROM":if(/[\r\n]/.test(q.address))throw new Z("Invalid address: contains CRLF",0,"MAIL FROM",q.address);z=`MAIL FROM:<${q.address}>`;break;case"RCPT_TO":if(/[\r\n]/.test(q.address))throw new Z("Invalid address: contains CRLF",0,"RCPT TO",q.address);z=`RCPT TO:<${q.address}>`;break;case"DATA":z="DATA";break;case"DATA_BODY":return H(S(q.content));case"QUIT":z="QUIT";break;case"RSET":z="RSET";break;case"NOOP":z="NOOP";break}return H(`${z}\r
3
+ `)}function l(q){let z=new TextDecoder().decode(q).trim(),G=z.split(/\r?\n/),N=(G[G.length-1]??"").match(/^(\d{3})([\s-])(.*)$/);if(!N)throw new Z("Invalid SMTP response",0,"PARSE",z);let J=Number.parseInt(N[1]??"0",10),Y=G.map((V)=>V.replace(/^\d{3}[\s-]/,"")).join(" ");return{code:J,message:Y,isSuccess:J>=200&&J<300,isReady:J>=300&&J<400,isError:J>=400}}function p(q){if(q.length===0)return null;let z=q.reduce((V,F)=>V+F.length,0),G=new Uint8Array(z),Q=0;for(let V of q)G.set(V,Q),Q+=V.length;let J=new TextDecoder().decode(G).split(/\r?\n/).filter((V)=>V.length>0);if(J.length===0)return null;let Y=J[J.length-1]??"";if(/^\d{3} /.test(Y))return G;return null}function m(q){let z=q.map((G)=>G.toUpperCase());if(z.some((G)=>G.includes("AUTH")&&G.includes("XOAUTH2")))return"OAUTH2";if(z.some((G)=>G.includes("AUTH")&&G.includes("CRAM-MD5")))return"CRAM-MD5";if(z.some((G)=>G.includes("AUTH")&&G.includes("LOGIN")))return"LOGIN";if(z.some((G)=>G.includes("AUTH")&&G.includes("PLAIN")))return"PLAIN";throw new Z("No supported AUTH method",0,"EHLO",q.join(" "))}function i(q){return q.message.split(/\s+/).flatMap((z)=>z.split(/\r?\n/)).filter(Boolean)}function r(q,z,G){if(!z.includes(q.code))throw new Z(`Unexpected SMTP response for ${G}`,q.code,G,q.message)}function S(q){return`${new TextDecoder().decode(q).split(/\r?\n/).map((N)=>N.startsWith(".")?`.${N}`:N).join(`\r
4
+ `)}\r
5
+ .\r
6
+ `}function t(q){return H(`${O(q).replace(/\r\n/g,"")}\r
7
+ `)}function o(q){return H(`${O(q).replace(/\r\n/g,"")}\r
8
+ `)}function n(q){return H(`${q}\r
9
+ `)}function s(q){return H(`${q}\r
10
+ `)}
11
+ export{M as x,Z as y,u as z,l as A,p as B,m as C,i as D,r as E,t as F,o as G,n as H,s as I};
12
+
13
+ //# debugId=F548381F8CF8AC4F64756E2164756E21
@@ -5,7 +5,7 @@
5
5
  "/**\n * @module\n * Pure-JS HMAC-MD5 implementation for SMTP CRAM-MD5 authentication.\n * Web Crypto does not support MD5, so this is implemented in pure TypeScript\n * with no external dependencies.\n *\n * @example\n * ```ts\n * import { computeCRAMMD5 } from \"sently/core/cram-md5\";\n * const response = await computeCRAMMD5(\"<challenge>\", \"user\", \"pass\");\n * ```\n */\nimport { decodeBase64, encodeBase64, encodeUtf8 } from \"./base64.js\";\n\n/** MD5 block size in bytes (HMAC block size per RFC 2104). */\nconst BLOCK_SIZE = 64;\n\n/** Coerce to unsigned 32-bit integer. */\nfunction u32(x: number): number {\n return x >>> 0;\n}\n\n/**\n * Compute an MD5 hash of the given data (RFC 1321).\n */\nexport function md5(data: Uint8Array): Uint8Array {\n const padded = padMessage(data);\n\n let a0 = 0x67452301;\n let b0 = 0xefcdab89;\n let c0 = 0x98badcfe;\n let d0 = 0x10325476;\n\n for (let i = 0; i < padded.length; i += 64) {\n const block = padded.subarray(i, i + 64);\n const m = new Uint32Array(16);\n for (let j = 0; j < 16; j++) {\n const o = j * 4;\n m[j] = u32(\n (block[o] ?? 0) |\n ((block[o + 1] ?? 0) << 8) |\n ((block[o + 2] ?? 0) << 16) |\n ((block[o + 3] ?? 0) << 24),\n );\n }\n\n let a = a0;\n let b = b0;\n let c = c0;\n let d = d0;\n\n for (let k = 0; k < 64; k++) {\n let f: number;\n let g: number;\n if (k < 16) {\n f = u32((b & c) | (~b & d));\n g = k;\n } else if (k < 32) {\n f = u32((b & d) | (c & ~d));\n g = u32((5 * k + 1) % 16);\n } else if (k < 48) {\n f = u32(b ^ c ^ d);\n g = u32((3 * k + 5) % 16);\n } else {\n f = u32(c ^ (b | ~d));\n g = u32((7 * k) % 16);\n }\n\n const temp = d;\n d = c;\n c = b;\n b = u32(b + leftRotate(u32(a + f + u32((K[k] ?? 0) + (m[g] ?? 0))), S[k] ?? 0));\n a = temp;\n }\n\n a0 = u32(a0 + a);\n b0 = u32(b0 + b);\n c0 = u32(c0 + c);\n d0 = u32(d0 + d);\n }\n\n const out = new Uint8Array(16);\n const view = new DataView(out.buffer);\n view.setUint32(0, a0, true);\n view.setUint32(4, b0, true);\n view.setUint32(8, c0, true);\n view.setUint32(12, d0, true);\n return out;\n}\n\nconst S = [\n 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14,\n 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6,\n 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,\n];\n\nconst K = new Uint32Array([\n 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,\n 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,\n 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,\n 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,\n 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,\n 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,\n 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,\n 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,\n]);\n\nfunction leftRotate(value: number, shift: number): number {\n return u32((value << shift) | (value >>> (32 - shift)));\n}\n\nfunction padMessage(data: Uint8Array): Uint8Array {\n const bitLen = data.length * 8;\n const padLen = (56 - ((data.length + 1) % 64) + 64) % 64;\n const totalLen = data.length + 1 + padLen + 8;\n const padded = new Uint8Array(totalLen);\n padded.set(data);\n padded[data.length] = 0x80;\n\n const view = new DataView(padded.buffer);\n view.setUint32(totalLen - 8, bitLen >>> 0, true);\n view.setUint32(totalLen - 4, Math.floor(bitLen / 0x100000000), true);\n return padded;\n}\n\n/**\n * Compute HMAC-MD5(key, data) per RFC 2104.\n */\nexport function hmacMD5(key: Uint8Array, data: Uint8Array): Uint8Array {\n let k = key;\n if (k.length > BLOCK_SIZE) {\n k = md5(k);\n }\n const paddedKey = new Uint8Array(BLOCK_SIZE);\n paddedKey.set(k);\n\n const ipad = new Uint8Array(BLOCK_SIZE);\n const opad = new Uint8Array(BLOCK_SIZE);\n for (let i = 0; i < BLOCK_SIZE; i++) {\n ipad[i] = (paddedKey[i] ?? 0) ^ 0x36;\n opad[i] = (paddedKey[i] ?? 0) ^ 0x5c;\n }\n\n const inner = new Uint8Array(ipad.length + data.length);\n inner.set(ipad);\n inner.set(data, ipad.length);\n const innerHash = md5(inner);\n\n const outer = new Uint8Array(opad.length + innerHash.length);\n outer.set(opad);\n outer.set(innerHash, opad.length);\n return md5(outer);\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/**\n * Compute the CRAM-MD5 response string for SMTP authentication.\n *\n * @param challenge - base64-encoded challenge from server\n * @param user - SMTP username\n * @param pass - SMTP password\n * @returns base64-encoded CRAM-MD5 response\n */\nexport async function computeCRAMMD5(\n challenge: string,\n user: string,\n pass: string,\n): Promise<string> {\n const challengeBytes = decodeBase64(challenge.trim());\n const passBytes = encodeUtf8(pass);\n const digest = hmacMD5(passBytes, challengeBytes);\n const hex = bytesToHex(digest);\n return encodeBase64(`${user} ${hex}`).replace(/\\r\\n/g, \"\");\n}\n",
6
6
  "// src/core/smtp.ts\nimport { encodeBase64, encodeUtf8 } from \"./base64.js\";\nimport { SentlyError, smtpCodeToSentlyCode } from \"./errors.js\";\n\nexport { computeCRAMMD5 } from \"./cram-md5.js\";\n\n/** SMTP command to send to the server. */\nexport type SMTPCommand =\n | { type: \"EHLO\"; domain: string }\n | { type: \"STARTTLS\" }\n | { type: \"AUTH_LOGIN\"; user: string; pass: string }\n | { type: \"AUTH_PLAIN\"; user: string; pass: string }\n | { type: \"AUTH_CRAM_MD5_INIT\" }\n | { type: \"AUTH_CRAM_MD5_RESPONSE\"; response: string }\n | { type: \"AUTH_XOAUTH2\"; xoauth2String: string }\n | { type: \"MAIL_FROM\"; address: string }\n | { type: \"RCPT_TO\"; address: string }\n | { type: \"DATA\" }\n | { type: \"DATA_BODY\"; content: Uint8Array }\n | { type: \"QUIT\" }\n | { type: \"RSET\" }\n | { type: \"NOOP\" };\n\n/** Parsed SMTP server response. */\nexport interface SMTPResponse {\n /** Three-digit SMTP status code. */\n code: number;\n /** Human-readable response text after the status code. */\n message: string;\n /** True when the code is in the 2xx success range. */\n isSuccess: boolean;\n /** True when the code is 354 (ready for message data). */\n isReady: boolean;\n /** True when the code is 4xx or 5xx. */\n isError: boolean;\n}\n\n/** SMTP protocol error with server response details. */\nexport class SMTPError extends SentlyError {\n /** Creates an SMTP protocol error. */\n constructor(\n message: string,\n smtpCode: number,\n public readonly command: string,\n public readonly response: string,\n ) {\n super(message, smtpCodeToSentlyCode(smtpCode, command), { provider: \"smtp\" });\n this.name = \"SMTPError\";\n this.code = smtpCode;\n }\n}\n\n/**\n * Encode an SMTPCommand into a Uint8Array for sending over the socket.\n */\nexport function encodeCommand(cmd: SMTPCommand): Uint8Array {\n let line: string;\n\n switch (cmd.type) {\n case \"EHLO\": {\n const safeDomain = cmd.domain.replace(/[\\r\\n]/g, \"\");\n line = `EHLO ${safeDomain}`;\n break;\n }\n case \"STARTTLS\":\n line = \"STARTTLS\";\n break;\n case \"AUTH_LOGIN\":\n line = \"AUTH LOGIN\";\n break;\n case \"AUTH_PLAIN\":\n line = `AUTH PLAIN ${encodeBase64(`\\0${cmd.user}\\0${cmd.pass}`).replace(/\\r\\n/g, \"\")}`;\n break;\n case \"AUTH_CRAM_MD5_INIT\":\n line = \"AUTH CRAM-MD5\";\n break;\n case \"AUTH_CRAM_MD5_RESPONSE\":\n return encodeUtf8(`${cmd.response}\\r\\n`);\n case \"AUTH_XOAUTH2\":\n line = `AUTH XOAUTH2 ${cmd.xoauth2String}`;\n break;\n case \"MAIL_FROM\":\n if (/[\\r\\n]/.test(cmd.address)) {\n throw new SMTPError(`Invalid address: contains CRLF`, 0, \"MAIL FROM\", cmd.address);\n }\n line = `MAIL FROM:<${cmd.address}>`;\n break;\n case \"RCPT_TO\":\n if (/[\\r\\n]/.test(cmd.address)) {\n throw new SMTPError(`Invalid address: contains CRLF`, 0, \"RCPT TO\", cmd.address);\n }\n line = `RCPT TO:<${cmd.address}>`;\n break;\n case \"DATA\":\n line = \"DATA\";\n break;\n case \"DATA_BODY\":\n return encodeUtf8(applyDotStuffing(cmd.content));\n case \"QUIT\":\n line = \"QUIT\";\n break;\n case \"RSET\":\n line = \"RSET\";\n break;\n case \"NOOP\":\n line = \"NOOP\";\n break;\n }\n\n return encodeUtf8(`${line}\\r\\n`);\n}\n\n/**\n * Parse raw bytes from the server into an SMTPResponse.\n */\nexport function parseResponse(data: Uint8Array): SMTPResponse {\n const text = new TextDecoder().decode(data).trim();\n const lines = text.split(/\\r?\\n/);\n const lastLine = lines[lines.length - 1] ?? \"\";\n const match = lastLine.match(/^(\\d{3})([\\s-])(.*)$/);\n\n if (!match) {\n throw new SMTPError(\"Invalid SMTP response\", 0, \"PARSE\", text);\n }\n\n const code = Number.parseInt(match[1] ?? \"0\", 10);\n const message = lines.map((l) => l.replace(/^\\d{3}[\\s-]/, \"\")).join(\" \");\n\n return {\n code,\n message,\n isSuccess: code >= 200 && code < 300,\n isReady: code >= 300 && code < 400,\n isError: code >= 400,\n };\n}\n\n/**\n * Accumulate byte chunks until a complete SMTP response is received.\n */\nexport function accumulateResponse(chunks: Uint8Array[]): Uint8Array | null {\n if (chunks.length === 0) {\n return null;\n }\n\n const total = chunks.reduce((sum, c) => sum + c.length, 0);\n const combined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n const text = new TextDecoder().decode(combined);\n const lines = text.split(/\\r?\\n/).filter((l) => l.length > 0);\n\n if (lines.length === 0) {\n return null;\n }\n\n const lastLine = lines[lines.length - 1] ?? \"\";\n if (/^\\d{3} /.test(lastLine)) {\n return combined;\n }\n\n return null;\n}\n\n/**\n * Select the best AUTH method from EHLO capability lines.\n * Priority: XOAUTH2 > CRAM-MD5 > LOGIN > PLAIN.\n */\nexport function selectAuthMethod(\n capabilities: string[],\n): \"LOGIN\" | \"PLAIN\" | \"CRAM-MD5\" | \"OAUTH2\" {\n const upper = capabilities.map((c) => c.toUpperCase());\n if (upper.some((c) => c.includes(\"AUTH\") && c.includes(\"XOAUTH2\"))) {\n return \"OAUTH2\";\n }\n if (upper.some((c) => c.includes(\"AUTH\") && c.includes(\"CRAM-MD5\"))) {\n return \"CRAM-MD5\";\n }\n if (upper.some((c) => c.includes(\"AUTH\") && c.includes(\"LOGIN\"))) {\n return \"LOGIN\";\n }\n if (upper.some((c) => c.includes(\"AUTH\") && c.includes(\"PLAIN\"))) {\n return \"PLAIN\";\n }\n throw new SMTPError(\"No supported AUTH method\", 0, \"EHLO\", capabilities.join(\" \"));\n}\n\n/**\n * Parse an EHLO multi-line response and extract capability keywords.\n */\nexport function parseEHLO(response: SMTPResponse): string[] {\n return response.message\n .split(/\\s+/)\n .flatMap((part) => part.split(/\\r?\\n/))\n .filter(Boolean);\n}\n\n/**\n * Assert that an SMTPResponse code is within the expected set.\n */\nexport function assertResponse(\n response: SMTPResponse,\n expectedCodes: number[],\n command: string,\n): void {\n if (!expectedCodes.includes(response.code)) {\n throw new SMTPError(\n `Unexpected SMTP response for ${command}`,\n response.code,\n command,\n response.message,\n );\n }\n}\n\nfunction applyDotStuffing(content: Uint8Array): string {\n const text = new TextDecoder().decode(content);\n const lines = text.split(/\\r?\\n/);\n const stuffed = lines.map((line) => (line.startsWith(\".\") ? `.${line}` : line));\n return `${stuffed.join(\"\\r\\n\")}\\r\\n.\\r\\n`;\n}\n\n/** Encode AUTH LOGIN password step (second base64 chunk). */\nexport function encodeAuthLoginPass(pass: string): Uint8Array {\n return encodeUtf8(`${encodeBase64(pass).replace(/\\r\\n/g, \"\")}\\r\\n`);\n}\n\n/** Encode AUTH LOGIN user step when sent separately after 334. */\nexport function encodeAuthLoginUser(user: string): Uint8Array {\n return encodeUtf8(`${encodeBase64(user).replace(/\\r\\n/g, \"\")}\\r\\n`);\n}\n\n/** Encode CRAM-MD5 response after challenge. */\nexport function encodeAuthCramResponse(response: string): Uint8Array {\n return encodeUtf8(`${response}\\r\\n`);\n}\n\n/** Encode raw SMTP line with CRLF. */\nexport function encodeLine(line: string): Uint8Array {\n return encodeUtf8(`${line}\\r\\n`);\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "E879B8E2491095AF64756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "F548381F8CF8AC4F64756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -0,0 +1,4 @@
1
+ import{P as S}from"./chunk-cs1tvehn.js";import{Q as E}from"./chunk-7wtfjx0d.js";import{U as D}from"./chunk-8kpgbrba.js";import{$ as f,aa as q,ba as z,ca as O}from"./chunk-htdg075t.js";import{ja as k}from"./chunk-ttbwyxmh.js";var v="SMTP config passed to transport-only createMailer. Use: import { createSMTPMailer } from 'sently' or import { createSMTPMailer } from 'sently/smtp'.";async function u(j){if(j.transport===void 0||"host"in j&&j.transport===void 0)throw new k(v,"INVALID_CONFIG");return new M(j.transport,j.plugins??[],j.hooks)}function b(j){return j.attachments!==void 0&&j.attachments.length>0}function y(j){return S(j)}function _(j,K){return{...j.messageId!==void 0?{messageId:j.messageId}:{},to:D(j.to),subject:j.subject,provider:y(K)}}class M{transport;plugins;hooks;constructor(j,K=[],V){this.transport=j;this.plugins=K;this.hooks=V}async send(j){let K=await O(j,this.plugins),V=_(K,this.transport);if(await z(this.hooks?.onSend,V),this.hooks?.onRetry!==void 0&&f(this.transport))this.transport.setMailerOnRetry((w,C)=>{z(this.hooks?.onRetry,V,w,C)});if(this.hooks?.onFallback!==void 0&&q(this.transport))this.transport.setMailerOnFallback((w,C,T)=>{z(this.hooks?.onFallback,V,w,C,T)});let A=performance.now();try{let w=await this.transport.send(K),C={...V,messageId:w.messageId};return await z(this.hooks?.onSuccess,C,w,performance.now()-A),w}catch(w){throw await z(this.hooks?.onError,V,w,performance.now()-A),w}finally{if(f(this.transport))this.transport.setMailerOnRetry(void 0);if(q(this.transport))this.transport.setMailerOnFallback(void 0)}}async processMessage(j){return O(j,this.plugins)}async sendBulk(j,K){if(j.length===0)return{total:0,sent:0,failed:0,results:[]};let V=Array(j.length),A=K?.stopOnError??!1,w=!1,C=async(X,$,B,Q,Z)=>{if(V[$]={status:"sent",result:B},Q!==void 0&&this.hooks!==void 0){let W=_(Q,this.transport);await z(this.hooks.onSend,W),await z(this.hooks.onSuccess,{...W,messageId:B.messageId},B,Z)}K?.onSuccess?.(X,$,B)},T=async(X,$,B,Q,Z)=>{if(V[$]={status:"failed",error:B},Q!==void 0&&this.hooks!==void 0){let W=_(Q,this.transport);await z(this.hooks.onSend,W),await z(this.hooks.onError,W,B,Z)}if(K?.onError?.(X,$,B),A)w=!0};if(this.transport.sendBatch){let X=[],$=[];for(let[B,Q]of j.entries())if(b(Q))$.push({index:B,message:Q});else X.push({index:B,message:Q});if(X.length>0&&!w){let B=this.transport.batchMax??X.length,Q=K?.rateDelta??2,Z=Q>0?new E(Q,K?.rateLimit??1000,K?.now):null;for(let W=0;W<X.length&&!w;W+=B){let U=X.slice(W,W+B);if(Z)await Z.acquire();try{let Y=await Promise.all(U.map(({message:G})=>this.processMessage(G))),J=performance.now(),H=await this.transport.sendBatch(Y),I=performance.now()-J;for(let G=0;G<U.length;G++){let R=U[G],L=Y[G],F=H[G];if(F===void 0)await T(R.message,R.index,Error("Batch response missing result for message"),L,I);else if(F.batchError!==void 0)await T(R.message,R.index,F.batchError,L,I);else await C(R.message,R.index,F,L,I)}}catch(Y){let J=await Promise.all(U.map(({message:H})=>this.processMessage(H)));for(let H=0;H<U.length;H++){if(w)break;let I=U[H];await T(I.message,I.index,Y,J[H])}}}}if($.length>0&&!w){let B=K?.concurrency??1,Q=[...$],Z=0;await new Promise((W)=>{let U=()=>{if(Q.length===0&&Z===0||w)W()},Y=()=>{if(Q.length===0||w){U();return}let J=Q.shift();if(J===void 0){U();return}Z++,this.send(J.message).then((H)=>{V[J.index]={status:"sent",result:H},K?.onSuccess?.(J.message,J.index,H)}).catch((H)=>{if(V[J.index]={status:"failed",error:H},K?.onError?.(J.message,J.index,H),A)w=!0}).finally(()=>{Z--,Y(),U()})};for(let J=0;J<B;J++)Y()})}}else{let X=K?.concurrency??1,$=[...j.entries()],B=0;await new Promise((Q)=>{let Z=()=>{if($.length===0&&B===0||w)Q()},W=()=>{if($.length===0||w){Z();return}let U=$.shift();if(U===void 0){Z();return}let[Y,J]=U;B++,this.send(J).then((H)=>{V[Y]={status:"sent",result:H},K?.onSuccess?.(J,Y,H)}).catch((H)=>{if(V[Y]={status:"failed",error:H},K?.onError?.(J,Y,H),A)w=!0}).finally(()=>{B--,W(),Z()})};for(let U=0;U<X;U++)W()})}let N=0,P=0;for(let X of V){if(X===void 0)continue;if(X.status==="sent")N++;else P++}return{total:j.length,sent:N,failed:P,results:V}}verify(){if(this.transport.verify)return this.transport.verify();return Promise.resolve({ok:!0,provider:"mailer"})}close(){if(this.transport.close)return this.transport.close();return Promise.resolve()}}
2
+ export{u as N,M as O};
3
+
4
+ //# debugId=04FD0B7C27E59A4C64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/mailer.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @module\n * Lightweight mailer factory for custom transports — no SMTP code in the bundle.\n *\n * Sently-first: apps call {@link createMailer}; providers implement `Transport`.\n * Use this entry instead of `sently` when you pass a transport explicitly\n * (Resend, SendGrid, etc.) and want the smallest bundle size.\n *\n * @example\n * ```ts\n * import { createMailer } from \"sently/mailer\";\n * import { ResendTransport } from \"sently/transports/resend\";\n *\n * const mailer = await createMailer({\n * transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }),\n * });\n *\n * await mailer.send({\n * from: \"onboarding@yourdomain.com\",\n * to: \"recipient@example.com\",\n * subject: \"Hello\",\n * html: \"<p>Sent via Resend</p>\",\n * });\n * ```\n */\nimport { extractEmails } from \"./core/address.js\";\nimport { isFallbackHookTransport, isRetryHookTransport } from \"./core/decorator-hooks.js\";\nimport { SentlyError } from \"./core/errors.js\";\nimport { invokeHook } from \"./core/hooks.js\";\nimport { runPlugins } from \"./core/plugin.js\";\nimport { getProviderLabel } from \"./core/provider-label.js\";\nimport { RateLimiter } from \"./core/rate-limiter.js\";\nimport type {\n BulkSendOptions,\n BulkSendResult,\n Mailer,\n MailerHookContext,\n MailerHooks,\n MailOptions,\n MailPlugin,\n SendResult,\n Transport,\n TransportMailerOptions,\n VerifyResult,\n} from \"./core/types.js\";\n\nexport type { MailerHookContext, MailerHooks, TransportMailerOptions };\n\nconst TRANSPORT_ONLY_SMTP_CONFIG_MESSAGE =\n \"SMTP config passed to transport-only createMailer. Use: import { createSMTPMailer } from 'sently' or import { createSMTPMailer } from 'sently/smtp'.\";\n\n/**\n * Create a mailer that wraps a custom {@link Transport} (HTTP API, preview, retry, etc.).\n */\nexport async function createMailer(options: TransportMailerOptions): Promise<Mailer> {\n if (options.transport === undefined || (\"host\" in options && options.transport === undefined)) {\n throw new SentlyError(TRANSPORT_ONLY_SMTP_CONFIG_MESSAGE, \"INVALID_CONFIG\");\n }\n\n return new MailerImpl(options.transport, options.plugins ?? [], options.hooks);\n}\n\nfunction hasAttachments(message: MailOptions): boolean {\n return message.attachments !== undefined && message.attachments.length > 0;\n}\n\n/** Infer a provider label from a transport instance for hook context. */\nfunction inferProvider(transport: Transport): string {\n return getProviderLabel(transport);\n}\n\n/** Build hook context from mail options (no body fields). */\nfunction buildHookContext(options: MailOptions, transport: Transport): MailerHookContext {\n return {\n ...(options.messageId !== undefined ? { messageId: options.messageId } : {}),\n to: extractEmails(options.to),\n subject: options.subject,\n provider: inferProvider(transport),\n };\n}\n\n/** Internal mailer implementation shared with the full `sently` entry. */\nexport class MailerImpl implements Mailer {\n constructor(\n private readonly transport: Transport,\n private readonly plugins: MailPlugin[] = [],\n private readonly hooks?: MailerHooks,\n ) {}\n\n async send(options: MailOptions): Promise<SendResult> {\n const processed = await runPlugins(options, this.plugins);\n const ctx = buildHookContext(processed, this.transport);\n\n await invokeHook(this.hooks?.onSend, ctx);\n\n if (this.hooks?.onRetry !== undefined && isRetryHookTransport(this.transport)) {\n this.transport.setMailerOnRetry((attempt, error) => {\n void invokeHook(this.hooks?.onRetry, ctx, attempt, error);\n });\n }\n\n if (this.hooks?.onFallback !== undefined && isFallbackHookTransport(this.transport)) {\n this.transport.setMailerOnFallback((failedProvider, nextProvider, error) => {\n void invokeHook(this.hooks?.onFallback, ctx, failedProvider, nextProvider, error);\n });\n }\n\n const start = performance.now();\n\n try {\n const result = await this.transport.send(processed);\n const successCtx: MailerHookContext = {\n ...ctx,\n messageId: result.messageId,\n };\n await invokeHook(this.hooks?.onSuccess, successCtx, result, performance.now() - start);\n return result;\n } catch (error) {\n await invokeHook(this.hooks?.onError, ctx, error, performance.now() - start);\n throw error;\n } finally {\n if (isRetryHookTransport(this.transport)) {\n this.transport.setMailerOnRetry(undefined);\n }\n if (isFallbackHookTransport(this.transport)) {\n this.transport.setMailerOnFallback(undefined);\n }\n }\n }\n\n private async processMessage(message: MailOptions): Promise<MailOptions> {\n return runPlugins(message, this.plugins);\n }\n\n async sendBulk(messages: MailOptions[], options?: BulkSendOptions): Promise<BulkSendResult> {\n if (messages.length === 0) {\n return { total: 0, sent: 0, failed: 0, results: [] };\n }\n\n const results: BulkSendResult[\"results\"] = new Array(messages.length);\n const stopOnError = options?.stopOnError ?? false;\n let halted = false;\n\n const recordSuccess = async (\n message: MailOptions,\n index: number,\n result: SendResult,\n processed?: MailOptions,\n durationMs?: number,\n ): Promise<void> => {\n results[index] = { status: \"sent\", result };\n if (processed !== undefined && this.hooks !== undefined) {\n const ctx = buildHookContext(processed, this.transport);\n await invokeHook(this.hooks.onSend, ctx);\n await invokeHook(\n this.hooks.onSuccess,\n { ...ctx, messageId: result.messageId },\n result,\n durationMs,\n );\n }\n options?.onSuccess?.(message, index, result);\n };\n\n const recordFailure = async (\n message: MailOptions,\n index: number,\n error: unknown,\n processed?: MailOptions,\n durationMs?: number,\n ): Promise<void> => {\n results[index] = { status: \"failed\", error };\n if (processed !== undefined && this.hooks !== undefined) {\n const ctx = buildHookContext(processed, this.transport);\n await invokeHook(this.hooks.onSend, ctx);\n await invokeHook(this.hooks.onError, ctx, error, durationMs);\n }\n options?.onError?.(message, index, error);\n if (stopOnError) {\n halted = true;\n }\n };\n\n if (this.transport.sendBatch) {\n const batchEntries: Array<{ index: number; message: MailOptions }> = [];\n const singleEntries: Array<{ index: number; message: MailOptions }> = [];\n\n for (const [index, message] of messages.entries()) {\n if (hasAttachments(message)) {\n singleEntries.push({ index, message });\n } else {\n batchEntries.push({ index, message });\n }\n }\n\n if (batchEntries.length > 0 && !halted) {\n const chunkSize = this.transport.batchMax ?? batchEntries.length;\n const rateDelta = options?.rateDelta ?? 2;\n const rateLimiter =\n rateDelta > 0\n ? new RateLimiter(rateDelta, options?.rateLimit ?? 1000, options?.now)\n : null;\n\n for (\n let chunkStart = 0;\n chunkStart < batchEntries.length && !halted;\n chunkStart += chunkSize\n ) {\n const chunk = batchEntries.slice(chunkStart, chunkStart + chunkSize);\n\n if (rateLimiter) {\n await rateLimiter.acquire();\n }\n\n try {\n const processed = await Promise.all(\n chunk.map(({ message }) => this.processMessage(message)),\n );\n const batchStart = performance.now();\n const batchResults = await this.transport.sendBatch(processed);\n const batchDurationMs = performance.now() - batchStart;\n\n for (let i = 0; i < chunk.length; i++) {\n const entry = chunk[i] as { index: number; message: MailOptions };\n const processedMessage = processed[i] as MailOptions;\n const result = batchResults[i];\n if (result === undefined) {\n await recordFailure(\n entry.message,\n entry.index,\n new Error(\"Batch response missing result for message\"),\n processedMessage,\n batchDurationMs,\n );\n } else if (result.batchError !== undefined) {\n await recordFailure(\n entry.message,\n entry.index,\n result.batchError,\n processedMessage,\n batchDurationMs,\n );\n } else {\n await recordSuccess(\n entry.message,\n entry.index,\n result,\n processedMessage,\n batchDurationMs,\n );\n }\n }\n } catch (error) {\n const processed = await Promise.all(\n chunk.map(({ message }) => this.processMessage(message)),\n );\n for (let i = 0; i < chunk.length; i++) {\n if (halted) {\n break;\n }\n const entry = chunk[i] as { index: number; message: MailOptions };\n await recordFailure(entry.message, entry.index, error, processed[i]);\n }\n }\n }\n }\n\n if (singleEntries.length > 0 && !halted) {\n const concurrency = options?.concurrency ?? 1;\n const queue = [...singleEntries];\n let active = 0;\n\n await new Promise<void>((resolve) => {\n const maybeDone = (): void => {\n if ((queue.length === 0 && active === 0) || halted) {\n resolve();\n }\n };\n\n const processNext = (): void => {\n if (queue.length === 0 || halted) {\n maybeDone();\n return;\n }\n\n const entry = queue.shift();\n if (entry === undefined) {\n maybeDone();\n return;\n }\n\n active++;\n void this.send(entry.message)\n .then((result) => {\n results[entry.index] = { status: \"sent\", result };\n options?.onSuccess?.(entry.message, entry.index, result);\n })\n .catch((error: unknown) => {\n results[entry.index] = { status: \"failed\", error };\n options?.onError?.(entry.message, entry.index, error);\n if (stopOnError) {\n halted = true;\n }\n })\n .finally(() => {\n active--;\n processNext();\n maybeDone();\n });\n };\n\n for (let i = 0; i < concurrency; i++) {\n processNext();\n }\n });\n }\n } else {\n const concurrency = options?.concurrency ?? 1;\n const queue = [...messages.entries()];\n let active = 0;\n\n await new Promise<void>((resolve) => {\n const maybeDone = (): void => {\n if ((queue.length === 0 && active === 0) || halted) {\n resolve();\n }\n };\n\n const processNext = (): void => {\n if (queue.length === 0 || halted) {\n maybeDone();\n return;\n }\n\n const entry = queue.shift();\n if (entry === undefined) {\n maybeDone();\n return;\n }\n\n const [index, message] = entry;\n active++;\n\n void this.send(message)\n .then((result) => {\n results[index] = { status: \"sent\", result };\n options?.onSuccess?.(message, index, result);\n })\n .catch((error: unknown) => {\n results[index] = { status: \"failed\", error };\n options?.onError?.(message, index, error);\n if (stopOnError) {\n halted = true;\n }\n })\n .finally(() => {\n active--;\n processNext();\n maybeDone();\n });\n };\n\n for (let i = 0; i < concurrency; i++) {\n processNext();\n }\n });\n }\n\n let sent = 0;\n let failed = 0;\n for (const result of results) {\n if (result === undefined) {\n continue;\n }\n if (result.status === \"sent\") {\n sent++;\n } else {\n failed++;\n }\n }\n\n return {\n total: messages.length,\n sent,\n failed,\n results,\n };\n }\n\n verify(): Promise<VerifyResult> {\n if (this.transport.verify) {\n return this.transport.verify();\n }\n return Promise.resolve({ ok: true, provider: \"mailer\" });\n }\n\n close(): Promise<void> {\n if (this.transport.close) {\n return this.transport.close();\n }\n return Promise.resolve();\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "04FD0B7C27E59A4C64756E2164756E21",
9
+ "names": []
10
+ }
@@ -1,5 +1,5 @@
1
- import{P as v,Q as j,R as D,S as T,T as y}from"./chunk-93vqxxj2.js";import{Y as F,_ as M,ba as P}from"./chunk-ywq6s10g.js";import{fa as b}from"./chunk-6npp3x3c.js";function N(q){return q.replace(/\r\n?|\n/g," ").trim()}function w(q){if(v(q.address,"address"),q.name!==void 0)v(q.name,"display name");let O=q.address.trim();if(!y(O))throw Error(`Invalid email address: ${JSON.stringify(q.address)}`);let G={address:O};if(q.name)G.name=N(q.name);return G}var Q=`\r
1
+ import{R as v,S as j,T as D,U as T,V as y}from"./chunk-8kpgbrba.js";import{da as F,fa as M,ia as P}from"./chunk-hnzmn4s4.js";import{ma as b}from"./chunk-th4cwrpb.js";function N(q){return q.replace(/\r\n?|\n/g," ").trim()}function w(q){if(v(q.address,"address"),q.name!==void 0)v(q.name,"display name");let O=q.address.trim();if(!y(O))throw Error(`Invalid email address: ${JSON.stringify(q.address)}`);let G={address:O};if(q.name)G.name=N(q.name);return G}var Q=`\r
2
2
  `;async function c(q,O){let G=q.messageId??f(),X=(q.date??new Date).toUTCString(),Y=j(q.from),Z=j(q.to),K=q.cc?j(q.cc):[];if(Y.length===0)throw Error("Missing from address");if(Z.length===0)throw Error("Missing to address");let H={from:Y[0]?.address??"",to:[...T(q.to),...q.cc?T(q.cc):[],...q.bcc?T(q.bcc):[]]},E=q.attachments??[],V=E.filter((J)=>J.inline||J.contentId),I=E.filter((J)=>!J.inline&&!J.contentId),W=k(q);if(V.length>0){let J=S();W={contentType:`multipart/related; boundary="${J}"`,content:x(J,[L(k(q)),...V.map(R)])}}if(I.length>0){let J=S();W={contentType:`multipart/mixed; boundary="${J}"`,content:x(J,[L(W),...I.map(R)])}}let _=[$("From",Y.map((J)=>D(w(J))).join(", ")),$("To",Z.map((J)=>D(w(J))).join(", "))];if(K.length>0)_.push($("Cc",K.map((J)=>D(w(J))).join(", ")));if(q.replyTo)_.push($("Reply-To",j(q.replyTo).map((J)=>D(w(J))).join(", ")));if(_.push($("Subject",M(N(q.subject))),$("Date",X),$("Message-ID",G),"MIME-Version: 1.0"),q.priority==="high")_.push("X-Priority: 1","Importance: high");else if(q.priority==="low")_.push("X-Priority: 5","Importance: low");if(q.headers)for(let[J,B]of Object.entries(q.headers))_.push($(N(J),N(B)));if(_.push(`Content-Type: ${W.contentType}`),W.contentTransferEncoding)_.push(`Content-Transfer-Encoding: ${W.contentTransferEncoding}`);let z=`${_.join(Q)}${Q}${Q}${W.content}`,U=P(z);if(O){let{signDKIM:J}=await import("./dkim.js"),{header:B}=await J(U,O),g=`${B}${Q}${z}`;U=P(g)}return{raw:U,envelope:H,messageId:G,size:U.length}}function k(q){let O=Boolean(q.text),G=Boolean(q.html);if(O&&G){let X=S();return{contentType:`multipart/alternative; boundary="${X}"`,content:x(X,[C({contentType:"text/plain; charset=utf-8",contentTransferEncoding:"8bit",content:q.text??""}),C({contentType:"text/html; charset=utf-8",contentTransferEncoding:"8bit",content:q.html??""})])}}if(G)return{contentType:"text/html; charset=utf-8",contentTransferEncoding:"8bit",content:q.html??""};return{contentType:"text/plain; charset=utf-8",contentTransferEncoding:"8bit",content:q.text??""}}function C(q){let O=[`Content-Type: ${q.contentType}`];if(q.contentTransferEncoding)O.push(`Content-Transfer-Encoding: ${q.contentTransferEncoding}`);return`${O.join(Q)}${Q}${Q}${q.content}`}function L(q){let O=[`Content-Type: ${q.contentType}`];if(q.contentTransferEncoding)O.push(`Content-Transfer-Encoding: ${q.contentTransferEncoding}`);return`${O.join(Q)}${Q}${Q}${q.content}`}function R(q){if(!q.content||typeof q.content==="string")throw Error(`Attachment "${q.filename}" requires Uint8Array content`);let O=N(q.filename??""),G=[`Content-Type: ${q.contentType??"application/octet-stream"}`,"Content-Transfer-Encoding: base64",`Content-Disposition: ${q.inline?"inline":"attachment"}; filename="${O}"`];if(q.contentId)G.push(`Content-ID: <${q.contentId}>`);if(q.headers)for(let[X,Y]of Object.entries(q.headers)){let Z=N(X),K=N(Y);G.push(`${Z}: ${K}`)}return`${G.join(Q)}${Q}${Q}${F(q.content)}`}function x(q,O){let G=O.map((X)=>`--${q}${Q}${X}`);return G.push(`--${q}--`),G.join(Q)}function f(){let q=crypto.getRandomValues(new Uint8Array(8)),O=Array.from(q,(G)=>G.toString(16).padStart(2,"0")).join("");return`<${Date.now()}.${O}@sently>`}function S(){let q=crypto.getRandomValues(new Uint8Array(12));return`----sently_${Array.from(q,(G)=>G.toString(16).padStart(2,"0")).join("")}`}function $(q,O){let G=`${q}: ${O}`;if(G.length<=76)return G;let X=[],Y=G;while(Y.length>76){let Z=Y.lastIndexOf(" ",76);if(Z<=q.length+1)Z=76;X.push(Y.slice(0,Z)),Y=` ${Y.slice(Z).trimStart()}`}return X.push(Y),X.join(`${Q} `)}
3
- export{c as u};
3
+ export{c as w};
4
4
 
5
- //# debugId=9145766DA8E5C19764756E2164756E21
5
+ //# debugId=88ABACC6FFC0A9F464756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "// src/core/mime.ts\nimport {\n assertSafeAddress,\n extractEmails,\n isValidEmail,\n parseAddresses,\n toMIMEHeader,\n} from \"./address.js\";\nimport { encodeBase64, encodeHeader, encodeUtf8 } from \"./base64.js\";\nimport type { Address, Attachment, DKIMConfig, Envelope, MailOptions } from \"./types.js\";\n\nfunction sanitizeHeaderValue(value: string): string {\n return value.replace(/\\r\\n?|\\n/g, \" \").trim();\n}\n\nfunction sanitizeAddress(addr: Address): Address {\n // Security check runs on the raw value FIRST and fails closed: any control\n // character (CR/LF/NUL/…) is rejected outright rather than stripped and\n // accepted. parseAddresses() already enforces this upstream; re-asserting\n // here keeps the function safe if it is ever called directly.\n assertSafeAddress(addr.address, \"address\");\n if (addr.name !== undefined) {\n assertSafeAddress(addr.name, \"display name\");\n }\n\n // Only ordinary surrounding whitespace is trimmed — the address identity is\n // never altered (no CR/LF-to-space repair).\n const address = addr.address.trim();\n if (!isValidEmail(address)) {\n throw new Error(`Invalid email address: ${JSON.stringify(addr.address)}`);\n }\n\n const sanitized: Address = { address };\n if (addr.name) {\n sanitized.name = sanitizeHeaderValue(addr.name);\n }\n return sanitized;\n}\n\n/** Result of building a complete MIME message. */\nexport interface MIMEBuildResult {\n /** Complete raw MIME message bytes ready to send. */\n raw: Uint8Array;\n /** SMTP envelope derived from From/To/Cc/Bcc. */\n envelope: Envelope;\n /** Message-ID assigned or supplied for the message. */\n messageId: string;\n /** Size of the raw MIME message in bytes. */\n size: number;\n}\n\nconst CRLF = \"\\r\\n\";\n\n/**\n * Build a complete MIME message as a Uint8Array ready for SMTP DATA.\n * When `dkim` is provided, signs the message and prepends the DKIM-Signature header.\n */\nexport async function buildMIME(options: MailOptions, dkim?: DKIMConfig): Promise<MIMEBuildResult> {\n const messageId = options.messageId ?? generateMessageId();\n const date = (options.date ?? new Date()).toUTCString();\n const fromAddrs = parseAddresses(options.from);\n const toAddrs = parseAddresses(options.to);\n const ccAddrs = options.cc ? parseAddresses(options.cc) : [];\n\n if (fromAddrs.length === 0) {\n throw new Error(\"Missing from address\");\n }\n if (toAddrs.length === 0) {\n throw new Error(\"Missing to address\");\n }\n\n const envelope: Envelope = {\n from: fromAddrs[0]?.address ?? \"\",\n to: [\n ...extractEmails(options.to),\n ...(options.cc ? extractEmails(options.cc) : []),\n ...(options.bcc ? extractEmails(options.bcc) : []),\n ],\n };\n\n const attachments = options.attachments ?? [];\n const inlineAttachments = attachments.filter((a) => a.inline || a.contentId);\n const regularAttachments = attachments.filter((a) => !a.inline && !a.contentId);\n\n let root = buildSimpleBody(options);\n\n if (inlineAttachments.length > 0) {\n const boundary = generateBoundary();\n root = {\n contentType: `multipart/related; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatNestedPart(buildSimpleBody(options)),\n ...inlineAttachments.map(formatAttachmentPart),\n ]),\n };\n }\n\n if (regularAttachments.length > 0) {\n const boundary = generateBoundary();\n root = {\n contentType: `multipart/mixed; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatNestedPart(root),\n ...regularAttachments.map(formatAttachmentPart),\n ]),\n };\n }\n\n const headers: string[] = [\n foldHeader(\"From\", fromAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")),\n foldHeader(\"To\", toAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")),\n ];\n\n if (ccAddrs.length > 0) {\n headers.push(foldHeader(\"Cc\", ccAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")));\n }\n\n if (options.replyTo) {\n headers.push(\n foldHeader(\n \"Reply-To\",\n parseAddresses(options.replyTo)\n .map((a) => toMIMEHeader(sanitizeAddress(a)))\n .join(\", \"),\n ),\n );\n }\n\n headers.push(\n foldHeader(\"Subject\", encodeHeader(sanitizeHeaderValue(options.subject))),\n foldHeader(\"Date\", date),\n foldHeader(\"Message-ID\", messageId),\n \"MIME-Version: 1.0\",\n );\n\n if (options.priority === \"high\") {\n headers.push(\"X-Priority: 1\", \"Importance: high\");\n } else if (options.priority === \"low\") {\n headers.push(\"X-Priority: 5\", \"Importance: low\");\n }\n\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.push(foldHeader(sanitizeHeaderValue(key), sanitizeHeaderValue(value)));\n }\n }\n\n headers.push(`Content-Type: ${root.contentType}`);\n if (root.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${root.contentTransferEncoding}`);\n }\n\n const rawText = `${headers.join(CRLF)}${CRLF}${CRLF}${root.content}`;\n let raw = encodeUtf8(rawText);\n\n if (dkim) {\n const { signDKIM } = await import(\"../dkim.js\");\n const { header } = await signDKIM(raw, dkim);\n const signedText = `${header}${CRLF}${rawText}`;\n raw = encodeUtf8(signedText);\n }\n\n return { raw, envelope, messageId, size: raw.length };\n}\n\ninterface SimpleBody {\n contentType: string;\n contentTransferEncoding?: string;\n content: string;\n}\n\nfunction buildSimpleBody(options: MailOptions): SimpleBody {\n const hasText = Boolean(options.text);\n const hasHtml = Boolean(options.html);\n\n if (hasText && hasHtml) {\n const boundary = generateBoundary();\n return {\n contentType: `multipart/alternative; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatSimplePart({\n contentType: \"text/plain; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.text ?? \"\",\n }),\n formatSimplePart({\n contentType: \"text/html; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.html ?? \"\",\n }),\n ]),\n };\n }\n\n if (hasHtml) {\n return {\n contentType: \"text/html; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.html ?? \"\",\n };\n }\n\n return {\n contentType: \"text/plain; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.text ?? \"\",\n };\n}\n\nfunction formatSimplePart(part: SimpleBody): string {\n const headers = [`Content-Type: ${part.contentType}`];\n if (part.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${part.contentTransferEncoding}`);\n }\n return `${headers.join(CRLF)}${CRLF}${CRLF}${part.content}`;\n}\n\nfunction formatNestedPart(part: SimpleBody): string {\n const headers = [`Content-Type: ${part.contentType}`];\n if (part.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${part.contentTransferEncoding}`);\n }\n return `${headers.join(CRLF)}${CRLF}${CRLF}${part.content}`;\n}\n\nfunction formatAttachmentPart(attachment: Attachment): string {\n if (!attachment.content || typeof attachment.content === \"string\") {\n throw new Error(`Attachment \"${attachment.filename}\" requires Uint8Array content`);\n }\n\n const safeFilename = sanitizeHeaderValue(attachment.filename ?? \"\");\n const headers = [\n `Content-Type: ${attachment.contentType ?? \"application/octet-stream\"}`,\n \"Content-Transfer-Encoding: base64\",\n `Content-Disposition: ${attachment.inline ? \"inline\" : \"attachment\"}; filename=\"${safeFilename}\"`,\n ];\n\n if (attachment.contentId) {\n headers.push(`Content-ID: <${attachment.contentId}>`);\n }\n\n if (attachment.headers) {\n for (const [key, value] of Object.entries(attachment.headers)) {\n const safeKey = sanitizeHeaderValue(key);\n const safeValue = sanitizeHeaderValue(value);\n headers.push(`${safeKey}: ${safeValue}`);\n }\n }\n\n return `${headers.join(CRLF)}${CRLF}${CRLF}${encodeBase64(attachment.content)}`;\n}\n\nfunction assembleMultipart(boundary: string, parts: string[]): string {\n const segments = parts.map((part) => `--${boundary}${CRLF}${part}`);\n segments.push(`--${boundary}--`);\n return segments.join(CRLF);\n}\n\nfunction generateMessageId(): string {\n const random = crypto.getRandomValues(new Uint8Array(8));\n const hex = Array.from(random, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `<${Date.now()}.${hex}@sently>`;\n}\n\nfunction generateBoundary(): string {\n const random = crypto.getRandomValues(new Uint8Array(12));\n const hex = Array.from(random, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `----sently_${hex}`;\n}\n\nfunction foldHeader(name: string, value: string): string {\n const line = `${name}: ${value}`;\n if (line.length <= 76) {\n return line;\n }\n\n const chunks: string[] = [];\n let remaining = line;\n\n while (remaining.length > 76) {\n let breakAt = remaining.lastIndexOf(\" \", 76);\n if (breakAt <= name.length + 1) {\n breakAt = 76;\n }\n chunks.push(remaining.slice(0, breakAt));\n remaining = ` ${remaining.slice(breakAt).trimStart()}`;\n }\n chunks.push(remaining);\n\n return chunks.join(`${CRLF} `);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "9145766DA8E5C19764756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "88ABACC6FFC0A9F464756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,4 @@
1
+ function z(x){return"token"in x&&typeof x.token==="string"}function B(x){return"subscription"in x&&typeof x.subscription?.endpoint==="string"}
2
+ export{z as Z,B as _};
3
+
4
+ //# debugId=F4A2DC6CC43BC46D64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/push-types.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @module\n * Shared push channel contracts — sibling types to email MailOptions/Transport/Hooks.\n *\n * Sently-first: this contract is the stable push surface. Provider transports\n * implement {@link PushTransport}. Web Push uses a browser subscription; FCM\n * uses a device registration token.\n */\nimport type { VerifyResult } from \"./types.js\";\n\n/** Browser push subscription as returned by the Push API. */\nexport interface PushSubscription {\n /** Push service endpoint URL. */\n endpoint: string;\n /** Client encryption keys for RFC 8291 payload encryption. */\n keys: {\n /** Base64url-encoded P-256 ECDH public key. */\n p256dh: string;\n /** Base64url-encoded authentication secret. */\n auth: string;\n };\n}\n\n/** Shared notification fields for Web Push and FCM. */\ninterface PushNotificationFields {\n /** Notification title. */\n title: string;\n /** Notification body text. */\n body: string;\n /** Arbitrary application data attached to the notification. */\n data?: Record<string, unknown>;\n /** Notification icon URL (Web Push / some FCM platforms). */\n icon?: string;\n /** Time-to-live in seconds for the push message. */\n ttl?: number;\n /** Client-supplied message identifier when known. */\n messageId?: string;\n}\n\n/** Options for sending a Web Push notification (VAPID / browser subscription). */\nexport interface WebPushOptions extends PushNotificationFields {\n /** Target browser push subscription. */\n subscription: PushSubscription;\n}\n\n/**\n * Options for sending via Firebase Cloud Messaging HTTP v1 (device token).\n * Data values are stringified by the FCM transport when needed.\n */\nexport interface FcmPushOptions extends PushNotificationFields {\n /** FCM registration token for the target device. */\n token: string;\n /** Optional image URL for the notification. */\n image?: string;\n}\n\n/** Options for sending a push notification (Web Push or FCM). */\nexport type PushOptions = WebPushOptions | FcmPushOptions;\n\n/** True when options target FCM (device token) rather than Web Push. */\nexport function isFcmPushOptions(options: PushOptions): options is FcmPushOptions {\n return \"token\" in options && typeof (options as FcmPushOptions).token === \"string\";\n}\n\n/** True when options target Web Push (browser subscription). */\nexport function isWebPushOptions(options: PushOptions): options is WebPushOptions {\n return (\n \"subscription\" in options &&\n typeof (options as WebPushOptions).subscription?.endpoint === \"string\"\n );\n}\n\n/** Result returned after a push notification is accepted by the push service. */\nexport interface PushSendResult {\n /** Client-generated or assigned message identifier. */\n messageId: string;\n /** Delivery status string (e.g. `\"accepted\"`). */\n status: string;\n /** Human-readable or raw status text (often the HTTP status). */\n response: string;\n /** Transport or provider identifier (e.g. `\"webpush\"`, `\"fcm\"`). */\n provider?: string;\n /**\n * Zero-based index of the transport that handled the send in a fallback chain.\n * Set by {@link FallbackTransport}.\n */\n providerIndex?: number;\n}\n\n/** Pluggable push delivery backend (Web Push, FCM, …). */\nexport interface PushTransport {\n /**\n * Stable provider identifier for observability (e.g. `\"webpush\"`, `\"fcm\"`).\n * Prefer this over constructor-name inference in hooks.\n */\n readonly provider?: string;\n /** Send a push notification through this transport. */\n send(options: PushOptions): Promise<PushSendResult>;\n /** Test connectivity and credentials without sending. */\n verify?(): Promise<VerifyResult>;\n /** Release resources held by the transport. */\n close?(): Promise<void>;\n}\n\n/**\n * Context passed to push lifecycle hooks.\n * Uses a redacted subscription endpoint or device-token fingerprint (no natural `to`).\n */\nexport interface PushHookContext {\n /** Message-ID when known (from options or send result). */\n messageId?: string;\n /**\n * Redacted push target for observability: `origin/#<short-hash>` (Web Push)\n * or `fcm:#<short-hash>` (FCM device token).\n * Never the full endpoint URL or raw device token.\n */\n endpoint: string;\n /** Transport or provider identifier (e.g. `\"webpush\"`, `\"fcm\"`). */\n provider: string;\n}\n\n/** Optional lifecycle hooks for metrics, tracing, and observability on every push send. */\nexport interface PushHooks {\n /** Fired before the transport sends the notification. */\n onSend?: (ctx: PushHookContext) => void | Promise<void>;\n /**\n * Fired after a successful send.\n * @param durationMs — elapsed milliseconds from send start to success (optional third argument).\n */\n onSuccess?: (\n ctx: PushHookContext,\n result: PushSendResult,\n durationMs?: number,\n ) => void | Promise<void>;\n /**\n * Fired when a send throws (error is re-thrown after the hook runs).\n * @param durationMs — elapsed milliseconds from send start to failure (optional third argument).\n */\n onError?: (ctx: PushHookContext, error: unknown, durationMs?: number) => void | Promise<void>;\n /** Fired before each retry attempt (requires {@link RetryTransport}). */\n onRetry?: (ctx: PushHookContext, attempt: number, error: unknown) => void | Promise<void>;\n /**\n * Fired when {@link FallbackTransport} fails over to the next provider.\n * Requires a fallback (or weighted fallback) transport in the push stack.\n */\n onFallback?: (\n ctx: PushHookContext,\n failedProvider: string,\n nextProvider: string,\n error: unknown,\n ) => void | Promise<void>;\n}\n\n/**\n * A push plugin transforms {@link PushOptions} before the transport sends.\n * Plugins run sequentially. Each receives the output of the previous.\n * Return a new options object — do not mutate the input.\n */\nexport type PushPlugin =\n | ((options: PushOptions) => PushOptions)\n | ((options: PushOptions) => Promise<PushOptions>);\n"
6
+ ],
7
+ "mappings": "AA4DO,SAAS,CAAgB,CAAC,EAAiD,CAChF,MAAO,UAAW,GAAW,OAAQ,EAA2B,QAAU,SAIrE,SAAS,CAAgB,CAAC,EAAiD,CAChF,MACE,iBAAkB,GAClB,OAAQ,EAA2B,cAAc,WAAa",
8
+ "debugId": "F4A2DC6CC43BC46D64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @module
3
+ * Cross-channel send-result mapping — normalize email / SMS / WhatsApp / push
4
+ * results into a shared `{ messageId, provider, accepted }` shape for adapters.
5
+ */
6
+ import type { PushSendResult } from "./push-types.js";
7
+ import type { SmsSendResult } from "./sms-types.js";
8
+ import type { SendResult } from "./types.js";
9
+ import type { WhatsAppSendResult } from "./whatsapp-types.js";
10
+ /**
11
+ * Stable send outcome shared across email, SMS, WhatsApp, and push.
12
+ * Prefer this in multi-channel adapter layers; channel-specific fields stay on
13
+ * the original result types.
14
+ */
15
+ export interface ChannelSendResult {
16
+ /** Provider-assigned or client message identifier. */
17
+ messageId: string;
18
+ /** Transport or provider identifier when known. */
19
+ provider?: string;
20
+ /**
21
+ * Whether the provider accepted the message for delivery.
22
+ * Does not guarantee end-user delivery (use webhooks for that).
23
+ */
24
+ accepted: boolean;
25
+ }
26
+ /** Any channel send result that {@link toChannelSendResult} can normalize. */
27
+ export type AnySendResult = SendResult | SmsSendResult | WhatsAppSendResult | PushSendResult;
28
+ /**
29
+ * Map a channel-specific send result to {@link ChannelSendResult}.
30
+ *
31
+ * | Channel result | `accepted` mapping |
32
+ * | --- | --- |
33
+ * | Email {@link SendResult} | `accepted.length > 0` and `rejected.length === 0` |
34
+ * | SMS / WhatsApp / Push | `status` in accepted set (case-insensitive), else `false` |
35
+ */
36
+ export declare function toChannelSendResult(result: AnySendResult): ChannelSendResult;
@@ -0,0 +1,3 @@
1
+ import"../chunk-th4cwrpb.js";var x=new Set(["accepted","queued","sending","sent","delivered","read","success"]);function B(b){if(y(b)){let w={messageId:b.messageId,accepted:b.accepted.length>0&&b.rejected.length===0};if(b.provider!==void 0)w.provider=b.provider;return w}let q={messageId:b.messageId,accepted:z(b.status)};if(b.provider!==void 0)q.provider=b.provider;return q}function y(b){return Array.isArray(b.accepted)&&Array.isArray(b.rejected)}function z(b){return x.has(b.trim().toLowerCase())}export{B as toChannelSendResult};
2
+
3
+ //# debugId=D355389C6F39068164756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/channel-result.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @module\n * Cross-channel send-result mapping — normalize email / SMS / WhatsApp / push\n * results into a shared `{ messageId, provider, accepted }` shape for adapters.\n */\nimport type { PushSendResult } from \"./push-types.js\";\nimport type { SmsSendResult } from \"./sms-types.js\";\nimport type { SendResult } from \"./types.js\";\nimport type { WhatsAppSendResult } from \"./whatsapp-types.js\";\n\n/**\n * Stable send outcome shared across email, SMS, WhatsApp, and push.\n * Prefer this in multi-channel adapter layers; channel-specific fields stay on\n * the original result types.\n */\nexport interface ChannelSendResult {\n /** Provider-assigned or client message identifier. */\n messageId: string;\n /** Transport or provider identifier when known. */\n provider?: string;\n /**\n * Whether the provider accepted the message for delivery.\n * Does not guarantee end-user delivery (use webhooks for that).\n */\n accepted: boolean;\n}\n\n/** Any channel send result that {@link toChannelSendResult} can normalize. */\nexport type AnySendResult = SendResult | SmsSendResult | WhatsAppSendResult | PushSendResult;\n\n/**\n * Status strings treated as provider-accepted for SMS / WhatsApp / push.\n * Twilio often returns `\"queued\"`; Unifonic may return `\"Sent\"`.\n */\nconst ACCEPTED_STATUSES = new Set([\n \"accepted\",\n \"queued\",\n \"sending\",\n \"sent\",\n \"delivered\",\n \"read\",\n \"success\",\n]);\n\n/**\n * Map a channel-specific send result to {@link ChannelSendResult}.\n *\n * | Channel result | `accepted` mapping |\n * | --- | --- |\n * | Email {@link SendResult} | `accepted.length > 0` and `rejected.length === 0` |\n * | SMS / WhatsApp / Push | `status` in accepted set (case-insensitive), else `false` |\n */\nexport function toChannelSendResult(result: AnySendResult): ChannelSendResult {\n if (isEmailSendResult(result)) {\n const out: ChannelSendResult = {\n messageId: result.messageId,\n accepted: result.accepted.length > 0 && result.rejected.length === 0,\n };\n if (result.provider !== undefined) {\n out.provider = result.provider;\n }\n return out;\n }\n\n const out: ChannelSendResult = {\n messageId: result.messageId,\n accepted: isAcceptedStatus(result.status),\n };\n if (result.provider !== undefined) {\n out.provider = result.provider;\n }\n return out;\n}\n\nfunction isEmailSendResult(result: AnySendResult): result is SendResult {\n return (\n Array.isArray((result as SendResult).accepted) && Array.isArray((result as SendResult).rejected)\n );\n}\n\nfunction isAcceptedStatus(status: string): boolean {\n return ACCEPTED_STATUSES.has(status.trim().toLowerCase());\n}\n"
6
+ ],
7
+ "mappings": "6BAkCA,IAAM,EAAoB,IAAI,IAAI,CAChC,WACA,SACA,UACA,OACA,YACA,OACA,SACF,CAAC,EAUM,SAAS,CAAmB,CAAC,EAA0C,CAC5E,GAAI,EAAkB,CAAM,EAAG,CAC7B,IAAM,EAAyB,CAC7B,UAAW,EAAO,UAClB,SAAU,EAAO,SAAS,OAAS,GAAK,EAAO,SAAS,SAAW,CACrE,EACA,GAAI,EAAO,WAAa,OACtB,EAAI,SAAW,EAAO,SAExB,OAAO,EAGT,IAAM,EAAyB,CAC7B,UAAW,EAAO,UAClB,SAAU,EAAiB,EAAO,MAAM,CAC1C,EACA,GAAI,EAAO,WAAa,OACtB,EAAI,SAAW,EAAO,SAExB,OAAO,EAGT,SAAS,CAAiB,CAAC,EAA6C,CACtE,OACE,MAAM,QAAS,EAAsB,QAAQ,GAAK,MAAM,QAAS,EAAsB,QAAQ,EAInG,SAAS,CAAgB,CAAC,EAAyB,CACjD,OAAO,EAAkB,IAAI,EAAO,KAAK,EAAE,YAAY,CAAC",
8
+ "debugId": "D355389C6F39068164756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module
3
+ * Minimal transport surface for cross-channel retry / fallback decorators.
4
+ */
5
+ import type { VerifyResult } from "./types.js";
6
+ /**
7
+ * Structural transport contract used by {@link RetryTransport},
8
+ * {@link FallbackTransport}, and {@link WeightedFallbackTransport}.
9
+ * Compatible with email {@link Transport}, {@link SmsTransport},
10
+ * {@link WhatsAppTransport}, and {@link PushTransport}.
11
+ */
12
+ export interface DecoratedTransport<TOptions, TResult> {
13
+ /** Stable provider identifier for observability when set. */
14
+ readonly provider?: string;
15
+ /** Send through this transport. */
16
+ send(options: TOptions): Promise<TResult>;
17
+ /** Optional connectivity check. */
18
+ verify?(): Promise<VerifyResult>;
19
+ /** Optional resource cleanup. */
20
+ close?(): Promise<void>;
21
+ /** Optional batch send (email transports). */
22
+ sendBatch?(messages: TOptions[]): Promise<TResult[]>;
23
+ }
24
+ /**
25
+ * Result fields added by fallback decorators when a chain member succeeds.
26
+ */
27
+ export type FallbackAugmentedResult<TResult> = TResult & {
28
+ provider: string;
29
+ providerIndex: number;
30
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @module
3
+ * Duck-typed wiring for RetryTransport / FallbackTransport sender hooks.
4
+ * Kept separate so channel senders do not import the decorator modules.
5
+ */
6
+ /** Transport that accepts per-send retry callbacks. */
7
+ export interface RetryHookTransport {
8
+ setMailerOnRetry(callback: ((attempt: number, error: unknown) => void) | undefined): void;
9
+ }
10
+ /** Transport that accepts per-send fallback callbacks. */
11
+ export interface FallbackHookTransport {
12
+ setMailerOnFallback(callback: ((failedProvider: string, nextProvider: string, error: unknown) => void) | undefined): void;
13
+ }
14
+ /** True when the transport exposes {@link RetryHookTransport.setMailerOnRetry}. */
15
+ export declare function isRetryHookTransport(transport: unknown): transport is RetryHookTransport;
16
+ /** True when the transport exposes {@link FallbackHookTransport.setMailerOnFallback}. */
17
+ export declare function isFallbackHookTransport(transport: unknown): transport is FallbackHookTransport;
@@ -1,3 +1,3 @@
1
- import{ca as a,da as b,ea as c}from"../chunk-tamww15j.js";import"../chunk-6npp3x3c.js";export{c as smtpCodeToSentlyCode,b as httpStatusToSentlyCode,a as SentlyError};
1
+ import{ja as a,ka as b,la as c}from"../chunk-ttbwyxmh.js";import"../chunk-th4cwrpb.js";export{c as smtpCodeToSentlyCode,b as httpStatusToSentlyCode,a as SentlyError};
2
2
 
3
- //# debugId=8BB8C05CE319F39464756E2164756E21
3
+ //# debugId=977FBDF71FF6E17564756E2164756E21