@visulima/email 2.1.6 → 2.1.7
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/CHANGELOG.md +7 -0
- package/dist/crypto/index.d.ts +183 -183
- package/dist/crypto/index.js +1 -1
- package/dist/deliverability/dmarc-report.d.ts +43 -43
- package/dist/deliverability/dmarc-report.js +1 -1
- package/dist/deliverability/index.d.ts +201 -201
- package/dist/events/index.d.ts +17 -17
- package/dist/inbound/index.d.ts +180 -180
- package/dist/index.d.ts +35 -46
- package/dist/index.js +1 -1
- package/dist/middleware/index.d.ts +213 -216
- package/dist/middleware/index.js +1 -1
- package/dist/packem_shared/{DkimSigner-CiLBaXrg.js → DkimSigner-sLcIw9bp.js} +6 -6
- package/dist/packem_shared/{DraftMailMessage-CGTVuy2z.js → DraftMailMessage-C3YTXqWo.js} +1 -1
- package/dist/packem_shared/EmailError-CDvYwuqz.js +1 -0
- package/dist/packem_shared/{Mail-CYAwMRnX.js → Mail-CIyxkmxu.js} +1 -1
- package/dist/packem_shared/MailMessage-DuEXJiCg.js +1 -0
- package/dist/packem_shared/{RequiredOptionError-DuNNY_a5.js → RequiredOptionError-DU2lxzk3.js} +1 -1
- package/dist/packem_shared/SmimeEncrypter-CzTbQM-z.js +6 -0
- package/dist/packem_shared/SmimeSigner-DjLShaOw.js +8 -0
- package/dist/packem_shared/{ahaSendProvider-DSuZIzaQ.js → ahaSendProvider-br1yB2un.js} +1 -1
- package/dist/packem_shared/arcMessageSignatureBase-D54jQIWu.js +17 -0
- package/dist/packem_shared/attachment-processor-D1cbAhQi.js +1 -0
- package/dist/packem_shared/{autoSendProvider-DqAoelWR.js → autoSendProvider-BSP8ueOC.js} +1 -1
- package/dist/packem_shared/{awsSesProvider-ClK1FUln.js → awsSesProvider-zRICW1pH.js} +13 -13
- package/dist/packem_shared/azureProvider-DwN4c5dC.js +1 -0
- package/dist/packem_shared/{brevoProvider-CIzuIDlt.js → brevoProvider-C491beE_.js} +1 -1
- package/dist/packem_shared/{build-mime-message-BW5FQ2Bt.js → build-mime-message-DT67qfMp.js} +1 -1
- package/dist/packem_shared/{circuitBreakerMiddleware-D2SA_07f.js → circuitBreakerMiddleware-N0CKF90q.js} +1 -1
- package/dist/packem_shared/{cloudflareEmailProvider-B8mOEl3N.js → cloudflareEmailProvider-8JxzLbpX.js} +1 -1
- package/dist/packem_shared/{createTestEmail-f12yLlWn.js → createTestEmail-D_ksEez3.js} +1 -1
- package/dist/packem_shared/dedupeMiddleware-CYYI_O7S.js +1 -0
- package/dist/packem_shared/{detectMimeType-DFH3kp6K.js → detectMimeType-CmYmWDXE.js} +1 -1
- package/dist/packem_shared/event-bus.d-BNQA-FZE.d.ts +104 -0
- package/dist/packem_shared/{failoverProvider-BgX6zfnY.js → failoverProvider-6qwE_HSJ.js} +1 -1
- package/dist/packem_shared/generate-boundary-0xGe9GqK.js +1 -0
- package/dist/packem_shared/{httpProvider-aBfTXyCT.js → httpProvider-BqrdZhGw.js} +1 -1
- package/dist/packem_shared/index-Gd7m-UQA.js +11 -0
- package/dist/packem_shared/{infobipProvider-DxzsONUX.js → infobipProvider-C2FU6VMP.js} +1 -1
- package/dist/packem_shared/isValidSigningCertUrl-DNxPA0Q-.js +3 -0
- package/dist/packem_shared/{loopsProvider-QBsAH6Ee.js → loopsProvider-Bz63so6m.js} +1 -1
- package/dist/packem_shared/mail.d-xKtvoKMK.d.ts +909 -0
- package/dist/packem_shared/{mailCrabProvider-DRE5snM9.js → mailCrabProvider-bkQy-2a1.js} +1 -1
- package/dist/packem_shared/{mailPaceProvider-DCa-4ghl.js → mailPaceProvider-S1AB-AYq.js} +1 -1
- package/dist/packem_shared/{mailchannelsProvider-GiwkYBdD.js → mailchannelsProvider-B_K6X4VY.js} +1 -1
- package/dist/packem_shared/{mailerSendProvider-RK6IbUrL.js → mailerSendProvider-DPEww2H1.js} +1 -1
- package/dist/packem_shared/mailgunProvider-DKxzVbDW.js +1 -0
- package/dist/packem_shared/mailjetProvider-C2TQcujL.js +1 -0
- package/dist/packem_shared/{mailomatProvider-DPDpVS8r.js → mailomatProvider-B8-5bQsu.js} +1 -1
- package/dist/packem_shared/{mailtrapProvider-DtrS4Q34.js → mailtrapProvider-DW7TLOdG.js} +1 -1
- package/dist/packem_shared/{make-request-B9XjBynA.js → make-request-CylyuRaN.js} +1 -1
- package/dist/packem_shared/{mandrillProvider-B84zH-eV.js → mandrillProvider-S-0lKNGd.js} +1 -1
- package/dist/packem_shared/{mockProvider-Behywbl1.js → mockProvider-BAl292mW.js} +1 -1
- package/dist/packem_shared/{netcoreProvider-D-wtCyJj.js → netcoreProvider-DajMprlo.js} +1 -1
- package/dist/packem_shared/{nodemailerProvider-BFHobXxt.js → nodemailerProvider-DRo0lJ6g.js} +1 -1
- package/dist/packem_shared/{opentelemetryProvider-ByHC01ub.js → opentelemetryProvider-C6spx2CD.js} +1 -1
- package/dist/packem_shared/{outlook365Provider-Btk4Emig.js → outlook365Provider-B0o7UZBW.js} +1 -1
- package/dist/packem_shared/{plunkProvider-Bw8e6460.js → plunkProvider-DJzEUEtU.js} +1 -1
- package/dist/packem_shared/{postalProvider-CT8zr89z.js → postalProvider-DHFjFE3Y.js} +1 -1
- package/dist/packem_shared/{postmarkProvider-CQSqZWDs.js → postmarkProvider-Dt1EGGBA.js} +1 -1
- package/dist/packem_shared/{provider-base-C7PuopYK.js → provider-base-DjPzWncP.js} +1 -1
- package/dist/packem_shared/{provider.d-J-y6iogK.d.ts → provider.d-Cx5YQJdP.d.ts} +9 -9
- package/dist/packem_shared/{resendProvider-drJYlvLP.js → resendProvider-qjI86j_d.js} +1 -1
- package/dist/packem_shared/{retry-ipI5DRJ8.js → retry-CG9iT2wF.js} +1 -1
- package/dist/packem_shared/{roundRobinProvider-D1by5KGW.js → roundRobinProvider-CO5YvhgR.js} +1 -1
- package/dist/packem_shared/{scalewayProvider-DU5gXQrl.js → scalewayProvider-CihQKhw6.js} +1 -1
- package/dist/packem_shared/{sendGridProvider-BuTbEXW8.js → sendGridProvider-Dkc5AKlC.js} +1 -1
- package/dist/packem_shared/{smtpProvider-5MI3-EPh.js → smtpProvider-CIXMxPu-.js} +12 -12
- package/dist/packem_shared/{sparkpostProvider-UAsFYIjP.js → sparkpostProvider-CKxQhpyB.js} +1 -1
- package/dist/packem_shared/{sweegoProvider-SUz0LIcA.js → sweegoProvider-DjmAs6La.js} +1 -1
- package/dist/packem_shared/{tracer.d-MU42G1jG.d.ts → tracer.d-sb5yrt_n.d.ts} +2 -2
- package/dist/packem_shared/types.d-B0t3PQ3t.d.ts +107 -0
- package/dist/packem_shared/{types.d-ejzh-xBP.d.ts → types.d-B9295M4_.d.ts} +82 -82
- package/dist/packem_shared/types.d-BzoHR9nB.d.ts +61 -0
- package/dist/packem_shared/types.d-C5geVKes.d.ts +51 -0
- package/dist/packem_shared/types.d-GKqPNk0I.d.ts +24 -0
- package/dist/packem_shared/types.d-I-KeZ5w2.d.ts +9 -0
- package/dist/packem_shared/types.d-kHO4kX9q.d.ts +69 -0
- package/dist/packem_shared/utils-DjEtR3qT.js +1 -0
- package/dist/packem_shared/verifyMailgunWebhook-DNk080BF.js +1 -0
- package/dist/packem_shared/verifyPostmarkWebhook-B4OIEHQF.js +1 -0
- package/dist/packem_shared/verifyResendWebhook-C7E32LZ1.js +1 -0
- package/dist/packem_shared/verifySendGridWebhook-1l9bqIMw.js +1 -0
- package/dist/packem_shared/withEvents-CytsykaK.js +1 -0
- package/dist/packem_shared/{withSuppression-DBaZDMAr.js → withSuppression-BoaO4Qdz.js} +1 -1
- package/dist/packem_shared/{zeptomailProvider-DXNX9mG_.js → zeptomailProvider-DSTC9pUi.js} +1 -1
- package/dist/providers/ahasend/index.d.ts +18 -18
- package/dist/providers/ahasend/index.js +1 -1
- package/dist/providers/autosend/index.d.ts +30 -30
- package/dist/providers/autosend/index.js +1 -1
- package/dist/providers/aws-ses/index.d.ts +20 -20
- package/dist/providers/aws-ses/index.js +1 -1
- package/dist/providers/azure/index.d.ts +26 -26
- package/dist/providers/azure/index.js +1 -1
- package/dist/providers/brevo/index.d.ts +35 -35
- package/dist/providers/brevo/index.js +1 -1
- package/dist/providers/cloudflare-email/index.d.ts +25 -25
- package/dist/providers/cloudflare-email/index.js +1 -1
- package/dist/providers/failover/index.d.ts +14 -14
- package/dist/providers/failover/index.js +1 -1
- package/dist/providers/http/index.d.ts +15 -15
- package/dist/providers/http/index.js +1 -1
- package/dist/providers/infobip/index.d.ts +28 -28
- package/dist/providers/infobip/index.js +1 -1
- package/dist/providers/loops/index.d.ts +25 -25
- package/dist/providers/loops/index.js +1 -1
- package/dist/providers/mailchannels/index.d.ts +13 -13
- package/dist/providers/mailchannels/index.js +1 -1
- package/dist/providers/mailcrab/index.d.ts +17 -17
- package/dist/providers/mailcrab/index.js +1 -1
- package/dist/providers/mailersend/index.d.ts +24 -24
- package/dist/providers/mailersend/index.js +1 -1
- package/dist/providers/mailgun/index.d.ts +37 -37
- package/dist/providers/mailgun/index.js +1 -1
- package/dist/providers/mailjet/index.d.ts +36 -36
- package/dist/providers/mailjet/index.js +1 -1
- package/dist/providers/mailomat/index.d.ts +20 -20
- package/dist/providers/mailomat/index.js +1 -1
- package/dist/providers/mailpace/index.d.ts +24 -24
- package/dist/providers/mailpace/index.js +1 -1
- package/dist/providers/mailtrap/index.d.ts +22 -22
- package/dist/providers/mailtrap/index.js +1 -1
- package/dist/providers/mandrill/index.d.ts +36 -36
- package/dist/providers/mandrill/index.js +1 -1
- package/dist/providers/mock/index.d.ts +8 -8
- package/dist/providers/mock/index.js +1 -1
- package/dist/providers/netcore/index.d.ts +17 -17
- package/dist/providers/netcore/index.js +1 -1
- package/dist/providers/nodemailer/index.d.ts +22 -22
- package/dist/providers/nodemailer/index.js +1 -1
- package/dist/providers/opentelemetry/index.d.ts +20 -20
- package/dist/providers/opentelemetry/index.js +1 -1
- package/dist/providers/outlook365/index.d.ts +82 -82
- package/dist/providers/outlook365/index.js +1 -1
- package/dist/providers/plunk/index.d.ts +18 -18
- package/dist/providers/plunk/index.js +1 -1
- package/dist/providers/postal/index.d.ts +24 -24
- package/dist/providers/postal/index.js +1 -1
- package/dist/providers/postmark/index.d.ts +30 -30
- package/dist/providers/postmark/index.js +1 -1
- package/dist/providers/resend/index.d.ts +24 -24
- package/dist/providers/resend/index.js +1 -1
- package/dist/providers/roundrobin/index.d.ts +14 -14
- package/dist/providers/roundrobin/index.js +1 -1
- package/dist/providers/scaleway/index.d.ts +22 -22
- package/dist/providers/scaleway/index.js +1 -1
- package/dist/providers/sendgrid/index.d.ts +25 -25
- package/dist/providers/sendgrid/index.js +1 -1
- package/dist/providers/smtp/index.d.ts +11 -11
- package/dist/providers/smtp/index.js +1 -1
- package/dist/providers/sparkpost/index.d.ts +21 -21
- package/dist/providers/sparkpost/index.js +1 -1
- package/dist/providers/sweego/index.d.ts +20 -20
- package/dist/providers/sweego/index.js +1 -1
- package/dist/providers/zeptomail/index.d.ts +17 -17
- package/dist/providers/zeptomail/index.js +1 -1
- package/dist/queue/bullmq-queue.d.ts +26 -26
- package/dist/queue/index.d.ts +86 -86
- package/dist/queue/pg-boss-queue.d.ts +13 -13
- package/dist/queue/sqs-queue.d.ts +20 -20
- package/dist/queue/unstorage-queue.d.ts +47 -47
- package/dist/queue/unstorage-queue.js +1 -1
- package/dist/render/cid.d.ts +12 -12
- package/dist/render/css-inline.d.ts +12 -12
- package/dist/render/css-inline.js +1 -1
- package/dist/render/dark-mode.d.ts +12 -12
- package/dist/render/preheader.d.ts +16 -16
- package/dist/template-engines/handlebars.d.ts +19 -19
- package/dist/template-engines/handlebars.js +1 -1
- package/dist/template-engines/html-to-text.d.ts +12 -12
- package/dist/template-engines/html-to-text.js +1 -1
- package/dist/template-engines/i18n.d.ts +43 -43
- package/dist/template-engines/i18n.js +1 -1
- package/dist/template-engines/jsx-email.d.ts +8 -8
- package/dist/template-engines/jsx-email.js +1 -1
- package/dist/template-engines/liquid.d.ts +9 -9
- package/dist/template-engines/liquid.js +1 -1
- package/dist/template-engines/mjml.d.ts +9 -9
- package/dist/template-engines/mjml.js +1 -1
- package/dist/template-engines/react-email.d.ts +8 -8
- package/dist/template-engines/react-email.js +1 -1
- package/dist/template-engines/vue-email.d.ts +8 -8
- package/dist/template-engines/vue-email.js +1 -1
- package/dist/test/index.d.ts +89 -89
- package/dist/test/index.js +1 -1
- package/dist/utils/cache.d.ts +27 -27
- package/dist/utils/format-email-address.d.ts +6 -6
- package/dist/utils/format-email-address.js +1 -1
- package/dist/utils/normalize-email-aliases.d.ts +19 -19
- package/dist/utils/parse-address.d.ts +16 -16
- package/dist/utils/parse-eml.d.ts +18 -18
- package/dist/utils/result.d.ts +30 -30
- package/dist/utils/result.js +1 -1
- package/dist/utils/validation/check-feature-support.d.ts +33 -33
- package/dist/utils/validation/validate-email.d.ts +4 -4
- package/dist/webhooks/index.d.ts +134 -134
- package/dist/webhooks/index.js +1 -1
- package/package.json +1 -1
- package/dist/packem_shared/EmailError-B-sEf3bp.js +0 -1
- package/dist/packem_shared/MailMessage-DQRgs5Dz.js +0 -1
- package/dist/packem_shared/SmimeEncrypter-DavopRlE.js +0 -6
- package/dist/packem_shared/SmimeSigner-0onWksAv.js +0 -8
- package/dist/packem_shared/arcMessageSignatureBase-DDLEHW2E.js +0 -17
- package/dist/packem_shared/attachment-processor-CMp7qqMI.js +0 -1
- package/dist/packem_shared/azureProvider-Cw_Tmde6.js +0 -1
- package/dist/packem_shared/dedupeMiddleware-B6ajWOTi.js +0 -1
- package/dist/packem_shared/event-bus.d-DEl3w_EW.d.ts +0 -104
- package/dist/packem_shared/generate-boundary-DQbzDiOI.js +0 -1
- package/dist/packem_shared/index-BoZvzveg.js +0 -11
- package/dist/packem_shared/isValidSigningCertUrl-Bii1AMGC.js +0 -3
- package/dist/packem_shared/mail.d-B9SSqyy0.d.ts +0 -909
- package/dist/packem_shared/mailgunProvider-D9HUWGKN.js +0 -1
- package/dist/packem_shared/mailjetProvider-DelLs2Vt.js +0 -1
- package/dist/packem_shared/types.d-BId55FW2.d.ts +0 -107
- package/dist/packem_shared/types.d-CmoWvdZi.d.ts +0 -61
- package/dist/packem_shared/types.d-DCkecJse.d.ts +0 -51
- package/dist/packem_shared/types.d-Mpu0HZoG.d.ts +0 -24
- package/dist/packem_shared/types.d-lcJZmwRK.d.ts +0 -69
- package/dist/packem_shared/types.d-nyR1ty1Q.d.ts +0 -9
- package/dist/packem_shared/utils-BfYfPB_I.js +0 -1
- package/dist/packem_shared/verifyMailgunWebhook-Cwl0OD3P.js +0 -1
- package/dist/packem_shared/verifyPostmarkWebhook-C72ZvbrG.js +0 -1
- package/dist/packem_shared/verifyResendWebhook-YK2zNDXR.js +0 -1
- package/dist/packem_shared/verifySendGridWebhook-Dbwc1tfG.js +0 -1
- package/dist/packem_shared/withEvents-CCVblSqj.js +0 -1
package/dist/webhooks/index.d.ts
CHANGED
|
@@ -1,140 +1,140 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Result of verifying an inbound webhook signature.
|
|
3
|
-
*/
|
|
2
|
+
* Result of verifying an inbound webhook signature.
|
|
3
|
+
*/
|
|
4
4
|
interface WebhookVerificationResult {
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
* Machine-readable reason when {@link WebhookVerificationResult.valid} is `false`.
|
|
7
|
+
*/
|
|
8
8
|
reason?: string;
|
|
9
9
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
* Whether the signature (and, when applicable, the timestamp) is valid.
|
|
11
|
+
*/
|
|
12
12
|
valid: boolean;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Headers passed to a webhook verifier. Either a plain record or a `Headers` instance.
|
|
16
|
-
*
|
|
17
|
-
* Lookups are case-insensitive.
|
|
18
|
-
*/
|
|
15
|
+
* Headers passed to a webhook verifier. Either a plain record or a `Headers` instance.
|
|
16
|
+
*
|
|
17
|
+
* Lookups are case-insensitive.
|
|
18
|
+
*/
|
|
19
19
|
type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;
|
|
20
20
|
/**
|
|
21
|
-
* Shared options for verifiers that enforce a timestamp tolerance to guard against replay attacks.
|
|
22
|
-
*/
|
|
21
|
+
* Shared options for verifiers that enforce a timestamp tolerance to guard against replay attacks.
|
|
22
|
+
*/
|
|
23
23
|
interface TimestampToleranceOptions {
|
|
24
24
|
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
* Maximum allowed difference, in seconds, between the signed timestamp and the current time.
|
|
26
|
+
*
|
|
27
|
+
* Set to `0` to disable the replay-protection window.
|
|
28
|
+
* @default 300
|
|
29
|
+
*/
|
|
30
30
|
tolerance?: number;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Options for {@link verifyMailgunWebhook}.
|
|
34
|
-
*
|
|
35
|
-
* Mailgun nests these three fields under a `signature` object in the webhook JSON body.
|
|
36
|
-
*/
|
|
33
|
+
* Options for {@link verifyMailgunWebhook}.
|
|
34
|
+
*
|
|
35
|
+
* Mailgun nests these three fields under a `signature` object in the webhook JSON body.
|
|
36
|
+
*/
|
|
37
37
|
interface MailgunWebhookOptions extends TimestampToleranceOptions {
|
|
38
38
|
/**
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
* Override the current time (milliseconds) — primarily for testing.
|
|
40
|
+
*/
|
|
41
41
|
now?: number;
|
|
42
42
|
/**
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
* The HMAC value from `signature.signature`.
|
|
44
|
+
*/
|
|
45
45
|
signature: string;
|
|
46
46
|
/**
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
* Your Mailgun HTTP webhook signing key (Settings → Webhooks).
|
|
48
|
+
*/
|
|
49
49
|
signingKey: string;
|
|
50
50
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
* The timestamp from `signature.timestamp` (unix seconds, as a string or number).
|
|
52
|
+
*/
|
|
53
53
|
timestamp: number | string;
|
|
54
54
|
/**
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
* The token from `signature.token`.
|
|
56
|
+
*/
|
|
57
57
|
token: string;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* Verifies a [Mailgun](https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages/#webhooks) webhook.
|
|
61
|
-
*
|
|
62
|
-
* Mailgun computes `HMAC-SHA256(key = signingKey, message = timestamp + token)` and sends the hex
|
|
63
|
-
* digest as `signature.signature`.
|
|
64
|
-
* @param options Verification inputs. See {@link MailgunWebhookOptions}.
|
|
65
|
-
* @returns The verification result.
|
|
66
|
-
*/
|
|
60
|
+
* Verifies a [Mailgun](https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages/#webhooks) webhook.
|
|
61
|
+
*
|
|
62
|
+
* Mailgun computes `HMAC-SHA256(key = signingKey, message = timestamp + token)` and sends the hex
|
|
63
|
+
* digest as `signature.signature`.
|
|
64
|
+
* @param options Verification inputs. See {@link MailgunWebhookOptions}.
|
|
65
|
+
* @returns The verification result.
|
|
66
|
+
*/
|
|
67
67
|
declare const verifyMailgunWebhook: (options: MailgunWebhookOptions) => WebhookVerificationResult;
|
|
68
68
|
/**
|
|
69
|
-
* Options for {@link verifyPostmarkWebhook}.
|
|
70
|
-
*
|
|
71
|
-
* Postmark does not sign webhook payloads; instead it supports HTTP Basic Auth credentials embedded
|
|
72
|
-
* in the webhook URL (and IP allow-listing). This verifier checks the Basic Auth credentials.
|
|
73
|
-
*/
|
|
69
|
+
* Options for {@link verifyPostmarkWebhook}.
|
|
70
|
+
*
|
|
71
|
+
* Postmark does not sign webhook payloads; instead it supports HTTP Basic Auth credentials embedded
|
|
72
|
+
* in the webhook URL (and IP allow-listing). This verifier checks the Basic Auth credentials.
|
|
73
|
+
*/
|
|
74
74
|
interface PostmarkWebhookOptions {
|
|
75
75
|
/**
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
* The value of the incoming `Authorization` header (e.g. `Basic dXNlcjpwYXNz`).
|
|
77
|
+
*/
|
|
78
78
|
authorization: string | undefined;
|
|
79
79
|
/**
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
* The password configured on the Postmark webhook URL.
|
|
81
|
+
*/
|
|
82
82
|
password: string;
|
|
83
83
|
/**
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
* The username configured on the Postmark webhook URL.
|
|
85
|
+
*/
|
|
86
86
|
username: string;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
|
-
* Verifies a [Postmark](https://postmarkapp.com/support/article/1213-securing-inbound-and-open-webhooks)
|
|
90
|
-
* webhook by validating its HTTP Basic Auth credentials.
|
|
91
|
-
* @param options Verification inputs. See {@link PostmarkWebhookOptions}.
|
|
92
|
-
* @returns The verification result.
|
|
93
|
-
*/
|
|
89
|
+
* Verifies a [Postmark](https://postmarkapp.com/support/article/1213-securing-inbound-and-open-webhooks)
|
|
90
|
+
* webhook by validating its HTTP Basic Auth credentials.
|
|
91
|
+
* @param options Verification inputs. See {@link PostmarkWebhookOptions}.
|
|
92
|
+
* @returns The verification result.
|
|
93
|
+
*/
|
|
94
94
|
declare const verifyPostmarkWebhook: (options: PostmarkWebhookOptions) => WebhookVerificationResult;
|
|
95
95
|
/**
|
|
96
|
-
* Options for {@link verifySendGridWebhook}.
|
|
97
|
-
*/
|
|
96
|
+
* Options for {@link verifySendGridWebhook}.
|
|
97
|
+
*/
|
|
98
98
|
interface SendGridWebhookOptions extends TimestampToleranceOptions {
|
|
99
99
|
/**
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
* Override the current time (milliseconds) — primarily for testing.
|
|
101
|
+
*/
|
|
102
102
|
now?: number;
|
|
103
103
|
/**
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
* The raw, unparsed request body exactly as received.
|
|
105
|
+
*/
|
|
106
106
|
payload: string;
|
|
107
107
|
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
* The verification key from the SendGrid Event Webhook settings.
|
|
109
|
+
*
|
|
110
|
+
* Either the base64-encoded DER (SPKI) string SendGrid displays, or a full PEM block.
|
|
111
|
+
*/
|
|
112
112
|
publicKey: string;
|
|
113
113
|
/**
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
* The value of the `X-Twilio-Email-Event-Webhook-Signature` header (base64 DER ECDSA signature).
|
|
115
|
+
*/
|
|
116
116
|
signature: string;
|
|
117
117
|
/**
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
* The value of the `X-Twilio-Email-Event-Webhook-Timestamp` header (unix epoch seconds).
|
|
119
|
+
*/
|
|
120
120
|
timestamp: string;
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
|
-
* Verifies a [SendGrid Event Webhook](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook-security-features)
|
|
124
|
-
* using its ECDSA (prime256v1) signature, and rejects stale requests to prevent replay.
|
|
125
|
-
*
|
|
126
|
-
* The signed message is `timestamp + payload`. The signature header is the base64-encoded DER
|
|
127
|
-
* ECDSA signature. The timestamp is unix epoch seconds and must fall within `tolerance` of now.
|
|
128
|
-
* @param options Verification inputs. See {@link SendGridWebhookOptions}.
|
|
129
|
-
* @returns The verification result.
|
|
130
|
-
* @throws {EmailError} When the supplied public key cannot be parsed.
|
|
131
|
-
*/
|
|
123
|
+
* Verifies a [SendGrid Event Webhook](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook-security-features)
|
|
124
|
+
* using its ECDSA (prime256v1) signature, and rejects stale requests to prevent replay.
|
|
125
|
+
*
|
|
126
|
+
* The signed message is `timestamp + payload`. The signature header is the base64-encoded DER
|
|
127
|
+
* ECDSA signature. The timestamp is unix epoch seconds and must fall within `tolerance` of now.
|
|
128
|
+
* @param options Verification inputs. See {@link SendGridWebhookOptions}.
|
|
129
|
+
* @returns The verification result.
|
|
130
|
+
* @throws {EmailError} When the supplied public key cannot be parsed.
|
|
131
|
+
*/
|
|
132
132
|
declare const verifySendGridWebhook: (options: SendGridWebhookOptions) => WebhookVerificationResult;
|
|
133
133
|
/**
|
|
134
|
-
* The subset of an Amazon SNS message envelope relevant to signature verification.
|
|
135
|
-
*
|
|
136
|
-
* AWS SES delivers events (deliveries, bounces, complaints) wrapped in SNS notifications.
|
|
137
|
-
*/
|
|
134
|
+
* The subset of an Amazon SNS message envelope relevant to signature verification.
|
|
135
|
+
*
|
|
136
|
+
* AWS SES delivers events (deliveries, bounces, complaints) wrapped in SNS notifications.
|
|
137
|
+
*/
|
|
138
138
|
interface SnsMessage {
|
|
139
139
|
[key: string]: unknown;
|
|
140
140
|
Message?: string;
|
|
@@ -150,82 +150,82 @@ interface SnsMessage {
|
|
|
150
150
|
Type?: string;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
* Resolves a signing-certificate URL to its PEM contents. Injectable for testing and caching.
|
|
154
|
-
*/
|
|
153
|
+
* Resolves a signing-certificate URL to its PEM contents. Injectable for testing and caching.
|
|
154
|
+
*/
|
|
155
155
|
type CertificateResolver = (url: string) => Promise<string> | string;
|
|
156
156
|
/**
|
|
157
|
-
* Options for {@link verifySnsMessage}.
|
|
158
|
-
*/
|
|
157
|
+
* Options for {@link verifySnsMessage}.
|
|
158
|
+
*/
|
|
159
159
|
interface SnsVerifyOptions {
|
|
160
160
|
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
* Override how the signing certificate is fetched. Defaults to a `fetch`-based resolver that
|
|
162
|
+
* only accepts `https://*.amazonaws.com` URLs.
|
|
163
|
+
*/
|
|
164
164
|
certificateResolver?: CertificateResolver;
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
167
|
-
* Validates that a signing-certificate URL points at an AWS SNS signing host over HTTPS.
|
|
168
|
-
* @param url The `SigningCertURL` from the SNS message.
|
|
169
|
-
* @returns `true` when the URL is an acceptable AWS SNS certificate endpoint.
|
|
170
|
-
*/
|
|
167
|
+
* Validates that a signing-certificate URL points at an AWS SNS signing host over HTTPS.
|
|
168
|
+
* @param url The `SigningCertURL` from the SNS message.
|
|
169
|
+
* @returns `true` when the URL is an acceptable AWS SNS certificate endpoint.
|
|
170
|
+
*/
|
|
171
171
|
declare const isValidSigningCertUrl: (url: string) => boolean;
|
|
172
172
|
/**
|
|
173
|
-
* Verifies the RSA signature on an Amazon SNS message (used to wrap AWS SES events).
|
|
174
|
-
*
|
|
175
|
-
* Signature version `1` uses SHA1, version `2` uses SHA256. The signing certificate is fetched from
|
|
176
|
-
* `SigningCertURL` (validated to be an `sns.<region>.amazonaws.com` HTTPS endpoint with no userinfo
|
|
177
|
-
* or explicit port) unless a custom {@link CertificateResolver} is supplied.
|
|
178
|
-
* @param message The parsed SNS message envelope.
|
|
179
|
-
* @param options Optional overrides. See {@link SnsVerifyOptions}.
|
|
180
|
-
* @returns The verification result.
|
|
181
|
-
* @throws {EmailError} When the certificate cannot be resolved.
|
|
182
|
-
*/
|
|
173
|
+
* Verifies the RSA signature on an Amazon SNS message (used to wrap AWS SES events).
|
|
174
|
+
*
|
|
175
|
+
* Signature version `1` uses SHA1, version `2` uses SHA256. The signing certificate is fetched from
|
|
176
|
+
* `SigningCertURL` (validated to be an `sns.<region>.amazonaws.com` HTTPS endpoint with no userinfo
|
|
177
|
+
* or explicit port) unless a custom {@link CertificateResolver} is supplied.
|
|
178
|
+
* @param message The parsed SNS message envelope.
|
|
179
|
+
* @param options Optional overrides. See {@link SnsVerifyOptions}.
|
|
180
|
+
* @returns The verification result.
|
|
181
|
+
* @throws {EmailError} When the certificate cannot be resolved.
|
|
182
|
+
*/
|
|
183
183
|
declare const verifySnsMessage: (message: SnsMessage, options?: SnsVerifyOptions) => Promise<WebhookVerificationResult>;
|
|
184
184
|
/**
|
|
185
|
-
* Options for {@link verifyStandardWebhook}.
|
|
186
|
-
*/
|
|
185
|
+
* Options for {@link verifyStandardWebhook}.
|
|
186
|
+
*/
|
|
187
187
|
interface StandardWebhookOptions extends TimestampToleranceOptions {
|
|
188
188
|
/**
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
* The request headers, or the three signature headers as a plain record.
|
|
190
|
+
*
|
|
191
|
+
* Recognized header names (case-insensitive): `webhook-id` / `svix-id`,
|
|
192
|
+
* `webhook-timestamp` / `svix-timestamp`, and `webhook-signature` / `svix-signature`.
|
|
193
|
+
*/
|
|
194
194
|
headers: WebhookHeaders;
|
|
195
195
|
/**
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
* Override the current time (milliseconds) — primarily for testing.
|
|
197
|
+
*/
|
|
198
198
|
now?: number;
|
|
199
199
|
/**
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
* The raw, unparsed request body exactly as received.
|
|
201
|
+
*
|
|
202
|
+
* Parsing and re-serializing the body changes the bytes and breaks verification.
|
|
203
|
+
*/
|
|
204
204
|
payload: string;
|
|
205
205
|
/**
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
* The signing secret. Supports the `whsec_`-prefixed, base64-encoded form used by Svix/Resend,
|
|
207
|
+
* or a raw secret string.
|
|
208
|
+
*/
|
|
209
209
|
secret: string;
|
|
210
210
|
}
|
|
211
211
|
/**
|
|
212
|
-
* Verifies a webhook signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) spec.
|
|
213
|
-
*
|
|
214
|
-
* This is the scheme used by Svix and, by extension, Resend. The signed content is
|
|
215
|
-
* `${id}.${timestamp}.${payload}`, HMAC-SHA256'd with the (base64-decoded) secret and base64-encoded.
|
|
216
|
-
* The `webhook-signature` header may contain multiple space-separated `v1,<sig>` entries; a match
|
|
217
|
-
* against any one of them passes.
|
|
218
|
-
* @param options Verification inputs. See {@link StandardWebhookOptions}.
|
|
219
|
-
* @returns The verification result.
|
|
220
|
-
*/
|
|
212
|
+
* Verifies a webhook signed according to the [Standard Webhooks](https://www.standardwebhooks.com/) spec.
|
|
213
|
+
*
|
|
214
|
+
* This is the scheme used by Svix and, by extension, Resend. The signed content is
|
|
215
|
+
* `${id}.${timestamp}.${payload}`, HMAC-SHA256'd with the (base64-decoded) secret and base64-encoded.
|
|
216
|
+
* The `webhook-signature` header may contain multiple space-separated `v1,<sig>` entries; a match
|
|
217
|
+
* against any one of them passes.
|
|
218
|
+
* @param options Verification inputs. See {@link StandardWebhookOptions}.
|
|
219
|
+
* @returns The verification result.
|
|
220
|
+
*/
|
|
221
221
|
declare const verifyStandardWebhook: (options: StandardWebhookOptions) => WebhookVerificationResult;
|
|
222
222
|
/**
|
|
223
|
-
* Verifies a [Resend](https://resend.com/docs/dashboard/webhooks/verify-webhooks-requests) webhook.
|
|
224
|
-
*
|
|
225
|
-
* Resend uses Svix, so this is an alias for {@link verifyStandardWebhook} that accepts the
|
|
226
|
-
* `svix-*` headers.
|
|
227
|
-
* @param options Verification inputs. See {@link StandardWebhookOptions}.
|
|
228
|
-
* @returns The verification result.
|
|
229
|
-
*/
|
|
223
|
+
* Verifies a [Resend](https://resend.com/docs/dashboard/webhooks/verify-webhooks-requests) webhook.
|
|
224
|
+
*
|
|
225
|
+
* Resend uses Svix, so this is an alias for {@link verifyStandardWebhook} that accepts the
|
|
226
|
+
* `svix-*` headers.
|
|
227
|
+
* @param options Verification inputs. See {@link StandardWebhookOptions}.
|
|
228
|
+
* @returns The verification result.
|
|
229
|
+
*/
|
|
230
230
|
declare const verifyResendWebhook: (options: StandardWebhookOptions) => WebhookVerificationResult;
|
|
231
231
|
export { type CertificateResolver, type MailgunWebhookOptions, type PostmarkWebhookOptions, type SendGridWebhookOptions, type SnsMessage, type SnsVerifyOptions, type StandardWebhookOptions, type TimestampToleranceOptions, type WebhookHeaders, type WebhookVerificationResult, isValidSigningCertUrl, verifyMailgunWebhook, verifyPostmarkWebhook, verifyResendWebhook, verifySendGridWebhook, verifySnsMessage, verifyStandardWebhook };
|
package/dist/webhooks/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{verifyMailgunWebhook as r}from"../packem_shared/verifyMailgunWebhook-
|
|
1
|
+
import{verifyMailgunWebhook as r}from"../packem_shared/verifyMailgunWebhook-DNk080BF.js";import{verifyPostmarkWebhook as f}from"../packem_shared/verifyPostmarkWebhook-B4OIEHQF.js";import{verifySendGridWebhook as n}from"../packem_shared/verifySendGridWebhook-1l9bqIMw.js";import{isValidSigningCertUrl as d,verifySnsMessage as k}from"../packem_shared/isValidSigningCertUrl-DNxPA0Q-.js";import{verifyResendWebhook as s,verifyStandardWebhook as v}from"../packem_shared/verifyResendWebhook-C7E32LZ1.js";export{d as isValidSigningCertUrl,r as verifyMailgunWebhook,f as verifyPostmarkWebhook,s as verifyResendWebhook,n as verifySendGridWebhook,k as verifySnsMessage,v as verifyStandardWebhook};
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as g}from"node:module";const h=g(import.meta.url),t=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,d=s=>{if(typeof t<"u"&&t.versions&&t.versions.node){const[e,r]=t.versions.node.split(".").map(Number);if(e>22||e===22&&r>=3||e===20&&r>=16)return t.getBuiltinModule(s)}return h(s)},{createRequire:l}=d("node:module"),E=new Map([["Error",Error],["EvalError",EvalError],["RangeError",RangeError],["ReferenceError",ReferenceError],["SyntaxError",SyntaxError],["TypeError",TypeError],["URIError",URIError]]);typeof AggregateError<"u"&&E.set("AggregateError",AggregateError);const f=l(import.meta.url),i=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,y=s=>{if(typeof i<"u"&&i.versions&&i.versions.node){const[e,r]=i.versions.node.split(".").map(Number);if(e>22||e===22&&r>=3||e===20&&r>=16)return i.getBuiltinModule(s)}return f(s)};y("node:util");class b extends Error{loc;title;hint;type="VisulimaError";constructor({cause:e,hint:r,location:o,message:c,name:u,stack:p,title:m}){super(c,{cause:e}),this.title=m,this.name=u,this.stack=p??this.stack,this.loc=o,this.hint=r}setLocation(e){this.loc=e}setName(e){this.name=e}setMessage(e){this.message=e}setHint(e){this.hint=e}}const v=l(import.meta.url),n=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,a=s=>{if(typeof n<"u"&&n.versions&&n.versions.node){const[e,r]=n.versions.node.split(".").map(Number);if(e>22||e===22&&r>=3||e===20&&r>=16)return n.getBuiltinModule(s)}return v(s)};a("node:fs");a("node:path");a("node:url");let T=class extends b{component;code;constructor(e,r,o){super({cause:o?.cause,hint:o?.hint,message:`[@visulima/email] [${e}] ${r}`,name:"EmailError",title:`Email ${e} Error`}),this.component=e,this.code=o?.code}};export{T as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as f}from"node:module";import{readFileAsBuffer as c,detectMimeType as d,generateContentId as u}from"./detectMimeType-DFH3kp6K.js";import{c as b}from"./create-logger-BQTS3f-I.js";import{s as l}from"./headers-to-record-De1Eg951.js";const y=f(import.meta.url),o=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,p=n=>{if(typeof o<"u"&&o.versions&&o.versions.node){const[t,e]=o.versions.node.split(".").map(Number);if(t>22||t===22&&e>=3||t===20&&e>=16)return o.getBuiltinModule(n)}return y(n)},{basename:g}=p("node:path"),{fileURLToPath:A}=p("node:url"),m=async()=>(await import("../template-engines/html-to-text.js")).default,T=async()=>(await import("ical-generator")).default,a=n=>Array.isArray(n)?n.map(t=>typeof t=="string"?{email:t}:t):typeof n=="string"?[{email:n}]:[n];class v{fromAddress;toAddresses=[];ccAddresses=[];bccAddresses=[];subjectText="";textContent;textCharset="utf8";autoTextEnabled=!0;htmlContent;htmlCharset="utf8";dateValue;returnPathAddress;senderAddress;headers={};attachments=[];replyToAddress;priorityValue;tagsValue=[];signer;encrypter;logger;icalEventData;icalEventBuilder;from(t){return this.fromAddress=typeof t=="string"?{email:t}:t,this}to(t){return this.toAddresses.length=0,this.toAddresses.push(...a(t)),this}cc(t){return this.ccAddresses.length=0,this.ccAddresses.push(...a(t)),this}bcc(t){return this.bccAddresses.length=0,this.bccAddresses.push(...a(t)),this}subject(t){return this.subjectText=t,this}text(t,e="utf8"){return this.textContent=t,this.textCharset=e,this}html(t,e="utf8"){return this.htmlContent=t,this.htmlCharset=e,this}header(t,e){return this.headers[t]=e,this}setHeaders(t){const e=l(t);return Object.assign(this.headers,e),this}async attachFromPath(t,e){try{const s=await c(t),i=e?.filename??(g(t)||"attachment"),r=e?.contentType??d(i);this.attachments.push({cid:e?.cid,content:s,contentDisposition:e?.contentDisposition??"attachment",contentType:r,encoding:e?.encoding,filename:i,headers:e?.headers}),this.logger&&this.logger.debug(`Attachment added from path: ${t}`,{contentType:r,filename:i})}catch(s){throw this.logger&&this.logger.error(`Failed to attach file from path: ${t}`,s),s}return this}attachData(t,e){const s=e.contentType??d(e.filename);return this.attachments.push({cid:e.cid,content:t,contentDisposition:e.contentDisposition??"attachment",contentType:s,encoding:e.encoding,filename:e.filename,headers:e.headers}),this.logger&&this.logger.debug("Attachment added from data",{contentType:s,filename:e.filename}),this}async embedFromPath(t,e){try{const s=await c(t),i=e?.filename??(g(t)||"inline"),r=e?.contentType??d(i),h=u(i);return this.attachments.push({cid:h,content:s,contentDisposition:"inline",contentType:r,filename:i}),this.logger&&this.logger.debug(`Inline attachment embedded from path: ${t}`,{cid:h,contentType:r,filename:i}),h}catch(s){throw this.logger&&this.logger.error(`Failed to embed file from path: ${t}`,s),s}}embedData(t,e,s){const i=s?.contentType??d(e),r=u(e);return this.attachments.push({cid:r,content:t,contentDisposition:"inline",contentType:i,filename:e}),this.logger&&this.logger.debug("Inline attachment embedded from data",{cid:r,contentType:i,filename:e}),r}replyTo(t){return this.replyToAddress=typeof t=="string"?{email:t}:t,this}date(t){return this.dateValue=typeof t=="string"?new Date(t):t,this.logger&&this.logger.debug("Date header set",{date:this.dateValue.toISOString()}),this}returnPath(t){return this.returnPathAddress=typeof t=="string"?{email:t}:t,this.logger&&this.logger.debug("Return-path address set",{returnPath:this.returnPathAddress.email}),this}sender(t){return this.senderAddress=typeof t=="string"?{email:t}:t,this.logger&&this.logger.debug("Sender address set",{sender:this.senderAddress.email}),this}addTo(t){return this.toAddresses.push(...a(t)),this}addCc(t){return this.ccAddresses.push(...a(t)),this}addBcc(t){return this.bccAddresses.push(...a(t)),this}addReplyTo(t){const e=Array.isArray(t)?t:[t];if(e.length>0){const s=e[0];this.replyToAddress=typeof s=="string"?{email:s}:s}return this}addFrom(t){const e=Array.isArray(t)?t:[t];if(e.length>0){const s=e[0];this.fromAddress=typeof s=="string"?{email:s}:s}return this}priority(t){return this.priorityValue=t,this}tags(t){return this.tagsValue=Array.isArray(t)?t:[t],this}sign(t){return this.signer=t,this.logger&&this.logger.debug("Email signer configured"),this}encrypt(t){return this.encrypter=t,this.logger&&this.logger.debug("Email encrypter configured"),this}setLogger(t){return this.logger=b("MailMessage",t),this}icalEvent(t,e){return typeof t=="function"?(this.icalEventBuilder={build:t,options:e},this.icalEventData=void 0):(this.icalEventBuilder=void 0,this.icalEventData={content:t,...e}),this.logger&&this.logger.debug("Calendar event attached",{method:e?.method}),this}icalEventFromFile(t,e){const s=typeof t=="string"?t:A(t);return this.icalEventData={path:s,...e},this.logger&&this.logger.debug(`Calendar event attached from file: ${s}`,{method:e?.method}),this}icalEventFromUrl(t,e){return this.icalEventData={href:t,...e},this.logger&&this.logger.debug(`Calendar event attached from URL: ${t}`,{method:e?.method}),this}async view(t,e,s,i){try{const r=i?.autoText!==!1;this.autoTextEnabled=r,this.logger&&this.logger.debug("Rendering template",{autoText:r});const h=await t(e,s,i);this.html(h),r&&h&&await this.tryAutoGenerateText(h),this.logger&&this.logger.debug("Template rendered successfully")}catch(r){throw this.logger&&this.logger.error("Failed to render template",r),new Error(`Failed to render template: ${r.message}`)}return this}async viewText(t,e,s,i){try{this.logger&&this.logger.debug("Rendering text template");const r=await t(e,s,i);if(typeof r=="string")this.text(r),this.logger&&this.logger.debug("Text template rendered successfully");else throw new TypeError("Text renderer must return a string")}catch(r){throw this.logger&&this.logger.error("Failed to render text template",r),new Error(`Failed to render text template: ${r.message}`)}return this}async build(){if(this.logger&&this.logger.debug("Building email message"),this.fromAddress||this.throwAndLogError("From address is required","Build failed: from address is required"),this.toAddresses.length===0&&this.throwAndLogError("At least one recipient is required","Build failed: at least one recipient is required"),this.subjectText||this.throwAndLogError("Subject is required","Build failed: subject is required"),this.htmlContent&&!this.textContent&&this.autoTextEnabled)try{const e=await m();this.textContent=e(this.htmlContent),this.logger&&this.logger.debug("Auto-generated text content from HTML")}catch{this.logger&&this.logger.debug("Failed to convert HTML to text; proceeding without text content.")}!this.textContent&&!this.htmlContent&&this.throwAndLogError("Either text or html content is required","Build failed: either text or html content is required");let t={from:this.fromAddress,html:this.htmlContent,subject:this.subjectText,text:this.textContent,to:this.toAddresses.length===1?this.toAddresses[0]:this.toAddresses};if(this.ccAddresses.length>0&&(t.cc=this.ccAddresses.length===1?this.ccAddresses[0]:this.ccAddresses),this.bccAddresses.length>0&&(t.bcc=this.bccAddresses.length===1?this.bccAddresses[0]:this.bccAddresses),Object.keys(this.headers).length>0&&(t.headers=this.headers),this.attachments.length>0&&(t.attachments=this.attachments,this.logger&&this.logger.debug(`Email includes ${this.attachments.length} attachment(s)`)),this.replyToAddress&&(t.replyTo=this.replyToAddress),this.priorityValue&&(t.priority=this.priorityValue),this.tagsValue.length>0&&(t.tags=this.tagsValue),this.icalEventBuilder){const e=(await T())();this.icalEventBuilder.build(e),this.icalEventData={content:e.toString(),...this.icalEventBuilder.options}}return this.icalEventData&&(t.icalEvent=this.icalEventData,this.logger&&this.logger.debug("Email includes calendar event")),this.dateValue&&(t.headers={...l(t.headers??{}),Date:this.dateValue.toUTCString()}),this.returnPathAddress&&(t.headers={...l(t.headers??{}),"Return-Path":this.returnPathAddress.email}),this.senderAddress&&(t.headers={...l(t.headers??{}),Sender:this.senderAddress.email}),this.signer&&(this.logger&&this.logger.debug("Signing email message"),t=await this.signer.sign(t),this.logger&&this.logger.debug("Email message signed successfully")),this.encrypter&&(this.logger&&this.logger.debug("Encrypting email message"),t=await this.encrypter.encrypt(t),this.logger&&this.logger.debug("Email message encrypted successfully")),this.logger&&this.logger.debug("Email message built successfully",{bcc:this.bccAddresses.length,cc:this.ccAddresses.length,hasHtml:!!this.htmlContent,hasText:!!this.textContent,to:this.toAddresses.length}),t}getSubject(){return this.subjectText}getFrom(){return this.fromAddress}getTo(){return[...this.toAddresses]}getCc(){return[...this.ccAddresses]}getBcc(){return[...this.bccAddresses]}getReplyTo(){return this.replyToAddress}getSender(){return this.senderAddress}getReturnPath(){return this.returnPathAddress}getDate(){return this.dateValue}getPriority(){return this.priorityValue}getTextBody(){return this.textContent}getTextCharset(){return this.textCharset}getHtmlBody(){return this.htmlContent}getHtmlCharset(){return this.htmlCharset}getAttachments(){return[...this.attachments]}async tryAutoGenerateText(t){try{const e=(await m())(t);e&&!this.textContent&&this.text(e),this.logger&&this.logger.debug("Auto-generated text content from HTML template")}catch(e){this.logger&&this.logger.warn("Failed to auto-generate text from HTML template",e)}}throwAndLogError(t,e){const s=new Error(t);throw this.logger&&this.logger.error(e??t),s}}export{v as default};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{createRequire as O}from"node:module";import{z as I}from"./index-BoZvzveg.js";import{fromBER as B,OctetString as E}from"asn1js";import{Certificate as $,EnvelopedData as L,EncryptedContentInfo as G,id_ContentType_Data as z,RecipientInfo as V,KeyTransRecipientInfo as J,IssuerAndSerialNumber as Q,AlgorithmIdentifier as S,ContentInfo as W,id_ContentType_EnvelopedData as X}from"pkijs";const F=O(import.meta.url),h=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,K=a=>{if(typeof h<"u"&&h.versions&&h.versions.node){const[e,t]=h.versions.node.split(".").map(Number);if(e>22||e===22&&t>=3||e===20&&t>=16)return h.getBuiltinModule(a)}return F(a)},{randomBytes:v,createCipheriv:U,createPublicKey:q,publicEncrypt:H}=K("node:crypto"),b=globalThis.Buffer!==void 0,j=a=>{const e=a.replaceAll(/-----BEGIN[^-]+-----/g,"").replaceAll(/-----END[^-]+-----/g,"").replaceAll(/\s/g,"");if(b)return Buffer.from(e,"base64");const t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r+=1)n[r]=t.charCodeAt(r);return n},x=(a,e)=>{let t;if(b)t=Buffer.from(a).toString("base64");else{const r=new Uint8Array(a);let u="";const s=8192;for(let o=0;o<r.length;o+=s){const d=r.subarray(o,Math.min(o+s,r.length));u+=String.fromCharCode(...d)}t=btoa(u)}const n=t.match(/.{1,64}/g)??[];return`-----BEGIN ${e}-----
|
|
2
|
-
${n.join(`
|
|
3
|
-
`)}
|
|
4
|
-
-----END ${e}-----
|
|
5
|
-
`};class i{static collectRecipients(e){const t=[],n=r=>{if(!r)return;const u=Array.isArray(r)?r:[r];for(const s of u){const o=typeof s=="string"?s:s.email;o&&t.push(o)}};return n(e.to),n(e.cc),n(e.bcc),[...new Set(t)]}static formatAddress(e){return typeof e=="string"?e:e.name?`"${e.name}" <${e.email}>`:e.email}static formatAddresses(e){return(Array.isArray(e)?e:[e]).map(t=>i.formatAddress(t)).join(", ")}options;constructor(e){this.options=e}async encrypt(e){const t=i.collectRecipients(e),n=[];if(typeof this.options.certificates=="string"){const c=await I(this.options.certificates,{encoding:"utf8"}),f=j(c),l=B(f);if(l.offset===-1)throw new Error("Failed to parse certificate: Invalid ASN.1 structure");n.push(new $({schema:l.result}))}else{const c=t.map(async f=>{const l=this.options.certificates[f];if(!l)throw new Error(`No certificate found for recipient: ${f}`);const C=await I(l,{encoding:"utf8"}),A=j(C),p=B(A);if(p.offset===-1)throw new Error(`Failed to parse certificate for ${f}: Invalid ASN.1 structure`);return new $({schema:p.result})});n.push(...await Promise.all(c))}const r=await this.buildMessage(e),u=new TextEncoder().encode(r),s=new L({version:0});s.encryptedContentInfo=new G({contentType:z});const o=(this.options.algorithm??"aes-256-cbc").toLowerCase();if(o==="3des"||o==="des-ede3-cbc")throw new Error("3DES/DES-EDE3-CBC is deprecated and insecure (Sweet32 vulnerability). Please use AES-256-CBC, AES-192-CBC, or AES-128-CBC instead.");let d,m;switch(o){case"aes128":case"aes-128-cbc":{d="2.16.840.1.101.3.4.1.2",m=16;break}case"aes192":case"aes-192-cbc":{d="2.16.840.1.101.3.4.1.22",m=24;break}default:{d="2.16.840.1.101.3.4.1.42",m=32;break}}const g=v(m),N=b?g:new Uint8Array(g),w=v(16),R=b?w:new Uint8Array(w),T=U(`aes-${m*8}-cbc`,g,w),D=Buffer.from(u),_=[T.update(D),T.final()],y=Buffer.concat(_);s.encryptedContentInfo.encryptedContent=new E({valueHex:y.buffer.slice(y.byteOffset,y.byteOffset+y.byteLength)});const P=await Promise.all(n.map(async c=>{const f=c.toSchema().toBER(!1),l=x(f,"CERTIFICATE"),C=q(l),A=Buffer.from(N),p=H({key:C,padding:1},A);return new V({value:new J({encryptedKey:new E({valueHex:p.buffer.slice(p.byteOffset,p.byteOffset+p.byteLength)}),keyEncryptionAlgorithm:new S({algorithmId:"1.2.840.113549.1.1.1"}),rid:new Q({issuer:c.issuer,serialNumber:c.serialNumber}),version:0}),variant:0})}));s.recipientInfos.push(...P),s.encryptedContentInfo.contentEncryptionAlgorithm=new S({algorithmId:d,algorithmParams:new E({valueHex:R.buffer})});const k=new W({content:s.toSchema(),contentType:X}).toSchema().toBER(!1),M=x(k,"PKCS7");return{...e,headers:{...e.headers,"Content-Disposition":"attachment; filename=smime.p7m","Content-Transfer-Encoding":"base64","Content-Type":"application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"},html:void 0,text:M}}async buildMessage(e){const t=[`From: ${i.formatAddress(e.from)}`,`To: ${i.formatAddresses(e.to)}`,...e.cc?[`Cc: ${i.formatAddresses(e.cc)}`]:[]];if(e.replyTo&&t.push(`Reply-To: ${i.formatAddress(e.replyTo)}`),t.push(`Subject: ${e.subject}`,"MIME-Version: 1.0"),e.headers)for(const[n,r]of Object.entries(e.headers))t.push(`${n}: ${r}`);return e.html?t.push("Content-Type: text/html; charset=utf-8"):e.text&&t.push("Content-Type: text/plain; charset=utf-8"),t.push(""),e.html?t.push(e.html):e.text&&t.push(e.text),t.join(`\r
|
|
6
|
-
`)}}const re=a=>new i(a);export{i as SmimeEncrypter,re as createSmimeEncrypter};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{createRequire as q}from"node:module";import{z as y}from"./index-BoZvzveg.js";import{fromBER as I,ObjectIdentifier as Q,OctetString as x,UTCTime as W}from"asn1js";import{Certificate as E,SignedData as X,EncapsulatedContentInfo as Y,id_ContentType_Data as B,SignerInfo as Z,AlgorithmIdentifier as N,IssuerAndSerialNumber as ee,id_sha256 as te,SignedAndUnsignedAttributes as ne,Attribute as w,ContentInfo as re,id_ContentType_SignedData as se}from"pkijs";import{r as oe}from"./generate-boundary-DQbzDiOI.js";const G=q(import.meta.url),u=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,z=o=>{if(typeof u<"u"&&u.versions&&u.versions.node){const[e,t]=u.versions.node.split(".").map(Number);if(e>22||e===22&&t>=3||e===20&&t>=16)return u.getBuiltinModule(o)}return G(o)},{createPrivateKey:j,createHash:L,createSign:V,randomBytes:J}=z("node:crypto"),ie="1.2.840.113549.1.9.3",ae="1.2.840.113549.1.9.4",ce="1.2.840.113549.1.9.5",le="1.2.840.113549.1.1.1",pe={v1:1},ue={v1:1},f=globalThis.Buffer!==void 0,D=o=>{const e=o.replaceAll(/-----BEGIN[^-]+-----/g,"").replaceAll(/-----END[^-]+-----/g,"").replaceAll(/\s/g,"");if(f)return Buffer.from(e,"base64");const t=atob(e),s=new Uint8Array(t.length);for(let n=0;n<t.length;n+=1)s[n]=t.codePointAt(n);return s},fe=(o,e)=>{let t;if(f)t=Buffer.from(o).toString("base64");else{const n=new Uint8Array(o);let r="";const a=8192;for(let i=0;i<n.length;i+=a){const d=n.subarray(i,Math.min(i+a,n.length));r+=String.fromCharCode(...d)}t=btoa(r)}const s=t.match(/.{1,64}/g)??[];return`-----BEGIN ${e}-----
|
|
2
|
-
${s.join(`
|
|
3
|
-
`)}
|
|
4
|
-
-----END ${e}-----
|
|
5
|
-
`};class m{static formatAddress(e){return e.name?`"${e.name.replaceAll("\\","\\\\").replaceAll('"',String.raw`\"`)}" <${e.email}>`:e.email}options;constructor(e){this.options=e}async sign(e){const t=await y(this.options.certificate,{encoding:"utf8"}),s=await y(this.options.privateKey,{encoding:"utf8"}),n=D(t),r=I(n);if(r.offset===-1)throw new Error("Failed to parse certificate: Invalid ASN.1 structure");const a=new E({schema:r.result});let i;try{i=this.options.passphrase?j({key:s,passphrase:this.options.passphrase}):j(s)}catch(c){throw new Error(`Failed to parse private key: ${c.message}`)}const d=[];if(this.options.intermediateCerts){const c=this.options.intermediateCerts.map(async S=>{const H=await y(S,{encoding:"utf8"}),K=D(H),_=I(K);if(_.offset===-1)throw new Error(`Failed to parse intermediate certificate ${S}: Invalid ASN.1 structure`);return new E({schema:_.result})});d.push(...await Promise.all(c))}const b=this.buildMessage(e),A=new TextEncoder().encode(b),h=new X({version:pe.v1});h.encapContentInfo=new Y({eContentType:B});const g=new Z({digestAlgorithm:new N({algorithmId:te}),sid:new ee({issuer:a.issuer,serialNumber:a.serialNumber}),signatureAlgorithm:new N({algorithmId:le}),version:ue.v1}),$=L("sha256");$.update(f?Buffer.from(A):A);const M=$.digest(),R=new Uint8Array(M),C=new ne({attributes:[new w({type:ie,values:[new Q({value:B})]}),new w({type:ae,values:[new x({valueHex:R.buffer.slice(0)})]}),new w({type:ce,values:[new W({valueDate:new Date})]})]});g.signedAttrs=C;const T=C.toSchema().toBER(!1),P=f?Buffer.from(T):new Uint8Array(T),v=V("RSA-SHA256");v.update(P);const l=v.sign(i),U=f?l.buffer.slice(l.byteOffset,l.byteOffset+l.byteLength):l.buffer;g.signature=new x({valueHex:U}),h.signerInfos.push(g),h.certificates=[a,...d];const k=new re({content:h.toSchema(),contentType:se}).toSchema().toBER(!1),O=fe(k,"PKCS7"),p=`----_=_NextPart_${Date.now()}_${J(8).toString("hex")}`,F=[`Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="${p}"`,"",`--${p}`,b,`--${p}`,"Content-Type: application/pkcs7-signature; name=smime.p7s","Content-Transfer-Encoding: base64","Content-Disposition: attachment; filename=smime.p7s","",O.split(`
|
|
6
|
-
`).filter(c=>c.trim()&&!c.includes("-----")).join(""),`--${p}--`].join(`\r
|
|
7
|
-
`);return{...e,headers:{...e.headers,"Content-Type":`multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="${p}"`},html:void 0,text:F}}buildMessage(e){const t=[`From: ${m.formatAddress(e.from)}`,`To: ${this.formatAddresses(e.to)}`];if(e.cc&&t.push(`Cc: ${this.formatAddresses(e.cc)}`),e.replyTo&&t.push(`Reply-To: ${m.formatAddress(e.replyTo)}`),t.push(`Subject: ${e.subject}`,"MIME-Version: 1.0"),e.headers)for(const[a,i]of Object.entries(e.headers))t.push(`${a}: ${i}`);const s=!!e.text,n=!!e.html;let r;return s&&n?(r=oe(),t.push(`Content-Type: multipart/alternative; boundary="${r}"`)):n?t.push("Content-Type: text/html; charset=utf-8"):t.push("Content-Type: text/plain; charset=utf-8"),t.push(""),s&&n&&r?t.push(`--${r}`,"Content-Type: text/plain; charset=utf-8","",e.text,"",`--${r}`,"Content-Type: text/html; charset=utf-8","",e.html,"",`--${r}--`):s?t.push(e.text):n&&t.push(e.html),t.join(`\r
|
|
8
|
-
`)}formatAddresses(e){return(Array.isArray(e)?e:[e]).map(t=>m.formatAddress(t)).join(", ")}}const we=o=>new m(o);export{m as SmimeSigner,we as createSmimeSigner};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import{createRequire as E}from"node:module";import{z as W}from"./index-BoZvzveg.js";import{s as x}from"./headers-to-record-De1Eg951.js";import{f as b}from"./format-address-DTl-9O70.js";const q=E(import.meta.url),g=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,B=s=>{if(typeof g<"u"&&g.versions&&g.versions.node){const[e,r]=g.versions.node.split(".").map(Number);if(e>22||e===22&&r>=3||e===20&&r>=16)return g.getBuiltinModule(s)}return q(s)},{Buffer:j}=B("node:buffer"),{createPublicKey:N,createHash:v,createPrivateKey:z,sign:D,createSign:P,verify:R}=B("node:crypto"),H=/\s+/g,F=/ $/,I=/^\s*i=(\d+)\s*;/,V=["from","to","cc","subject","date","message-id","mime-version"],u=(s,e)=>`${s.toLowerCase()}:${e.replaceAll(H," ").trim()}`,G=s=>{let e=s.replaceAll(`\r
|
|
2
|
-
`,`
|
|
3
|
-
`).replaceAll("\r",`
|
|
4
|
-
`).split(`
|
|
5
|
-
`).map(r=>r.replaceAll(H," ").replace(F,"")).join(`\r
|
|
6
|
-
`);for(;e.endsWith(`\r
|
|
7
|
-
`);)e=e.slice(0,-2);return e.length>0?`${e}\r
|
|
8
|
-
`:`\r
|
|
9
|
-
`},k=s=>{const e={...s.headers?x(s.headers):{},From:b(s.from),Subject:s.subject,To:b(s.to)};return s.cc&&(e.Cc=b(s.cc)),e["MIME-Version"]??="1.0",e},C=s=>{const e={};for(const r of s.split(";")){const a=r.indexOf("=");a!==-1&&(e[r.slice(0,a).trim()]=r.slice(a+1).trim())}return e},w=s=>{const e=s.lastIndexOf("b=");return e===-1?s:s.slice(0,e+2)},K=s=>{const e=[s.text,s.html].filter(r=>r!==void 0).join(`
|
|
10
|
-
|
|
11
|
-
`);return v("sha256").update(G(e)).digest("base64")},M=(s,e,r)=>r==="ed25519-sha256"?D(null,v("sha256").update(s).digest(),e).toString("base64"):P("RSA-SHA256").update(s).sign(e,"base64"),_=(s,e,r,a)=>{const t=j.from(e,"base64");try{return a==="ed25519-sha256"?R(null,v("sha256").update(s).digest(),r,t):R("RSA-SHA256",j.from(s),r,t)}catch{return!1}},J=(s,e)=>{const r=e.instance??1,a=e.algorithm??"rsa-sha256",t=e.timestamp??Math.floor(Date.now()/1e3),n=k(s),l=(e.headersToSign??V).filter(i=>{const d=Object.keys(n).find(h=>h.toLowerCase()===i);return d!==void 0&&n[d]!==void 0&&n[d]!==""}),c=[`i=${String(r)}`,`a=${a}`,"c=relaxed/relaxed",`d=${e.domainName}`,`s=${e.keySelector}`,`t=${String(t)}`,`h=${l.join(":")}`,`bh=${K(s)}`,"b="].join("; "),o=`${l.map(i=>{const d=Object.keys(n).find(h=>h.toLowerCase()===i);return u(i,n[d]??"")}).join(`\r
|
|
12
|
-
`)}\r
|
|
13
|
-
${u("ARC-Message-Signature",c)}`;return{header:c,signBase:o}},U=(s,e,r)=>{const a=r.instance??1,t=r.algorithm??"rsa-sha256",n=r.timestamp??Math.floor(Date.now()/1e3),l=r.cv??"none",c=[`i=${String(a)}`,`a=${t}`,`cv=${l}`,`d=${r.domainName}`,`s=${r.keySelector}`,`t=${String(n)}`,"b="].join("; "),o=[u("ARC-Authentication-Results",s),u("ARC-Message-Signature",e),u("ARC-Seal",c)].join(`\r
|
|
14
|
-
`);return{header:c,signBase:o}},Q=async(s,e)=>{let r=s;return r.startsWith("file://")&&(r=await W(r.slice(7),{encoding:"utf8"})),z({key:r,passphrase:e})},se=async(s,e)=>{const r=e.instance??1,a=e.cv??"none";if(r!==1)throw new Error(`signArc only supports an originating sealer (instance 1); received i=${String(r)}`);if(a!=="none")throw new Error(`signArc only supports cv=none for an originating sealer; received cv=${a}`);const t=e.algorithm??"rsa-sha256",n={...e,cv:"none",timestamp:e.timestamp??Math.floor(Date.now()/1e3)},l=await Q(e.privateKey,e.passphrase),c=`i=${String(r)}; ${e.authenticationResults}`,o=J(s,n),i=`${o.header}${M(o.signBase,l,t)}`,d=U(c,i,n),h=`${d.header}${M(d.signBase,l,t)}`,m={"ARC-Authentication-Results":c,"ARC-Message-Signature":i,"ARC-Seal":h};return{email:{...s,headers:{...s.headers?x(s.headers):{},...m}},headers:m}},re=(s,e,r)=>{const a=Object.fromEntries(Object.entries(e).map(([f,p])=>[f.toLowerCase(),p])),t=a["arc-message-signature"],n=a["arc-seal"],l=a["arc-authentication-results"];if(!t||!n||!l)return{components:{ams:!1,bodyHash:!1,seal:!1},reason:"missing-arc-headers",valid:!1};let c;try{c=typeof r.publicKey=="string"?N(r.publicKey):r.publicKey}catch{return{components:{ams:!1,bodyHash:!1,seal:!1},reason:"invalid-public-key",valid:!1}}const o=C(t),i=C(n);if(I.exec(l)?.[1]!=="1"||o.i!=="1"||i.i!=="1"||i.cv!=="none")return{components:{ams:!1,bodyHash:!1,seal:!1},cv:i.cv,reason:"unsupported-arc-instance",valid:!1};const d=o.a==="ed25519-sha256"?"ed25519-sha256":"rsa-sha256",h=i.a==="ed25519-sha256"?"ed25519-sha256":"rsa-sha256",m=o.bh!==void 0&&o.bh===K(s),y=k(s),O=`${(o.h??"").split(":").map(f=>f.trim().toLowerCase()).filter(Boolean).map(f=>{const p=Object.keys(y).find(T=>T.toLowerCase()===f);return u(f,p?y[p]??"":"")}).join(`\r
|
|
15
|
-
`)}\r
|
|
16
|
-
${u("ARC-Message-Signature",w(t))}`,A=_(O,o.b??"",c,d),L=[u("ARC-Authentication-Results",l),u("ARC-Message-Signature",t),u("ARC-Seal",w(n))].join(`\r
|
|
17
|
-
`),S=_(L,i.b??"",c,h),$=A&&S&&m;return{components:{ams:A,bodyHash:m,seal:S},cv:i.cv,reason:$?void 0:"signature-mismatch",valid:$}};export{J as arcMessageSignatureBase,U as arcSealBase,se as signArc,re as verifyArc};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as c}from"node:module";import m from"./EmailError-B-sEf3bp.js";const s=c(import.meta.url),o=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,r=e=>{if(typeof o<"u"&&o.versions&&o.versions.node){const[t,n]=o.versions.node.split(".").map(Number);if(t>22||t===22&&n>=3||t===20&&n>=16)return o.getBuiltinModule(e)}return s(e)},{Buffer:p}=r("node:buffer"),a=async(e,t)=>{let n;if(e.content)if(typeof e.content=="string")n=e.content;else if(e.content instanceof Promise){const i=await e.content;n=p.from(i).toString("base64")}else n=e.content.toString("base64");else if(e.raw)n=typeof e.raw=="string"?e.raw:e.raw.toString("base64");else throw new m(t,`Attachment ${e.filename} has no content`);return n},d=async(e,t)=>({content:await a(e,t),contentType:e.contentType??"application/octet-stream",disposition:e.contentDisposition??"attachment",filename:e.filename,...e.cid&&{contentId:e.cid}}),u=async(e,t)=>({content:await a(e,t),disposition:e.contentDisposition??"attachment",filename:e.filename,type:e.contentType??"application/octet-stream",...e.cid&&{content_id:e.cid}}),y=async(e,t)=>({Content:await a(e,t),ContentType:e.contentType??"application/octet-stream",Name:e.filename,...e.cid&&{ContentID:e.cid}}),h=async(e,t,n)=>({content:await a(e,t),key:`attachment[${n}]`});export{h as a,y as b,d as c,u as d,a as p};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as A}from"node:module";import l from"./EmailError-B-sEf3bp.js";import w from"./RequiredOptionError-DuNNY_a5.js";import{e as I}from"./generate-message-id-gXAuMz4g.js";import{s as P}from"./headers-to-record-De1Eg951.js";import{m as h}from"./make-request-B9XjBynA.js";import{i as v}from"./retry-ipI5DRJ8.js";import{f as j}from"./validate-email-options-mCM9dVug.js";import{defineProvider as _}from"./defineProvider-C9q-7iwt.js";import{P as B,h as T,c as C}from"./provider-base-C7PuopYK.js";import{b as y,c as E}from"./address-formatter-BWR2Dddx.js";const z=A(import.meta.url),f=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,k=n=>{if(typeof f<"u"&&f.versions&&f.versions.node){const[u,t]=f.versions.node.split(".").map(Number);if(u>22||u===22&&t>=3||u===20&&t>=16)return f.getBuiltinModule(n)}return z(n)},{Buffer:p}=k("node:buffer"),i="azure",q=3e4,R=3,K=_((n={})=>{if(!n.region)throw new w(i,"region");if(!n.connectionString&&!n.accessToken)throw new w(i,"connectionString or accessToken");const u=n.endpoint??`https://${n.region}.communication.azure.com`,t={debug:n.debug??!1,endpoint:u,region:n.region,retries:n.retries??R,timeout:n.timeout??q,...n.connectionString&&{connectionString:n.connectionString},...n.accessToken&&{accessToken:n.accessToken},...n.logger&&{logger:n.logger}},g=new B,a=C(i,n.logger);return{features:{attachments:!0,batchSending:!1,customHeaders:!0,html:!0,replyTo:!0,scheduling:!1,tagging:!1,templates:!0,tracking:!1},async getEmail(e){try{if(!e)return{error:new l(i,"Email ID is required to retrieve email details"),success:!1};await g.ensureInitialized(()=>this.initialize(),i);const o={"Content-Type":"application/json"};if(t.accessToken)o.Authorization=`Bearer ${t.accessToken}`;else if(t.connectionString){const c=t.connectionString.match(/endpoint=([^;]+);accesskey=([^;]+)/);c&&(o.Authorization=`Bearer ${c[2]}`)}a.debug("Retrieving email details",{id:e});const r=await v(async()=>h(`${t.endpoint}/emails/${e}`,{headers:o,method:"GET",timeout:t.timeout}),t.retries);return r.success?(a.debug("Email details retrieved successfully"),{data:r.data?.body,success:!0}):(a.debug("API request failed when retrieving email",r.error),{error:new l(i,`Failed to retrieve email: ${r.error instanceof Error?r.error.message:"Unknown error"}`,{cause:r.error}),success:!1})}catch(o){return{error:T(i,"retrieve email",o,a),success:!1}}},async initialize(){await g.ensureInitialized(async()=>{if(!await this.isAvailable())throw new l(i,"Azure Communication Services API not available or invalid credentials");a.debug("Provider initialized successfully")},i)},async isAvailable(){try{const e={"Content-Type":"application/json"};if(t.accessToken)e.Authorization=`Bearer ${t.accessToken}`;else if(t.connectionString){const c=t.connectionString.match(/endpoint=([^;]+);accesskey=([^;]+)/);if(c)e.Authorization=`Bearer ${c[2]}`;else return!1}else return!1;a.debug("Checking Azure Communication Services API availability");const o=await h(`${t.endpoint}/emails:send`,{headers:e,method:"POST",timeout:t.timeout},JSON.stringify({}));if(o.success)return!0;const r=o.data?.statusCode;return r===401||r===403?!1:r===400}catch(e){if(a.debug("Error checking availability:",e),e instanceof Error){const o=e.message;if(o.includes("401")||o.includes("403"))return!1}return!1}},name:i,options:t,async sendEmail(e){try{const o=j(e);if(o.length>0)return{error:new l(i,`Invalid email options: ${o.join(", ")}`),success:!1};await g.ensureInitialized(()=>this.initialize(),i);const r={content:{subject:e.subject},recipients:{to:y(e.to)},senderAddress:e.from.email};if(e.html&&(r.content.html=e.html),e.text&&(r.content.plainText=e.text),e.cc&&(r.recipients.cc=y(e.cc)),e.bcc&&(r.recipients.bcc=y(e.bcc)),e.replyTo&&(r.replyTo=E(e.replyTo).email),e.importance&&(r.importance=e.importance),e.headers){const s=P(e.headers);r.headers=s}e.attachments&&e.attachments.length>0&&(r.attachments=await Promise.all(e.attachments.map(async s=>{let d;if(s.content)if(typeof s.content=="string")d=p.from(s.content,"utf8").toString("base64");else if(s.content&&typeof s.content.then=="function"){const S=await s.content;d=p.from(S).toString("base64")}else d=s.content.toString("base64");else if(s.raw)d=typeof s.raw=="string"?p.from(s.raw,"utf8").toString("base64"):s.raw.toString("base64");else throw new l(i,`Attachment ${s.filename} has no content`);return{contentInBase64:d,contentType:s.contentType??"application/octet-stream",name:s.filename}}))),a.debug("Sending email via Azure Communication Services API",{subject:r.content.subject,to:r.recipients.to});const c={"Content-Type":"application/json"};if(t.accessToken)c.Authorization=`Bearer ${t.accessToken}`;else if(t.connectionString){const s=t.connectionString.match(/endpoint=([^;]+);accesskey=([^;]+)/);if(s)c.Authorization=`Bearer ${s[2]}`;else return{error:new l(i,"Invalid connection string format"),success:!1}}const m=await v(async()=>h(`${t.endpoint}/emails:send`,{headers:c,method:"POST",timeout:t.timeout},JSON.stringify(r)),t.retries);if(!m.success)return a.debug("API request failed when sending email",m.error),{error:m.error??new l(i,"Failed to send email"),success:!1};const b=m.data?.body?.messageId??I();return a.debug("Email sent successfully",{messageId:b}),{data:{messageId:b,provider:i,response:m.data,sent:!0,timestamp:new Date},success:!0}}catch(o){return{error:T(i,"send email",o,a),success:!1}}},async validateCredentials(){return this.isAvailable()}}});export{K as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as m}from"node:module";const _=m(import.meta.url),r=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,f=t=>{if(typeof r<"u"&&r.versions&&r.versions.node){const[e,s]=r.versions.node.split(".").map(Number);if(e>22||e===22&&s>=3||e===20&&s>=16)return r.getBuiltinModule(t)}return _(t)},{createHash:g}=f("node:crypto"),p=t=>t?(Array.isArray(t)?t:[t]).map(e=>e.email.toLowerCase()).toSorted((e,s)=>e.localeCompare(s)).join(","):"",y=t=>{const e=g("sha256");return e.update(p(t.to)),e.update("\0"),e.update(p(t.cc)),e.update("\0"),e.update(t.subject),e.update("\0"),e.update(t.text??t.html??""),e.digest("hex")},j=(t={})=>{const{keyFn:e=y,now:s=Date.now,ttl:d=6e4}=t,a=new Map;return async(c,l)=>{const i=e(c),u=s(),o=a.get(i);if(o&&o.expires>u)return o.result;const n=await l(c);return n.success&&a.set(i,{expires:u+d,result:n}),n}};export{j as dedupeMiddleware};
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The lifecycle/engagement event types that converge onto a single {@link EmailEvent} shape.
|
|
3
|
-
*
|
|
4
|
-
* The first group (`queued` → `failed`) is emitted by the send pipeline; the rest typically originate
|
|
5
|
-
* from provider webhooks (delivery/engagement signals).
|
|
6
|
-
*/
|
|
7
|
-
type EmailEventType = "attempt" | "bounced" | "clicked" | "complained" | "deferred" | "delivered" | "failed" | "opened" | "queued" | "sent" | "unsubscribed";
|
|
8
|
-
/**
|
|
9
|
-
* A single, provider-agnostic email event. Both internal send-lifecycle signals and normalized
|
|
10
|
-
* webhook events use this shape so a timeline can be reconstructed from one stream.
|
|
11
|
-
*/
|
|
12
|
-
interface EmailEvent {
|
|
13
|
-
/**
|
|
14
|
-
* Arbitrary structured payload (provider response, bounce sub-type, click URL, …).
|
|
15
|
-
*/
|
|
16
|
-
data?: Record<string, unknown>;
|
|
17
|
-
/**
|
|
18
|
-
* A unique id for this event.
|
|
19
|
-
*/
|
|
20
|
-
id: string;
|
|
21
|
-
/**
|
|
22
|
-
* The message this event concerns.
|
|
23
|
-
*/
|
|
24
|
-
messageId?: string;
|
|
25
|
-
/**
|
|
26
|
-
* The provider that produced (or will produce) the message.
|
|
27
|
-
*/
|
|
28
|
-
provider?: string;
|
|
29
|
-
/**
|
|
30
|
-
* The recipient address this event concerns, when applicable.
|
|
31
|
-
*/
|
|
32
|
-
recipient?: string;
|
|
33
|
-
/**
|
|
34
|
-
* When the event occurred.
|
|
35
|
-
*/
|
|
36
|
-
timestamp: Date;
|
|
37
|
-
/**
|
|
38
|
-
* The kind of event.
|
|
39
|
-
*/
|
|
40
|
-
type: EmailEventType;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* A listener invoked for matching {@link EmailEvent}s.
|
|
44
|
-
*/
|
|
45
|
-
type EmailEventListener = (event: EmailEvent) => void;
|
|
46
|
-
/**
|
|
47
|
-
* A persistence backend for {@link EmailEvent}s.
|
|
48
|
-
*/
|
|
49
|
-
interface EventStore {
|
|
50
|
-
/**
|
|
51
|
-
* Appends an event.
|
|
52
|
-
* @param event The event to store.
|
|
53
|
-
*/
|
|
54
|
-
append: (event: EmailEvent) => Promise<void> | void;
|
|
55
|
-
/**
|
|
56
|
-
* Returns the full, time-ordered timeline for a message.
|
|
57
|
-
* @param messageId The message to reconstruct.
|
|
58
|
-
*/
|
|
59
|
-
timeline: (messageId: string) => EmailEvent[] | Promise<EmailEvent[]>;
|
|
60
|
-
}
|
|
61
|
-
type Selector = "*" | EmailEventType;
|
|
62
|
-
/**
|
|
63
|
-
* The wildcard selector that subscribes to every event type.
|
|
64
|
-
*/
|
|
65
|
-
declare const ALL_EVENTS: "*";
|
|
66
|
-
/**
|
|
67
|
-
* A tiny synchronous pub/sub bus for {@link EmailEvent}s.
|
|
68
|
-
*
|
|
69
|
-
* Subscribe to a specific {@link EmailEventType} or to {@link ALL_EVENTS} (`"*"`) for every event.
|
|
70
|
-
*/
|
|
71
|
-
declare class EventBus {
|
|
72
|
-
private readonly listeners;
|
|
73
|
-
/**
|
|
74
|
-
* Subscribes a listener to an event type (or all events).
|
|
75
|
-
* @param type The event type, or `"*"` for all events.
|
|
76
|
-
* @param listener The listener to invoke.
|
|
77
|
-
* @returns An unsubscribe function.
|
|
78
|
-
*/
|
|
79
|
-
on(type: Selector, listener: EmailEventListener): () => void;
|
|
80
|
-
/**
|
|
81
|
-
* Subscribes a listener that is removed after its first invocation.
|
|
82
|
-
* @param type The event type, or `"*"` for all events.
|
|
83
|
-
* @param listener The listener to invoke once.
|
|
84
|
-
* @returns An unsubscribe function.
|
|
85
|
-
*/
|
|
86
|
-
once(type: Selector, listener: EmailEventListener): () => void;
|
|
87
|
-
/**
|
|
88
|
-
* Removes a previously-added listener.
|
|
89
|
-
* @param type The event type the listener was registered under.
|
|
90
|
-
* @param listener The listener to remove.
|
|
91
|
-
*/
|
|
92
|
-
off(type: Selector, listener: EmailEventListener): void;
|
|
93
|
-
/**
|
|
94
|
-
* Emits an event to all matching listeners (type-specific first, then wildcard).
|
|
95
|
-
* @param event The event to dispatch.
|
|
96
|
-
*/
|
|
97
|
-
emit(event: EmailEvent): void;
|
|
98
|
-
/**
|
|
99
|
-
* Removes all listeners (optionally for a single type).
|
|
100
|
-
* @param type When provided, only listeners for this type are removed.
|
|
101
|
-
*/
|
|
102
|
-
clear(type?: Selector): void;
|
|
103
|
-
}
|
|
104
|
-
export { ALL_EVENTS as A, EmailEvent as E, EventStore as a, EmailEventListener as b, EmailEventType as c, EventBus as d };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createRequire as t}from"node:module";const n=t(import.meta.url),e=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,i=r=>{if(typeof e<"u"&&e.versions&&e.versions.node){const[o,s]=e.versions.node.split(".").map(Number);if(o>22||o===22&&s>=3||o===20&&s>=16)return e.getBuiltinModule(r)}return n(r)},{randomBytes:c}=i("node:crypto"),u=()=>`----_=_NextPart_${c(16).toString("hex")}`;export{u as r};
|