sently 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -0
- package/CHANGELOG.md +82 -41
- package/README.md +89 -960
- package/dist/adapters/bun.js +1 -1
- package/dist/adapters/cf.js +2 -2
- package/dist/adapters/cf.js.map +2 -2
- package/dist/adapters/deno.js +1 -1
- package/dist/adapters/node.js +1 -1
- package/dist/auth/oauth2.js +2 -2
- package/dist/auth/oauth2.js.map +1 -1
- package/dist/chunk-0gqy32pe.js +4 -0
- package/dist/{chunk-n5dan5bz.js.map → chunk-0gqy32pe.js.map} +2 -2
- package/dist/{chunk-z62q7kqr.js → chunk-0qxws3kj.js} +2 -2
- package/dist/{chunk-z62q7kqr.js.map → chunk-0qxws3kj.js.map} +1 -1
- package/dist/chunk-29z7fkzy.js +4 -0
- package/dist/{chunk-wsymfbkn.js.map → chunk-29z7fkzy.js.map} +2 -2
- package/dist/chunk-5915vbcj.js +4 -0
- package/dist/chunk-5915vbcj.js.map +10 -0
- package/dist/{chunk-nbmq8ejv.js → chunk-6npp3x3c.js} +2 -2
- package/dist/{chunk-nbmq8ejv.js.map → chunk-6npp3x3c.js.map} +1 -1
- package/dist/chunk-7gy2q9sh.js +4 -0
- package/dist/chunk-7gy2q9sh.js.map +10 -0
- package/dist/{chunk-zst8an2p.js → chunk-8dty8c4p.js} +2 -2
- package/dist/{chunk-zst8an2p.js.map → chunk-8dty8c4p.js.map} +2 -2
- package/dist/{chunk-f3dz43cy.js → chunk-8njyga62.js} +2 -2
- package/dist/{chunk-f3dz43cy.js.map → chunk-8njyga62.js.map} +1 -1
- package/dist/chunk-93vqxxj2.js +4 -0
- package/dist/{chunk-qh90yr6d.js.map → chunk-93vqxxj2.js.map} +2 -2
- package/dist/chunk-b602dhck.js +4 -0
- package/dist/{chunk-wbvhaqcp.js.map → chunk-b602dhck.js.map} +2 -2
- package/dist/{chunk-9zkv5azm.js → chunk-gp4fwrs8.js} +2 -2
- package/dist/{chunk-9zkv5azm.js.map → chunk-gp4fwrs8.js.map} +1 -1
- package/dist/chunk-n0qeyzqm.js +13 -0
- package/dist/{chunk-8phpsns1.js.map → chunk-n0qeyzqm.js.map} +2 -2
- package/dist/chunk-qtkd5bak.js +4 -0
- package/dist/chunk-qtkd5bak.js.map +11 -0
- package/dist/chunk-skqhj0rm.js +4 -0
- package/dist/{chunk-vhxzhx8b.js.map → chunk-skqhj0rm.js.map} +2 -2
- package/dist/{chunk-6bkj4y4r.js → chunk-tamww15j.js} +2 -2
- package/dist/{chunk-6bkj4y4r.js.map → chunk-tamww15j.js.map} +1 -1
- package/dist/chunk-vjpds2pf.js +3 -0
- package/dist/{chunk-m07smapm.js.map → chunk-vjpds2pf.js.map} +2 -2
- package/dist/chunk-yp311efr.js +4 -0
- package/dist/chunk-yp311efr.js.map +10 -0
- package/dist/chunk-ywq6s10g.js +5 -0
- package/dist/{chunk-5scdgffb.js.map → chunk-ywq6s10g.js.map} +3 -3
- package/dist/core/base64.d.ts +10 -0
- package/dist/core/errors.js +2 -2
- package/dist/core/errors.js.map +1 -1
- package/dist/core/hooks.d.ts +14 -0
- package/dist/core/plugin.d.ts +7 -7
- package/dist/core/push-endpoint.d.ts +29 -0
- package/dist/core/push-types.d.ts +98 -0
- package/dist/core/sms-types.d.ts +76 -0
- package/dist/core/smtp.js +2 -2
- package/dist/core/smtp.js.map +1 -1
- package/dist/core/whatsapp-types.d.ts +116 -0
- package/dist/detect.js +2 -2
- package/dist/detect.js.map +1 -1
- package/dist/dkim.js +2 -2
- package/dist/dkim.js.map +2 -2
- package/dist/idempotency.js +2 -2
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +5 -32
- package/dist/index.js +0 -35
- package/dist/mailer.js +2 -2
- package/dist/mailer.js.map +1 -1
- package/dist/observability/console.js +1 -1
- package/dist/plugins/react.js +2 -2
- package/dist/plugins/react.js.map +2 -2
- package/dist/plugins/template.js +1 -1
- package/dist/pool/pool.js +2 -2
- package/dist/pool/pool.js.map +1 -1
- package/dist/push.d.ts +26 -0
- package/dist/push.js +3 -0
- package/dist/push.js.map +10 -0
- package/dist/sms.d.ts +26 -0
- package/dist/sms.js +3 -0
- package/dist/sms.js.map +10 -0
- package/dist/smtp-mailer.js +2 -2
- package/dist/smtp-mailer.js.map +2 -2
- package/dist/transports/brevo.js +2 -2
- package/dist/transports/brevo.js.map +2 -2
- package/dist/transports/cloudflare-email.js +2 -2
- package/dist/transports/cloudflare-email.js.map +2 -2
- package/dist/transports/fallback.js +2 -2
- package/dist/transports/fallback.js.map +1 -1
- package/dist/transports/loops.js +2 -2
- package/dist/transports/loops.js.map +2 -2
- package/dist/transports/mailersend.js +2 -2
- package/dist/transports/mailersend.js.map +2 -2
- package/dist/transports/mailgun.js +2 -2
- package/dist/transports/mailgun.js.map +2 -2
- package/dist/transports/mailtrap.js +2 -2
- package/dist/transports/mailtrap.js.map +2 -2
- package/dist/transports/msegat.d.ts +132 -0
- package/dist/transports/msegat.js +3 -0
- package/dist/transports/msegat.js.map +10 -0
- package/dist/transports/plunk.js +2 -2
- package/dist/transports/plunk.js.map +2 -2
- package/dist/transports/postmark.js +2 -2
- package/dist/transports/postmark.js.map +2 -2
- package/dist/transports/preview.js +2 -2
- package/dist/transports/preview.js.map +2 -2
- package/dist/transports/resend.js +2 -2
- package/dist/transports/resend.js.map +2 -2
- package/dist/transports/retry.js +2 -2
- package/dist/transports/retry.js.map +2 -2
- package/dist/transports/sendgrid.js +2 -2
- package/dist/transports/sendgrid.js.map +2 -2
- package/dist/transports/ses.js +2 -2
- package/dist/transports/ses.js.map +2 -2
- package/dist/transports/smtp.js +2 -2
- package/dist/transports/smtp.js.map +1 -1
- package/dist/transports/sndr.d.ts +41 -0
- package/dist/transports/sndr.js +3 -0
- package/dist/transports/sndr.js.map +10 -0
- package/dist/transports/sparkpost.js +2 -2
- package/dist/transports/sparkpost.js.map +2 -2
- package/dist/transports/taqnyat-mail.d.ts +33 -0
- package/dist/transports/taqnyat-mail.js +3 -0
- package/dist/transports/taqnyat-mail.js.map +10 -0
- package/dist/transports/taqnyat-phone.d.ts +4 -0
- package/dist/transports/taqnyat-sms.d.ts +131 -0
- package/dist/transports/taqnyat-sms.js +3 -0
- package/dist/transports/taqnyat-sms.js.map +10 -0
- package/dist/transports/taqnyat-whatsapp.d.ts +51 -0
- package/dist/transports/taqnyat-whatsapp.js +3 -0
- package/dist/transports/taqnyat-whatsapp.js.map +10 -0
- package/dist/transports/twilio-sms.d.ts +66 -0
- package/dist/transports/twilio-sms.js +3 -0
- package/dist/transports/twilio-sms.js.map +10 -0
- package/dist/transports/webpush.d.ts +46 -0
- package/dist/transports/webpush.js +3 -0
- package/dist/transports/webpush.js.map +10 -0
- package/dist/transports/weighted-fallback.js +2 -2
- package/dist/transports/weighted-fallback.js.map +1 -1
- package/dist/transports/whatsapp-cloud.d.ts +56 -0
- package/dist/transports/whatsapp-cloud.js +3 -0
- package/dist/transports/whatsapp-cloud.js.map +10 -0
- package/dist/webhooks/brevo.js +1 -1
- package/dist/webhooks/mailgun.js +1 -1
- package/dist/webhooks/postmark.js +1 -1
- package/dist/webhooks/resend.js +1 -1
- package/dist/webhooks/sendgrid.js +1 -1
- package/dist/webhooks/ses.js +1 -1
- package/dist/webhooks/sndr.d.ts +16 -0
- package/dist/webhooks/sndr.js +3 -0
- package/dist/webhooks/sndr.js.map +10 -0
- package/dist/webhooks/timing-safe-equal.js +1 -1
- package/dist/webhooks.d.ts +9 -2
- package/dist/webhooks.js +4 -0
- package/dist/whatsapp.d.ts +26 -0
- package/dist/whatsapp.js +3 -0
- package/dist/whatsapp.js.map +10 -0
- package/package.json +85 -4
- package/site/README.md +26 -0
- package/site/content/docs/ai/index.mdx +13 -0
- package/site/content/docs/ai/llms-txt.mdx +12 -0
- package/site/content/docs/ai/mcp.mdx +16 -0
- package/site/content/docs/ai/meta.json +9 -0
- package/site/content/docs/channels/email.mdx +100 -0
- package/site/content/docs/channels/hooks.mdx +87 -0
- package/site/content/docs/channels/index.mdx +81 -0
- package/site/content/docs/channels/meta.json +12 -0
- package/site/content/docs/channels/push.mdx +92 -0
- package/site/content/docs/channels/sms.mdx +88 -0
- package/site/content/docs/channels/whatsapp.mdx +95 -0
- package/site/content/docs/decorators/fallback.mdx +34 -0
- package/site/content/docs/decorators/idempotency.mdx +34 -0
- package/site/content/docs/decorators/index.mdx +50 -0
- package/site/content/docs/decorators/meta.json +12 -0
- package/site/content/docs/decorators/preview.mdx +34 -0
- package/site/content/docs/decorators/retry.mdx +34 -0
- package/site/content/docs/decorators/weighted-fallback.mdx +34 -0
- package/site/content/docs/get-started/entrypoints.mdx +114 -0
- package/site/content/docs/get-started/index.mdx +14 -0
- package/site/content/docs/get-started/installation.mdx +78 -0
- package/site/content/docs/get-started/introduction.mdx +77 -0
- package/site/content/docs/get-started/meta.json +12 -0
- package/site/content/docs/get-started/migrate-nodemailer.mdx +23 -0
- package/site/content/docs/get-started/runtimes.mdx +17 -0
- package/site/content/docs/guides/adapters.mdx +26 -0
- package/site/content/docs/guides/attachments.mdx +19 -0
- package/site/content/docs/guides/bundle-size.mdx +78 -0
- package/site/content/docs/guides/dkim.mdx +26 -0
- package/site/content/docs/guides/index.mdx +15 -0
- package/site/content/docs/guides/meta.json +21 -0
- package/site/content/docs/guides/oauth2.mdx +23 -0
- package/site/content/docs/guides/observability.mdx +16 -0
- package/site/content/docs/guides/plugins-template.mdx +22 -0
- package/site/content/docs/guides/pool.mdx +24 -0
- package/site/content/docs/guides/react-email.mdx +20 -0
- package/site/content/docs/guides/security.mdx +17 -0
- package/site/content/docs/guides/send-bulk.mdx +18 -0
- package/site/content/docs/guides/vendor-extras-otp.mdx +18 -0
- package/site/content/docs/guides/webhooks.mdx +120 -0
- package/site/content/docs/guides/webpush-interop.mdx +18 -0
- package/site/content/docs/index.mdx +15 -0
- package/site/content/docs/meta.json +15 -0
- package/site/content/docs/quick-start/email.mdx +40 -0
- package/site/content/docs/quick-start/index.mdx +15 -0
- package/site/content/docs/quick-start/meta.json +5 -0
- package/site/content/docs/quick-start/push.mdx +36 -0
- package/site/content/docs/quick-start/sms.mdx +36 -0
- package/site/content/docs/quick-start/whatsapp.mdx +38 -0
- package/site/content/docs/reference/errors.mdx +22 -0
- package/site/content/docs/reference/exports.mdx +83 -0
- package/site/content/docs/reference/index.mdx +15 -0
- package/site/content/docs/reference/mail-options.mdx +22 -0
- package/site/content/docs/reference/meta.json +15 -0
- package/site/content/docs/reference/push-options.mdx +20 -0
- package/site/content/docs/reference/sms-options.mdx +17 -0
- package/site/content/docs/reference/transport-contracts.mdx +17 -0
- package/site/content/docs/reference/webhook-events.mdx +70 -0
- package/site/content/docs/reference/whatsapp-options.mdx +15 -0
- package/site/content/docs/transports/brevo.mdx +40 -0
- package/site/content/docs/transports/cloudflare-email.mdx +40 -0
- package/site/content/docs/transports/index.mdx +105 -0
- package/site/content/docs/transports/loops.mdx +41 -0
- package/site/content/docs/transports/mailersend.mdx +40 -0
- package/site/content/docs/transports/mailgun.mdx +42 -0
- package/site/content/docs/transports/mailtrap.mdx +42 -0
- package/site/content/docs/transports/meta.json +32 -0
- package/site/content/docs/transports/msegat.mdx +42 -0
- package/site/content/docs/transports/plunk.mdx +40 -0
- package/site/content/docs/transports/postmark.mdx +40 -0
- package/site/content/docs/transports/resend.mdx +43 -0
- package/site/content/docs/transports/sendgrid.mdx +40 -0
- package/site/content/docs/transports/ses.mdx +44 -0
- package/site/content/docs/transports/smtp.mdx +47 -0
- package/site/content/docs/transports/sndr.mdx +144 -0
- package/site/content/docs/transports/sparkpost.mdx +41 -0
- package/site/content/docs/transports/taqnyat-mail.mdx +41 -0
- package/site/content/docs/transports/taqnyat-sms.mdx +41 -0
- package/site/content/docs/transports/taqnyat-whatsapp.mdx +40 -0
- package/site/content/docs/transports/twilio-sms.mdx +128 -0
- package/site/content/docs/transports/webpush.mdx +43 -0
- package/site/content/docs/transports/whatsapp-cloud.mdx +42 -0
- package/dist/chunk-5scdgffb.js +0 -5
- package/dist/chunk-8phpsns1.js +0 -13
- package/dist/chunk-m07smapm.js +0 -3
- package/dist/chunk-n5dan5bz.js +0 -4
- package/dist/chunk-qh90yr6d.js +0 -4
- package/dist/chunk-vhxzhx8b.js +0 -4
- package/dist/chunk-wbvhaqcp.js +0 -4
- package/dist/chunk-wsymfbkn.js +0 -4
- package/dist/chunk-yr56b0ts.js +0 -4
- package/dist/chunk-yr56b0ts.js.map +0 -11
package/dist/chunk-yr56b0ts.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{A as E}from"./chunk-9zkv5azm.js";import{B as M}from"./chunk-z62q7kqr.js";import{F as D}from"./chunk-qh90yr6d.js";import{X as S}from"./chunk-6bkj4y4r.js";async function _(j,w){if(!w||w.length===0)return j;let H=j;for(let z of w)H=await z(H);return H}function P(j){return typeof j.setMailerOnRetry==="function"}function f(j){return typeof j.setMailerOnFallback==="function"}var b="SMTP config passed to transport-only createMailer. Use: import { createSMTPMailer } from 'sently' or import { createSMTPMailer } from 'sently/smtp'.";async function l(j){if(j.transport===void 0||"host"in j&&j.transport===void 0)throw new S(b,"INVALID_CONFIG");return new k(j.transport,j.plugins??[],j.hooks)}function v(j){return j.attachments!==void 0&&j.attachments.length>0}function x(j){return E(j)}function q(j,w){return{...j.messageId!==void 0?{messageId:j.messageId}:{},to:D(j.to),subject:j.subject,provider:x(w)}}async function C(j,...w){if(j===void 0)return;try{await j(...w)}catch(H){if(!(typeof process<"u"&&process.env?.NODE_ENV==="production"))console.warn("[sently] Mailer hook threw; send continues:",H)}}class k{transport;plugins;hooks;constructor(j,w=[],H){this.transport=j;this.plugins=w;this.hooks=H}async send(j){let w=await _(j,this.plugins),H=q(w,this.transport);if(await C(this.hooks?.onSend,H),this.hooks?.onRetry!==void 0&&P(this.transport))this.transport.setMailerOnRetry((B,G)=>{C(this.hooks?.onRetry,H,B,G)});if(this.hooks?.onFallback!==void 0&&f(this.transport))this.transport.setMailerOnFallback((B,G,I)=>{C(this.hooks?.onFallback,H,B,G,I)});let z=performance.now();try{let B=await this.transport.send(w),G={...H,messageId:B.messageId};return await C(this.hooks?.onSuccess,G,B,performance.now()-z),B}catch(B){throw await C(this.hooks?.onError,H,B,performance.now()-z),B}finally{if(P(this.transport))this.transport.setMailerOnRetry(void 0);if(f(this.transport))this.transport.setMailerOnFallback(void 0)}}async processMessage(j){return _(j,this.plugins)}async sendBulk(j,w){if(j.length===0)return{total:0,sent:0,failed:0,results:[]};let H=Array(j.length),z=w?.stopOnError??!1,B=!1,G=async(X,$,J,U,Z)=>{if(H[$]={status:"sent",result:J},U!==void 0&&this.hooks!==void 0){let W=q(U,this.transport);await C(this.hooks.onSend,W),await C(this.hooks.onSuccess,{...W,messageId:J.messageId},J,Z)}w?.onSuccess?.(X,$,J)},I=async(X,$,J,U,Z)=>{if(H[$]={status:"failed",error:J},U!==void 0&&this.hooks!==void 0){let W=q(U,this.transport);await C(this.hooks.onSend,W),await C(this.hooks.onError,W,J,Z)}if(w?.onError?.(X,$,J),z)B=!0};if(this.transport.sendBatch){let X=[],$=[];for(let[J,U]of j.entries())if(v(U))$.push({index:J,message:U});else X.push({index:J,message:U});if(X.length>0&&!B){let J=this.transport.batchMax??X.length,U=w?.rateDelta??2,Z=U>0?new M(U,w?.rateLimit??1000,w?.now):null;for(let W=0;W<X.length&&!B;W+=J){let V=X.slice(W,W+J);if(Z)await Z.acquire();try{let Y=await Promise.all(V.map(({message:A})=>this.processMessage(A))),Q=performance.now(),K=await this.transport.sendBatch(Y),T=performance.now()-Q;for(let A=0;A<V.length;A++){let F=V[A],R=Y[A],L=K[A];if(L===void 0)await I(F.message,F.index,Error("Batch response missing result for message"),R,T);else if(L.batchError!==void 0)await I(F.message,F.index,L.batchError,R,T);else await G(F.message,F.index,L,R,T)}}catch(Y){let Q=await Promise.all(V.map(({message:K})=>this.processMessage(K)));for(let K=0;K<V.length;K++){if(B)break;let T=V[K];await I(T.message,T.index,Y,Q[K])}}}}if($.length>0&&!B){let J=w?.concurrency??1,U=[...$],Z=0;await new Promise((W)=>{let V=()=>{if(U.length===0&&Z===0||B)W()},Y=()=>{if(U.length===0||B){V();return}let Q=U.shift();if(Q===void 0){V();return}Z++,this.send(Q.message).then((K)=>{H[Q.index]={status:"sent",result:K},w?.onSuccess?.(Q.message,Q.index,K)}).catch((K)=>{if(H[Q.index]={status:"failed",error:K},w?.onError?.(Q.message,Q.index,K),z)B=!0}).finally(()=>{Z--,Y(),V()})};for(let Q=0;Q<J;Q++)Y()})}}else{let X=w?.concurrency??1,$=[...j.entries()],J=0;await new Promise((U)=>{let Z=()=>{if($.length===0&&J===0||B)U()},W=()=>{if($.length===0||B){Z();return}let V=$.shift();if(V===void 0){Z();return}let[Y,Q]=V;J++,this.send(Q).then((K)=>{H[Y]={status:"sent",result:K},w?.onSuccess?.(Q,Y,K)}).catch((K)=>{if(H[Y]={status:"failed",error:K},w?.onError?.(Q,Y,K),z)B=!0}).finally(()=>{J--,W(),Z()})};for(let V=0;V<X;V++)W()})}let N=0,O=0;for(let X of H){if(X===void 0)continue;if(X.status==="sent")N++;else O++}return{total:j.length,sent:N,failed:O,results:H}}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{l as y,k as z};
|
|
3
|
-
|
|
4
|
-
//# debugId=A6BD4A8094E8BBE064756E2164756E21
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/core/plugin.ts", "../src/mailer.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * @module\n * Plugin pipeline for sently.\n * Plugins transform MailOptions before message construction.\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 */\nimport type { MailOptions, MailPlugin } from \"./types.js\";\n\n/**\n * Run a list of plugins sequentially over MailOptions.\n * If plugins is empty or undefined, returns options unchanged.\n * Each plugin may be sync or async.\n *\n * @param options - the original mail options\n * @param plugins - ordered list of plugins to apply\n * @returns transformed mail options after all plugins have run\n */\nexport async function runPlugins(\n options: MailOptions,\n plugins: MailPlugin[] | undefined,\n): Promise<MailOptions> {\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",
|
|
6
|
-
"/**\n * @module\n * Lightweight mailer factory for custom transports — no SMTP code in the bundle.\n *\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 { SentlyError } from \"./core/errors.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\n/** Retry decorator wired by mailer hooks (duck-typed to avoid pulling retry into all bundles). */\ninterface RetryHookTransport extends Transport {\n setMailerOnRetry(callback: ((attempt: number, error: unknown) => void) | undefined): void;\n}\n\nfunction isRetryHookTransport(transport: Transport): transport is RetryHookTransport {\n return typeof (transport as RetryHookTransport).setMailerOnRetry === \"function\";\n}\n\n/** Fallback decorator wired by mailer hooks (duck-typed). */\ninterface FallbackHookTransport extends Transport {\n setMailerOnFallback(\n callback: ((failedProvider: string, nextProvider: string, error: unknown) => void) | undefined,\n ): void;\n}\n\nfunction isFallbackHookTransport(transport: Transport): transport is FallbackHookTransport {\n return typeof (transport as FallbackHookTransport).setMailerOnFallback === \"function\";\n}\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/**\n * Invoke a mailer hook without letting hook failures break the send.\n * In non-production environments, hook errors are logged with `console.warn`.\n */\nasync 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] Mailer hook threw; send continues:\", hookError);\n }\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"
|
|
7
|
-
],
|
|
8
|
-
"mappings": "kLAuBA,SAAsB,LAAU,LAC9B,EACA,EACsB,CACtB,GAAI,CAAC,GAAW,EAAQ,SAAW,EACjC,OAAO,EAGT,IAAI,EAAU,EACd,QAAW,KAAU,EACnB,EAAU,MAAM,EAAO,CAAO,EAEhC,OAAO,ECeT,SAAS,CAAoB,CAAC,EAAuD,CACnF,OAAO,OAAQ,EAAiC,mBAAqB,WAUvE,SAAS,CAAuB,CAAC,EAA0D,CACzF,OAAO,OAAQ,EAAoC,sBAAwB,WAG7E,IAAM,EACJ,uJAKF,eAAsB,CAAY,CAAC,EAAkD,CACnF,GAAI,EAAQ,YAAc,QAAc,SAAU,GAAW,EAAQ,YAAc,OACjF,MAAM,IAAI,EAAY,EAAoC,gBAAgB,EAG5E,OAAO,IAAI,EAAW,EAAQ,UAAW,EAAQ,SAAW,CAAC,EAAG,EAAQ,KAAK,EAG/E,SAAS,CAAc,CAAC,EAA+B,CACrD,OAAO,EAAQ,cAAgB,QAAa,EAAQ,YAAY,OAAS,EAI3E,SAAS,CAAa,CAAC,EAA8B,CACnD,OAAO,EAAiB,CAAS,EAInC,SAAS,CAAgB,CAAC,EAAsB,EAAyC,CACvF,MAAO,IACD,EAAQ,YAAc,OAAY,CAAE,UAAW,EAAQ,SAAU,EAAI,CAAC,EAC1E,GAAI,EAAc,EAAQ,EAAE,EAC5B,QAAS,EAAQ,QACjB,SAAU,EAAc,CAAS,CACnC,EAOF,eAAe,CAA+B,CAC5C,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,8CAA+C,CAAS,GAMpE,MAAM,CAA6B,CAErB,UACA,QACA,MAHnB,WAAW,CACQ,EACA,EAAwB,CAAC,EACzB,EACjB,CAHiB,iBACA,eACA,kBAGb,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAY,MAAM,EAAW,EAAS,KAAK,OAAO,EAClD,EAAM,EAAiB,EAAW,KAAK,SAAS,EAItD,GAFA,MAAM,EAAW,KAAK,OAAO,OAAQ,CAAG,EAEpC,KAAK,OAAO,UAAY,QAAa,EAAqB,KAAK,SAAS,EAC1E,KAAK,UAAU,iBAAiB,CAAC,EAAS,IAAU,CAC7C,EAAW,KAAK,OAAO,QAAS,EAAK,EAAS,CAAK,EACzD,EAGH,GAAI,KAAK,OAAO,aAAe,QAAa,EAAwB,KAAK,SAAS,EAChF,KAAK,UAAU,oBAAoB,CAAC,EAAgB,EAAc,IAAU,CACrE,EAAW,KAAK,OAAO,WAAY,EAAK,EAAgB,EAAc,CAAK,EACjF,EAGH,IAAM,EAAQ,YAAY,IAAI,EAE9B,GAAI,CACF,IAAM,EAAS,MAAM,KAAK,UAAU,KAAK,CAAS,EAC5C,EAAgC,IACjC,EACH,UAAW,EAAO,SACpB,EAEA,OADA,MAAM,EAAW,KAAK,OAAO,UAAW,EAAY,EAAQ,YAAY,IAAI,EAAI,CAAK,EAC9E,EACP,MAAO,EAAO,CAEd,MADA,MAAM,EAAW,KAAK,OAAO,QAAS,EAAK,EAAO,YAAY,IAAI,EAAI,CAAK,EACrE,SACN,CACA,GAAI,EAAqB,KAAK,SAAS,EACrC,KAAK,UAAU,iBAAiB,MAAS,EAE3C,GAAI,EAAwB,KAAK,SAAS,EACxC,KAAK,UAAU,oBAAoB,MAAS,QAKpC,eAAc,CAAC,EAA4C,CACvE,OAAO,EAAW,EAAS,KAAK,OAAO,OAGnC,SAAQ,CAAC,EAAyB,EAAoD,CAC1F,GAAI,EAAS,SAAW,EACtB,MAAO,CAAE,MAAO,EAAG,KAAM,EAAG,OAAQ,EAAG,QAAS,CAAC,CAAE,EAGrD,IAAM,EAAyC,MAAM,EAAS,MAAM,EAC9D,EAAc,GAAS,aAAe,GACxC,EAAS,GAEP,EAAgB,MACpB,EACA,EACA,EACA,EACA,IACkB,CAElB,GADA,EAAQ,GAAS,CAAE,OAAQ,OAAQ,QAAO,EACtC,IAAc,QAAa,KAAK,QAAU,OAAW,CACvD,IAAM,EAAM,EAAiB,EAAW,KAAK,SAAS,EACtD,MAAM,EAAW,KAAK,MAAM,OAAQ,CAAG,EACvC,MAAM,EACJ,KAAK,MAAM,UACX,IAAK,EAAK,UAAW,EAAO,SAAU,EACtC,EACA,CACF,EAEF,GAAS,YAAY,EAAS,EAAO,CAAM,GAGvC,EAAgB,MACpB,EACA,EACA,EACA,EACA,IACkB,CAElB,GADA,EAAQ,GAAS,CAAE,OAAQ,SAAU,OAAM,EACvC,IAAc,QAAa,KAAK,QAAU,OAAW,CACvD,IAAM,EAAM,EAAiB,EAAW,KAAK,SAAS,EACtD,MAAM,EAAW,KAAK,MAAM,OAAQ,CAAG,EACvC,MAAM,EAAW,KAAK,MAAM,QAAS,EAAK,EAAO,CAAU,EAG7D,GADA,GAAS,UAAU,EAAS,EAAO,CAAK,EACpC,EACF,EAAS,IAIb,GAAI,KAAK,UAAU,UAAW,CAC5B,IAAM,EAA+D,CAAC,EAChE,EAAgE,CAAC,EAEvE,QAAY,EAAO,KAAY,EAAS,QAAQ,EAC9C,GAAI,EAAe,CAAO,EACxB,EAAc,KAAK,CAAE,QAAO,SAAQ,CAAC,EAErC,OAAa,KAAK,CAAE,QAAO,SAAQ,CAAC,EAIxC,GAAI,EAAa,OAAS,GAAK,CAAC,EAAQ,CACtC,IAAM,EAAY,KAAK,UAAU,UAAY,EAAa,OACpD,EAAY,GAAS,WAAa,EAClC,EACJ,EAAY,EACR,IAAI,EAAY,EAAW,GAAS,WAAa,KAAM,GAAS,GAAG,EACnE,KAEN,QACM,EAAa,EACjB,EAAa,EAAa,QAAU,CAAC,EACrC,GAAc,EACd,CACA,IAAM,EAAQ,EAAa,MAAM,EAAY,EAAa,CAAS,EAEnE,GAAI,EACF,MAAM,EAAY,QAAQ,EAG5B,GAAI,CACF,IAAM,EAAY,MAAM,QAAQ,IAC9B,EAAM,IAAI,EAAG,aAAc,KAAK,eAAe,CAAO,CAAC,CACzD,EACM,EAAa,YAAY,IAAI,EAC7B,EAAe,MAAM,KAAK,UAAU,UAAU,CAAS,EACvD,EAAkB,YAAY,IAAI,EAAI,EAE5C,QAAS,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,IAAM,EAAQ,EAAM,GACd,EAAmB,EAAU,GAC7B,EAAS,EAAa,GAC5B,GAAI,IAAW,OACb,MAAM,EACJ,EAAM,QACN,EAAM,MACF,MAAM,2CAA2C,EACrD,EACA,CACF,EACK,QAAI,EAAO,aAAe,OAC/B,MAAM,EACJ,EAAM,QACN,EAAM,MACN,EAAO,WACP,EACA,CACF,EAEA,WAAM,EACJ,EAAM,QACN,EAAM,MACN,EACA,EACA,CACF,GAGJ,MAAO,EAAO,CACd,IAAM,EAAY,MAAM,QAAQ,IAC9B,EAAM,IAAI,EAAG,aAAc,KAAK,eAAe,CAAO,CAAC,CACzD,EACA,QAAS,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,EACF,MAEF,IAAM,EAAQ,EAAM,GACpB,MAAM,EAAc,EAAM,QAAS,EAAM,MAAO,EAAO,EAAU,EAAE,KAM3E,GAAI,EAAc,OAAS,GAAK,CAAC,EAAQ,CACvC,IAAM,EAAc,GAAS,aAAe,EACtC,EAAQ,CAAC,GAAG,CAAa,EAC3B,EAAS,EAEb,MAAM,IAAI,QAAc,CAAC,IAAY,CACnC,IAAM,EAAY,IAAY,CAC5B,GAAK,EAAM,SAAW,GAAK,IAAW,GAAM,EAC1C,EAAQ,GAIN,EAAc,IAAY,CAC9B,GAAI,EAAM,SAAW,GAAK,EAAQ,CAChC,EAAU,EACV,OAGF,IAAM,EAAQ,EAAM,MAAM,EAC1B,GAAI,IAAU,OAAW,CACvB,EAAU,EACV,OAGF,IACK,KAAK,KAAK,EAAM,OAAO,EACzB,KAAK,CAAC,IAAW,CAChB,EAAQ,EAAM,OAAS,CAAE,OAAQ,OAAQ,QAAO,EAChD,GAAS,YAAY,EAAM,QAAS,EAAM,MAAO,CAAM,EACxD,EACA,MAAM,CAAC,IAAmB,CAGzB,GAFA,EAAQ,EAAM,OAAS,CAAE,OAAQ,SAAU,OAAM,EACjD,GAAS,UAAU,EAAM,QAAS,EAAM,MAAO,CAAK,EAChD,EACF,EAAS,GAEZ,EACA,QAAQ,IAAM,CACb,IACA,EAAY,EACZ,EAAU,EACX,GAGL,QAAS,EAAI,EAAG,EAAI,EAAa,IAC/B,EAAY,EAEf,GAEE,KACL,IAAM,EAAc,GAAS,aAAe,EACtC,EAAQ,CAAC,GAAG,EAAS,QAAQ,CAAC,EAChC,EAAS,EAEb,MAAM,IAAI,QAAc,CAAC,IAAY,CACnC,IAAM,EAAY,IAAY,CAC5B,GAAK,EAAM,SAAW,GAAK,IAAW,GAAM,EAC1C,EAAQ,GAIN,EAAc,IAAY,CAC9B,GAAI,EAAM,SAAW,GAAK,EAAQ,CAChC,EAAU,EACV,OAGF,IAAM,EAAQ,EAAM,MAAM,EAC1B,GAAI,IAAU,OAAW,CACvB,EAAU,EACV,OAGF,IAAO,EAAO,GAAW,EACzB,IAEK,KAAK,KAAK,CAAO,EACnB,KAAK,CAAC,IAAW,CAChB,EAAQ,GAAS,CAAE,OAAQ,OAAQ,QAAO,EAC1C,GAAS,YAAY,EAAS,EAAO,CAAM,EAC5C,EACA,MAAM,CAAC,IAAmB,CAGzB,GAFA,EAAQ,GAAS,CAAE,OAAQ,SAAU,OAAM,EAC3C,GAAS,UAAU,EAAS,EAAO,CAAK,EACpC,EACF,EAAS,GAEZ,EACA,QAAQ,IAAM,CACb,IACA,EAAY,EACZ,EAAU,EACX,GAGL,QAAS,EAAI,EAAG,EAAI,EAAa,IAC/B,EAAY,EAEf,EAGH,IAAI,EAAO,EACP,EAAS,EACb,QAAW,KAAU,EAAS,CAC5B,GAAI,IAAW,OACb,SAEF,GAAI,EAAO,SAAW,OACpB,IAEA,SAIJ,MAAO,CACL,MAAO,EAAS,OAChB,OACA,SACA,SACF,EAGF,MAAM,EAA0B,CAC9B,GAAI,KAAK,UAAU,OACjB,OAAO,KAAK,UAAU,OAAO,EAE/B,OAAO,QAAQ,QAAQ,CAAE,GAAI,GAAM,SAAU,QAAS,CAAC,EAGzD,KAAK,EAAkB,CACrB,GAAI,KAAK,UAAU,MACjB,OAAO,KAAK,UAAU,MAAM,EAE9B,OAAO,QAAQ,QAAQ,EAE3B",
|
|
9
|
-
"debugId": "A6BD4A8094E8BBE064756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|