@parsrun/email 0.1.30 → 0.1.31
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/dist/index.d.ts +64 -6
- package/dist/index.js +153 -4
- package/dist/index.js.map +1 -1
- package/dist/providers/console.d.ts +29 -1
- package/dist/providers/console.js +25 -0
- package/dist/providers/console.js.map +1 -1
- package/dist/providers/index.js +130 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/postmark.d.ts +37 -1
- package/dist/providers/postmark.js +40 -0
- package/dist/providers/postmark.js.map +1 -1
- package/dist/providers/resend.d.ts +36 -1
- package/dist/providers/resend.js +39 -0
- package/dist/providers/resend.js.map +1 -1
- package/dist/providers/sendgrid.d.ts +37 -1
- package/dist/providers/sendgrid.js +40 -0
- package/dist/providers/sendgrid.js.map +1 -1
- package/dist/templates/index.d.ts +219 -2
- package/dist/templates/index.js.map +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/providers/index.js
CHANGED
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
emailConfig
|
|
15
15
|
} from "@parsrun/types";
|
|
16
16
|
var EmailError = class extends Error {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new EmailError instance.
|
|
19
|
+
*
|
|
20
|
+
* @param message - Human-readable error description
|
|
21
|
+
* @param code - Error code from EmailErrorCodes for programmatic handling
|
|
22
|
+
* @param cause - The underlying error that caused this error, if any
|
|
23
|
+
*/
|
|
17
24
|
constructor(message, code, cause) {
|
|
18
25
|
super(message);
|
|
19
26
|
this.code = code;
|
|
@@ -34,11 +41,17 @@ var EmailErrorCodes = {
|
|
|
34
41
|
|
|
35
42
|
// src/providers/resend.ts
|
|
36
43
|
var ResendProvider = class {
|
|
44
|
+
/** Provider type identifier */
|
|
37
45
|
type = "resend";
|
|
38
46
|
apiKey;
|
|
39
47
|
fromEmail;
|
|
40
48
|
fromName;
|
|
41
49
|
baseUrl = "https://api.resend.com";
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new ResendProvider instance.
|
|
52
|
+
*
|
|
53
|
+
* @param config - The provider configuration including API key and sender info
|
|
54
|
+
*/
|
|
42
55
|
constructor(config) {
|
|
43
56
|
this.apiKey = config.apiKey;
|
|
44
57
|
this.fromEmail = config.fromEmail;
|
|
@@ -59,6 +72,13 @@ var ResendProvider = class {
|
|
|
59
72
|
}
|
|
60
73
|
return [this.formatAddress(addresses)];
|
|
61
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Sends an email via the Resend API.
|
|
77
|
+
*
|
|
78
|
+
* @param options - The email options including recipient, subject, and content
|
|
79
|
+
* @returns A promise that resolves to the send result with message ID if successful
|
|
80
|
+
* @throws {EmailError} If the Resend API request fails
|
|
81
|
+
*/
|
|
62
82
|
async send(options) {
|
|
63
83
|
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
64
84
|
const payload = {
|
|
@@ -111,6 +131,12 @@ var ResendProvider = class {
|
|
|
111
131
|
);
|
|
112
132
|
}
|
|
113
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Sends multiple emails via the Resend API sequentially.
|
|
136
|
+
*
|
|
137
|
+
* @param options - The batch email options containing emails and error handling config
|
|
138
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
139
|
+
*/
|
|
114
140
|
async sendBatch(options) {
|
|
115
141
|
const results = [];
|
|
116
142
|
let successful = 0;
|
|
@@ -141,6 +167,11 @@ var ResendProvider = class {
|
|
|
141
167
|
results
|
|
142
168
|
};
|
|
143
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Verifies the Resend API key by checking configured domains.
|
|
172
|
+
*
|
|
173
|
+
* @returns A promise that resolves to true if the API key is valid, false otherwise
|
|
174
|
+
*/
|
|
144
175
|
async verify() {
|
|
145
176
|
try {
|
|
146
177
|
const response = await fetch(`${this.baseUrl}/domains`, {
|
|
@@ -153,6 +184,14 @@ var ResendProvider = class {
|
|
|
153
184
|
return false;
|
|
154
185
|
}
|
|
155
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Converts a Uint8Array to a base64-encoded string.
|
|
189
|
+
*
|
|
190
|
+
* Edge-compatible base64 encoding that works in all JavaScript runtimes.
|
|
191
|
+
*
|
|
192
|
+
* @param data - The binary data to encode
|
|
193
|
+
* @returns The base64-encoded string
|
|
194
|
+
*/
|
|
156
195
|
uint8ArrayToBase64(data) {
|
|
157
196
|
let binary = "";
|
|
158
197
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -170,11 +209,17 @@ function createResendProvider(config) {
|
|
|
170
209
|
|
|
171
210
|
// src/providers/sendgrid.ts
|
|
172
211
|
var SendGridProvider = class {
|
|
212
|
+
/** Provider type identifier */
|
|
173
213
|
type = "sendgrid";
|
|
174
214
|
apiKey;
|
|
175
215
|
fromEmail;
|
|
176
216
|
fromName;
|
|
177
217
|
baseUrl = "https://api.sendgrid.com/v3";
|
|
218
|
+
/**
|
|
219
|
+
* Creates a new SendGridProvider instance.
|
|
220
|
+
*
|
|
221
|
+
* @param config - The provider configuration including API key and sender info
|
|
222
|
+
*/
|
|
178
223
|
constructor(config) {
|
|
179
224
|
this.apiKey = config.apiKey;
|
|
180
225
|
this.fromEmail = config.fromEmail;
|
|
@@ -192,6 +237,13 @@ var SendGridProvider = class {
|
|
|
192
237
|
}
|
|
193
238
|
return [this.formatAddress(addresses)];
|
|
194
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Sends an email via the SendGrid API.
|
|
242
|
+
*
|
|
243
|
+
* @param options - The email options including recipient, subject, and content
|
|
244
|
+
* @returns A promise that resolves to the send result with message ID if successful
|
|
245
|
+
* @throws {EmailError} If the SendGrid API request fails
|
|
246
|
+
*/
|
|
195
247
|
async send(options) {
|
|
196
248
|
const from = options.from ? this.formatAddress(options.from) : this.fromName ? { email: this.fromEmail, name: this.fromName } : { email: this.fromEmail };
|
|
197
249
|
const personalization = {
|
|
@@ -266,6 +318,15 @@ var SendGridProvider = class {
|
|
|
266
318
|
);
|
|
267
319
|
}
|
|
268
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Sends multiple emails via the SendGrid API sequentially.
|
|
323
|
+
*
|
|
324
|
+
* Note: SendGrid does not support true batch sending via the standard API,
|
|
325
|
+
* so emails are sent one at a time.
|
|
326
|
+
*
|
|
327
|
+
* @param options - The batch email options containing emails and error handling config
|
|
328
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
329
|
+
*/
|
|
269
330
|
async sendBatch(options) {
|
|
270
331
|
const results = [];
|
|
271
332
|
let successful = 0;
|
|
@@ -296,6 +357,11 @@ var SendGridProvider = class {
|
|
|
296
357
|
results
|
|
297
358
|
};
|
|
298
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Verifies the SendGrid API key by checking API scopes.
|
|
362
|
+
*
|
|
363
|
+
* @returns A promise that resolves to true if the API key is valid, false otherwise
|
|
364
|
+
*/
|
|
299
365
|
async verify() {
|
|
300
366
|
try {
|
|
301
367
|
const response = await fetch(`${this.baseUrl}/scopes`, {
|
|
@@ -308,6 +374,12 @@ var SendGridProvider = class {
|
|
|
308
374
|
return false;
|
|
309
375
|
}
|
|
310
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Converts a Uint8Array to a base64-encoded string.
|
|
379
|
+
*
|
|
380
|
+
* @param data - The binary data to encode
|
|
381
|
+
* @returns The base64-encoded string
|
|
382
|
+
*/
|
|
311
383
|
uint8ArrayToBase64(data) {
|
|
312
384
|
let binary = "";
|
|
313
385
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -325,11 +397,17 @@ function createSendGridProvider(config) {
|
|
|
325
397
|
|
|
326
398
|
// src/providers/postmark.ts
|
|
327
399
|
var PostmarkProvider = class {
|
|
400
|
+
/** Provider type identifier */
|
|
328
401
|
type = "postmark";
|
|
329
402
|
apiKey;
|
|
330
403
|
fromEmail;
|
|
331
404
|
fromName;
|
|
332
405
|
baseUrl = "https://api.postmarkapp.com";
|
|
406
|
+
/**
|
|
407
|
+
* Creates a new PostmarkProvider instance.
|
|
408
|
+
*
|
|
409
|
+
* @param config - The provider configuration including API key (server token) and sender info
|
|
410
|
+
*/
|
|
333
411
|
constructor(config) {
|
|
334
412
|
this.apiKey = config.apiKey;
|
|
335
413
|
this.fromEmail = config.fromEmail;
|
|
@@ -350,6 +428,13 @@ var PostmarkProvider = class {
|
|
|
350
428
|
}
|
|
351
429
|
return this.formatAddress(addresses);
|
|
352
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Sends an email via the Postmark API.
|
|
433
|
+
*
|
|
434
|
+
* @param options - The email options including recipient, subject, and content
|
|
435
|
+
* @returns A promise that resolves to the send result with message ID if successful
|
|
436
|
+
* @throws {EmailError} If the Postmark API request fails
|
|
437
|
+
*/
|
|
353
438
|
async send(options) {
|
|
354
439
|
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
355
440
|
const payload = {
|
|
@@ -411,6 +496,15 @@ var PostmarkProvider = class {
|
|
|
411
496
|
);
|
|
412
497
|
}
|
|
413
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Sends multiple emails via Postmark's batch API.
|
|
501
|
+
*
|
|
502
|
+
* Postmark supports native batch sending of up to 500 emails in a single request.
|
|
503
|
+
*
|
|
504
|
+
* @param options - The batch email options containing emails and error handling config
|
|
505
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
506
|
+
* @throws {EmailError} If the Postmark batch API request fails
|
|
507
|
+
*/
|
|
414
508
|
async sendBatch(options) {
|
|
415
509
|
const batchPayload = options.emails.map((email) => {
|
|
416
510
|
const from = email.from ? this.formatAddress(email.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
@@ -459,6 +553,11 @@ var PostmarkProvider = class {
|
|
|
459
553
|
);
|
|
460
554
|
}
|
|
461
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Verifies the Postmark server token by checking server info.
|
|
558
|
+
*
|
|
559
|
+
* @returns A promise that resolves to true if the server token is valid, false otherwise
|
|
560
|
+
*/
|
|
462
561
|
async verify() {
|
|
463
562
|
try {
|
|
464
563
|
const response = await fetch(`${this.baseUrl}/server`, {
|
|
@@ -472,6 +571,12 @@ var PostmarkProvider = class {
|
|
|
472
571
|
return false;
|
|
473
572
|
}
|
|
474
573
|
}
|
|
574
|
+
/**
|
|
575
|
+
* Converts a Uint8Array to a base64-encoded string.
|
|
576
|
+
*
|
|
577
|
+
* @param data - The binary data to encode
|
|
578
|
+
* @returns The base64-encoded string
|
|
579
|
+
*/
|
|
475
580
|
uint8ArrayToBase64(data) {
|
|
476
581
|
let binary = "";
|
|
477
582
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -489,10 +594,16 @@ function createPostmarkProvider(config) {
|
|
|
489
594
|
|
|
490
595
|
// src/providers/console.ts
|
|
491
596
|
var ConsoleProvider = class {
|
|
597
|
+
/** Provider type identifier */
|
|
492
598
|
type = "console";
|
|
493
599
|
fromEmail;
|
|
494
600
|
fromName;
|
|
495
601
|
messageCounter = 0;
|
|
602
|
+
/**
|
|
603
|
+
* Creates a new ConsoleProvider instance.
|
|
604
|
+
*
|
|
605
|
+
* @param config - The provider configuration (apiKey is not required for console provider)
|
|
606
|
+
*/
|
|
496
607
|
constructor(config) {
|
|
497
608
|
this.fromEmail = config.fromEmail;
|
|
498
609
|
this.fromName = config.fromName;
|
|
@@ -512,6 +623,12 @@ var ConsoleProvider = class {
|
|
|
512
623
|
}
|
|
513
624
|
return this.formatAddress(addresses);
|
|
514
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* Logs an email to the console instead of sending it.
|
|
628
|
+
*
|
|
629
|
+
* @param options - The email options to log
|
|
630
|
+
* @returns A promise that resolves to a successful result with a generated message ID
|
|
631
|
+
*/
|
|
515
632
|
async send(options) {
|
|
516
633
|
this.messageCounter++;
|
|
517
634
|
const messageId = `console-${Date.now()}-${this.messageCounter}`;
|
|
@@ -566,6 +683,12 @@ ${separator}`);
|
|
|
566
683
|
messageId
|
|
567
684
|
};
|
|
568
685
|
}
|
|
686
|
+
/**
|
|
687
|
+
* Logs multiple emails to the console.
|
|
688
|
+
*
|
|
689
|
+
* @param options - The batch email options containing emails to log
|
|
690
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
691
|
+
*/
|
|
569
692
|
async sendBatch(options) {
|
|
570
693
|
const results = [];
|
|
571
694
|
let successful = 0;
|
|
@@ -600,6 +723,13 @@ ${separator}`);
|
|
|
600
723
|
results
|
|
601
724
|
};
|
|
602
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* Verifies the provider configuration.
|
|
728
|
+
*
|
|
729
|
+
* For the console provider, this always returns true and logs a message.
|
|
730
|
+
*
|
|
731
|
+
* @returns A promise that always resolves to true
|
|
732
|
+
*/
|
|
603
733
|
async verify() {
|
|
604
734
|
console.log("\u{1F4E7} Console email provider verified (always returns true)");
|
|
605
735
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types.ts","../../src/providers/resend.ts","../../src/providers/sendgrid.ts","../../src/providers/postmark.ts","../../src/providers/console.ts"],"sourcesContent":["/**\n * @parsrun/email - Type Definitions\n * Email types and interfaces\n */\n\n// Re-export types from @parsrun/types for convenience\nexport {\n type,\n emailAddress,\n emailAttachment,\n sendEmailOptions,\n sendTemplateEmailOptions,\n emailSendResult,\n smtpConfig,\n resendConfig,\n sendgridConfig,\n sesConfig,\n postmarkConfig,\n emailConfig,\n type EmailAddress as ParsEmailAddress,\n type EmailAttachment as ParsEmailAttachment,\n type SendEmailOptions,\n type SendTemplateEmailOptions,\n type EmailSendResult,\n type SmtpConfig,\n type ResendConfig,\n type SendgridConfig,\n type SesConfig,\n type PostmarkConfig,\n type EmailConfig,\n} from \"@parsrun/types\";\n\n/**\n * Email provider type\n */\nexport type EmailProviderType = \"resend\" | \"sendgrid\" | \"postmark\" | \"ses\" | \"console\" | \"mailgun\";\n\n/**\n * Email address with optional name\n */\nexport interface EmailAddress {\n email: string;\n name?: string | undefined;\n}\n\n/**\n * Email attachment\n */\nexport interface EmailAttachment {\n /** File name */\n filename: string;\n /** File content (base64 encoded or Buffer) */\n content: string | Uint8Array;\n /** Content type (MIME type) */\n contentType?: string | undefined;\n /** Content ID for inline attachments */\n contentId?: string | undefined;\n}\n\n/**\n * Email options\n */\nexport interface EmailOptions {\n /** Recipient email address(es) */\n to: string | string[] | EmailAddress | EmailAddress[];\n /** Email subject */\n subject: string;\n /** HTML content */\n html?: string | undefined;\n /** Plain text content */\n text?: string | undefined;\n /** From address (overrides default) */\n from?: string | EmailAddress | undefined;\n /** Reply-to address */\n replyTo?: string | EmailAddress | undefined;\n /** CC recipients */\n cc?: string | string[] | EmailAddress | EmailAddress[] | undefined;\n /** BCC recipients */\n bcc?: string | string[] | EmailAddress | EmailAddress[] | undefined;\n /** Attachments */\n attachments?: EmailAttachment[] | undefined;\n /** Custom headers */\n headers?: Record<string, string> | undefined;\n /** Tags for tracking */\n tags?: Record<string, string> | undefined;\n /** Schedule send time */\n scheduledAt?: Date | undefined;\n}\n\n/**\n * Email send result\n */\nexport interface EmailResult {\n /** Whether send was successful */\n success: boolean;\n /** Message ID from provider */\n messageId?: string | undefined;\n /** Error message if failed */\n error?: string | undefined;\n /** Provider-specific response data */\n data?: unknown;\n}\n\n/**\n * Batch email options\n */\nexport interface BatchEmailOptions {\n /** List of emails to send */\n emails: EmailOptions[];\n /** Whether to stop on first error */\n stopOnError?: boolean | undefined;\n}\n\n/**\n * Batch email result\n */\nexport interface BatchEmailResult {\n /** Total emails attempted */\n total: number;\n /** Successful sends */\n successful: number;\n /** Failed sends */\n failed: number;\n /** Individual results */\n results: EmailResult[];\n}\n\n/**\n * Email provider configuration\n */\nexport interface EmailProviderConfig {\n /** API key for the provider */\n apiKey: string;\n /** Default from email */\n fromEmail: string;\n /** Default from name */\n fromName?: string | undefined;\n /** Provider-specific options */\n options?: Record<string, unknown> | undefined;\n}\n\n/**\n * Email provider interface\n */\nexport interface EmailProvider {\n /** Provider type */\n readonly type: EmailProviderType;\n\n /**\n * Send a single email\n */\n send(options: EmailOptions): Promise<EmailResult>;\n\n /**\n * Send multiple emails\n */\n sendBatch?(options: BatchEmailOptions): Promise<BatchEmailResult>;\n\n /**\n * Verify provider configuration\n */\n verify?(): Promise<boolean>;\n}\n\n/**\n * Email service configuration\n */\nexport interface EmailServiceConfig {\n /** Provider type */\n provider: EmailProviderType;\n /** API key */\n apiKey: string;\n /** Default from email */\n fromEmail: string;\n /** Default from name */\n fromName?: string | undefined;\n /** Enable debug logging */\n debug?: boolean | undefined;\n /** Provider-specific options */\n providerOptions?: Record<string, unknown> | undefined;\n}\n\n/**\n * Template data for email templates\n */\nexport interface TemplateData {\n [key: string]: string | number | boolean | undefined | null | TemplateData | TemplateData[];\n}\n\n/**\n * Email template\n */\nexport interface EmailTemplate {\n /** Template name */\n name: string;\n /** Subject template */\n subject: string;\n /** HTML template */\n html: string;\n /** Plain text template */\n text?: string | undefined;\n}\n\n/**\n * Email error\n */\nexport class EmailError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"EmailError\";\n }\n}\n\n/**\n * Common email error codes\n */\nexport const EmailErrorCodes = {\n INVALID_CONFIG: \"INVALID_CONFIG\",\n INVALID_RECIPIENT: \"INVALID_RECIPIENT\",\n INVALID_CONTENT: \"INVALID_CONTENT\",\n SEND_FAILED: \"SEND_FAILED\",\n RATE_LIMITED: \"RATE_LIMITED\",\n PROVIDER_ERROR: \"PROVIDER_ERROR\",\n TEMPLATE_ERROR: \"TEMPLATE_ERROR\",\n ATTACHMENT_ERROR: \"ATTACHMENT_ERROR\",\n} as const;\n","/**\n * @parsrun/email - Resend Provider\n * Edge-compatible Resend email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * Resend Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const resend = new ResendProvider({\n * apiKey: process.env.RESEND_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await resend.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class ResendProvider implements EmailProvider {\n readonly type = \"resend\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.resend.com\";\n\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string[] {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a));\n }\n return [this.formatAddress(addresses)];\n }\n\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const payload: Record<string, unknown> = {\n from,\n to: this.formatAddresses(options.to),\n subject: options.subject,\n };\n\n if (options.html) payload[\"html\"] = options.html;\n if (options.text) payload[\"text\"] = options.text;\n if (options.replyTo) payload[\"reply_to\"] = this.formatAddress(options.replyTo);\n if (options.cc) payload[\"cc\"] = this.formatAddresses(options.cc);\n if (options.bcc) payload[\"bcc\"] = this.formatAddresses(options.bcc);\n if (options.headers) payload[\"headers\"] = options.headers;\n if (options.tags) payload[\"tags\"] = Object.entries(options.tags).map(([name, value]) => ({ name, value }));\n if (options.scheduledAt) payload[\"scheduled_at\"] = options.scheduledAt.toISOString();\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"attachments\"] = options.attachments.map((att) => ({\n filename: att.filename,\n content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n content_type: att.contentType,\n }));\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/emails`, {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n const data = await response.json() as { id?: string; message?: string; statusCode?: number };\n\n if (!response.ok) {\n return {\n success: false,\n error: data.message || `HTTP ${response.status}`,\n data,\n };\n }\n\n return {\n success: true,\n messageId: data.id,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `Resend send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/domains`, {\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n // Edge-compatible base64 encoding\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Create a Resend provider\n */\nexport function createResendProvider(config: EmailProviderConfig): ResendProvider {\n return new ResendProvider(config);\n}\n","/**\n * @parsrun/email - SendGrid Provider\n * Edge-compatible SendGrid email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * SendGrid Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const sendgrid = new SendGridProvider({\n * apiKey: process.env.SENDGRID_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await sendgrid.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class SendGridProvider implements EmailProvider {\n readonly type = \"sendgrid\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.sendgrid.com/v3\";\n\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): { email: string; name?: string | undefined } {\n if (typeof address === \"string\") {\n return { email: address };\n }\n return address.name ? { email: address.email, name: address.name } : { email: address.email };\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): Array<{ email: string; name?: string | undefined }> {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a));\n }\n return [this.formatAddress(addresses)];\n }\n\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? { email: this.fromEmail, name: this.fromName }\n : { email: this.fromEmail };\n\n const personalization: {\n to: Array<{ email: string; name?: string | undefined }>;\n cc?: Array<{ email: string; name?: string | undefined }> | undefined;\n bcc?: Array<{ email: string; name?: string | undefined }> | undefined;\n headers?: Record<string, string> | undefined;\n } = {\n to: this.formatAddresses(options.to),\n };\n\n if (options.cc) {\n personalization.cc = this.formatAddresses(options.cc);\n }\n if (options.bcc) {\n personalization.bcc = this.formatAddresses(options.bcc);\n }\n if (options.headers) {\n personalization.headers = options.headers;\n }\n\n const payload: Record<string, unknown> = {\n personalizations: [personalization],\n from,\n subject: options.subject,\n content: [],\n };\n\n const content: Array<{ type: string; value: string }> = [];\n if (options.text) {\n content.push({ type: \"text/plain\", value: options.text });\n }\n if (options.html) {\n content.push({ type: \"text/html\", value: options.html });\n }\n payload[\"content\"] = content;\n\n if (options.replyTo) {\n payload[\"reply_to\"] = this.formatAddress(options.replyTo);\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"attachments\"] = options.attachments.map((att) => ({\n filename: att.filename,\n content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n type: att.contentType,\n content_id: att.contentId,\n disposition: att.contentId ? \"inline\" : \"attachment\",\n }));\n }\n\n if (options.scheduledAt) {\n payload[\"send_at\"] = Math.floor(options.scheduledAt.getTime() / 1000);\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/mail/send`, {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n // SendGrid returns 202 for success with no body\n if (response.status === 202) {\n const messageId = response.headers.get(\"x-message-id\");\n return {\n success: true,\n messageId: messageId ?? undefined,\n };\n }\n\n const data = await response.json().catch(() => ({})) as { errors?: Array<{ message: string }> };\n const errorMessage = data.errors?.[0]?.message || `HTTP ${response.status}`;\n\n return {\n success: false,\n error: errorMessage,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `SendGrid send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/scopes`, {\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Create a SendGrid provider\n */\nexport function createSendGridProvider(config: EmailProviderConfig): SendGridProvider {\n return new SendGridProvider(config);\n}\n","/**\n * @parsrun/email - Postmark Provider\n * Edge-compatible Postmark email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * Postmark Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const postmark = new PostmarkProvider({\n * apiKey: process.env.POSTMARK_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await postmark.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class PostmarkProvider implements EmailProvider {\n readonly type = \"postmark\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.postmarkapp.com\";\n\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a)).join(\",\");\n }\n return this.formatAddress(addresses);\n }\n\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const payload: Record<string, unknown> = {\n From: from,\n To: this.formatAddresses(options.to),\n Subject: options.subject,\n };\n\n if (options.html) payload[\"HtmlBody\"] = options.html;\n if (options.text) payload[\"TextBody\"] = options.text;\n if (options.replyTo) payload[\"ReplyTo\"] = this.formatAddress(options.replyTo);\n if (options.cc) payload[\"Cc\"] = this.formatAddresses(options.cc);\n if (options.bcc) payload[\"Bcc\"] = this.formatAddresses(options.bcc);\n\n if (options.headers) {\n payload[\"Headers\"] = Object.entries(options.headers).map(([Name, Value]) => ({ Name, Value }));\n }\n\n if (options.tags) {\n // Postmark uses Tag field (single tag) and Metadata for custom data\n const tagEntries = Object.entries(options.tags);\n if (tagEntries.length > 0 && tagEntries[0]) {\n payload[\"Tag\"] = tagEntries[0][1];\n }\n payload[\"Metadata\"] = options.tags;\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"Attachments\"] = options.attachments.map((att) => ({\n Name: att.filename,\n Content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n ContentType: att.contentType || \"application/octet-stream\",\n ContentID: att.contentId,\n }));\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/email`, {\n method: \"POST\",\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n const data = await response.json() as {\n MessageID?: string;\n ErrorCode?: number;\n Message?: string;\n };\n\n if (!response.ok || data.ErrorCode) {\n return {\n success: false,\n error: data.Message || `HTTP ${response.status}`,\n data,\n };\n }\n\n return {\n success: true,\n messageId: data.MessageID,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `Postmark send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n // Postmark supports batch sending up to 500 emails\n const batchPayload = options.emails.map((email) => {\n const from = email.from\n ? this.formatAddress(email.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const item: Record<string, unknown> = {\n From: from,\n To: this.formatAddresses(email.to),\n Subject: email.subject,\n };\n\n if (email.html) item[\"HtmlBody\"] = email.html;\n if (email.text) item[\"TextBody\"] = email.text;\n if (email.replyTo) item[\"ReplyTo\"] = this.formatAddress(email.replyTo);\n if (email.cc) item[\"Cc\"] = this.formatAddresses(email.cc);\n if (email.bcc) item[\"Bcc\"] = this.formatAddresses(email.bcc);\n\n return item;\n });\n\n try {\n const response = await fetch(`${this.baseUrl}/email/batch`, {\n method: \"POST\",\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n body: JSON.stringify(batchPayload),\n });\n\n const data = await response.json() as Array<{\n MessageID?: string;\n ErrorCode?: number;\n Message?: string;\n }>;\n\n const results: EmailResult[] = data.map((item) => ({\n success: !item.ErrorCode,\n messageId: item.MessageID,\n error: item.ErrorCode ? item.Message : undefined,\n data: item,\n }));\n\n const successful = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n } catch (err) {\n throw new EmailError(\n `Postmark batch send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/server`, {\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Accept\": \"application/json\",\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Create a Postmark provider\n */\nexport function createPostmarkProvider(config: EmailProviderConfig): PostmarkProvider {\n return new PostmarkProvider(config);\n}\n","/**\n * @parsrun/email - Console Provider\n * Development/testing email provider that logs to console\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\n\n/**\n * Console Email Provider\n * Logs emails to console instead of sending them.\n * Useful for development and testing.\n *\n * @example\n * ```typescript\n * const console = new ConsoleProvider({\n * apiKey: 'not-needed',\n * fromEmail: 'test@example.com',\n * fromName: 'Test App',\n * });\n *\n * await console.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * // Logs email details to console\n * ```\n */\nexport class ConsoleProvider implements EmailProvider {\n readonly type = \"console\" as const;\n\n private fromEmail: string;\n private fromName: string | undefined;\n private messageCounter = 0;\n\n constructor(config: EmailProviderConfig) {\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a)).join(\", \");\n }\n return this.formatAddress(addresses);\n }\n\n async send(options: EmailOptions): Promise<EmailResult> {\n this.messageCounter++;\n const messageId = `console-${Date.now()}-${this.messageCounter}`;\n\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const separator = \"─\".repeat(60);\n\n console.log(`\\n${separator}`);\n console.log(\"📧 EMAIL (Console Provider)\");\n console.log(separator);\n console.log(`Message ID: ${messageId}`);\n console.log(`From: ${from}`);\n console.log(`To: ${this.formatAddresses(options.to)}`);\n if (options.cc) {\n console.log(`CC: ${this.formatAddresses(options.cc)}`);\n }\n if (options.bcc) {\n console.log(`BCC: ${this.formatAddresses(options.bcc)}`);\n }\n if (options.replyTo) {\n console.log(`Reply-To: ${this.formatAddress(options.replyTo)}`);\n }\n console.log(`Subject: ${options.subject}`);\n\n if (options.headers) {\n console.log(`Headers: ${JSON.stringify(options.headers)}`);\n }\n if (options.tags) {\n console.log(`Tags: ${JSON.stringify(options.tags)}`);\n }\n if (options.scheduledAt) {\n console.log(`Scheduled: ${options.scheduledAt.toISOString()}`);\n }\n if (options.attachments && options.attachments.length > 0) {\n console.log(`Attachments:`);\n for (const att of options.attachments) {\n const size = typeof att.content === \"string\"\n ? att.content.length\n : att.content.length;\n console.log(` - ${att.filename} (${att.contentType || \"unknown\"}, ${size} bytes)`);\n }\n }\n\n console.log(separator);\n if (options.text) {\n console.log(\"TEXT CONTENT:\");\n console.log(options.text);\n }\n if (options.html) {\n console.log(\"HTML CONTENT:\");\n console.log(options.html);\n }\n console.log(`${separator}\\n`);\n\n return {\n success: true,\n messageId,\n };\n }\n\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n console.log(`\\n📬 BATCH EMAIL (${options.emails.length} emails)`);\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n console.log(`📬 BATCH COMPLETE: ${successful} sent, ${failed} failed\\n`);\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n async verify(): Promise<boolean> {\n console.log(\"📧 Console email provider verified (always returns true)\");\n return true;\n }\n}\n\n/**\n * Create a Console provider\n */\nexport function createConsoleProvider(config: EmailProviderConfig): ConsoleProvider {\n return new ConsoleProvider(config);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/providers/resend.ts","../../src/providers/sendgrid.ts","../../src/providers/postmark.ts","../../src/providers/console.ts"],"sourcesContent":["/**\n * @parsrun/email - Type Definitions\n * Email types and interfaces\n */\n\n// Re-export types from @parsrun/types for convenience\nexport {\n type,\n emailAddress,\n emailAttachment,\n sendEmailOptions,\n sendTemplateEmailOptions,\n emailSendResult,\n smtpConfig,\n resendConfig,\n sendgridConfig,\n sesConfig,\n postmarkConfig,\n emailConfig,\n type EmailAddress as ParsEmailAddress,\n type EmailAttachment as ParsEmailAttachment,\n type SendEmailOptions,\n type SendTemplateEmailOptions,\n type EmailSendResult,\n type SmtpConfig,\n type ResendConfig,\n type SendgridConfig,\n type SesConfig,\n type PostmarkConfig,\n type EmailConfig,\n} from \"@parsrun/types\";\n\n/**\n * Email provider type\n */\nexport type EmailProviderType = \"resend\" | \"sendgrid\" | \"postmark\" | \"ses\" | \"console\" | \"mailgun\";\n\n/**\n * Email address with optional name\n */\nexport interface EmailAddress {\n email: string;\n name?: string | undefined;\n}\n\n/**\n * Email attachment\n */\nexport interface EmailAttachment {\n /** File name */\n filename: string;\n /** File content (base64 encoded or Buffer) */\n content: string | Uint8Array;\n /** Content type (MIME type) */\n contentType?: string | undefined;\n /** Content ID for inline attachments */\n contentId?: string | undefined;\n}\n\n/**\n * Email options\n */\nexport interface EmailOptions {\n /** Recipient email address(es) */\n to: string | string[] | EmailAddress | EmailAddress[];\n /** Email subject */\n subject: string;\n /** HTML content */\n html?: string | undefined;\n /** Plain text content */\n text?: string | undefined;\n /** From address (overrides default) */\n from?: string | EmailAddress | undefined;\n /** Reply-to address */\n replyTo?: string | EmailAddress | undefined;\n /** CC recipients */\n cc?: string | string[] | EmailAddress | EmailAddress[] | undefined;\n /** BCC recipients */\n bcc?: string | string[] | EmailAddress | EmailAddress[] | undefined;\n /** Attachments */\n attachments?: EmailAttachment[] | undefined;\n /** Custom headers */\n headers?: Record<string, string> | undefined;\n /** Tags for tracking */\n tags?: Record<string, string> | undefined;\n /** Schedule send time */\n scheduledAt?: Date | undefined;\n}\n\n/**\n * Email send result\n */\nexport interface EmailResult {\n /** Whether send was successful */\n success: boolean;\n /** Message ID from provider */\n messageId?: string | undefined;\n /** Error message if failed */\n error?: string | undefined;\n /** Provider-specific response data */\n data?: unknown;\n}\n\n/**\n * Batch email options\n */\nexport interface BatchEmailOptions {\n /** List of emails to send */\n emails: EmailOptions[];\n /** Whether to stop on first error */\n stopOnError?: boolean | undefined;\n}\n\n/**\n * Batch email result\n */\nexport interface BatchEmailResult {\n /** Total emails attempted */\n total: number;\n /** Successful sends */\n successful: number;\n /** Failed sends */\n failed: number;\n /** Individual results */\n results: EmailResult[];\n}\n\n/**\n * Email provider configuration\n */\nexport interface EmailProviderConfig {\n /** API key for the provider */\n apiKey: string;\n /** Default from email */\n fromEmail: string;\n /** Default from name */\n fromName?: string | undefined;\n /** Provider-specific options */\n options?: Record<string, unknown> | undefined;\n}\n\n/**\n * Email provider interface\n */\nexport interface EmailProvider {\n /** Provider type */\n readonly type: EmailProviderType;\n\n /**\n * Send a single email\n */\n send(options: EmailOptions): Promise<EmailResult>;\n\n /**\n * Send multiple emails\n */\n sendBatch?(options: BatchEmailOptions): Promise<BatchEmailResult>;\n\n /**\n * Verify provider configuration\n */\n verify?(): Promise<boolean>;\n}\n\n/**\n * Email service configuration\n */\nexport interface EmailServiceConfig {\n /** Provider type */\n provider: EmailProviderType;\n /** API key */\n apiKey: string;\n /** Default from email */\n fromEmail: string;\n /** Default from name */\n fromName?: string | undefined;\n /** Enable debug logging */\n debug?: boolean | undefined;\n /** Provider-specific options */\n providerOptions?: Record<string, unknown> | undefined;\n}\n\n/**\n * Template data for email templates\n */\nexport interface TemplateData {\n [key: string]: string | number | boolean | undefined | null | TemplateData | TemplateData[];\n}\n\n/**\n * Email template\n */\nexport interface EmailTemplate {\n /** Template name */\n name: string;\n /** Subject template */\n subject: string;\n /** HTML template */\n html: string;\n /** Plain text template */\n text?: string | undefined;\n}\n\n/**\n * Custom error class for email-related errors.\n *\n * Provides structured error information with error codes for programmatic handling.\n *\n * @example\n * ```typescript\n * try {\n * await provider.send(options);\n * } catch (err) {\n * if (err instanceof EmailError) {\n * console.log(`Error code: ${err.code}`);\n * }\n * }\n * ```\n */\nexport class EmailError extends Error {\n /**\n * Creates a new EmailError instance.\n *\n * @param message - Human-readable error description\n * @param code - Error code from EmailErrorCodes for programmatic handling\n * @param cause - The underlying error that caused this error, if any\n */\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"EmailError\";\n }\n}\n\n/**\n * Common email error codes\n */\nexport const EmailErrorCodes = {\n INVALID_CONFIG: \"INVALID_CONFIG\",\n INVALID_RECIPIENT: \"INVALID_RECIPIENT\",\n INVALID_CONTENT: \"INVALID_CONTENT\",\n SEND_FAILED: \"SEND_FAILED\",\n RATE_LIMITED: \"RATE_LIMITED\",\n PROVIDER_ERROR: \"PROVIDER_ERROR\",\n TEMPLATE_ERROR: \"TEMPLATE_ERROR\",\n ATTACHMENT_ERROR: \"ATTACHMENT_ERROR\",\n} as const;\n","/**\n * @parsrun/email - Resend Provider\n * Edge-compatible Resend email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * Resend Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const resend = new ResendProvider({\n * apiKey: process.env.RESEND_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await resend.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class ResendProvider implements EmailProvider {\n /** Provider type identifier */\n readonly type = \"resend\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.resend.com\";\n\n /**\n * Creates a new ResendProvider instance.\n *\n * @param config - The provider configuration including API key and sender info\n */\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string[] {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a));\n }\n return [this.formatAddress(addresses)];\n }\n\n /**\n * Sends an email via the Resend API.\n *\n * @param options - The email options including recipient, subject, and content\n * @returns A promise that resolves to the send result with message ID if successful\n * @throws {EmailError} If the Resend API request fails\n */\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const payload: Record<string, unknown> = {\n from,\n to: this.formatAddresses(options.to),\n subject: options.subject,\n };\n\n if (options.html) payload[\"html\"] = options.html;\n if (options.text) payload[\"text\"] = options.text;\n if (options.replyTo) payload[\"reply_to\"] = this.formatAddress(options.replyTo);\n if (options.cc) payload[\"cc\"] = this.formatAddresses(options.cc);\n if (options.bcc) payload[\"bcc\"] = this.formatAddresses(options.bcc);\n if (options.headers) payload[\"headers\"] = options.headers;\n if (options.tags) payload[\"tags\"] = Object.entries(options.tags).map(([name, value]) => ({ name, value }));\n if (options.scheduledAt) payload[\"scheduled_at\"] = options.scheduledAt.toISOString();\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"attachments\"] = options.attachments.map((att) => ({\n filename: att.filename,\n content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n content_type: att.contentType,\n }));\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/emails`, {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n const data = await response.json() as { id?: string; message?: string; statusCode?: number };\n\n if (!response.ok) {\n return {\n success: false,\n error: data.message || `HTTP ${response.status}`,\n data,\n };\n }\n\n return {\n success: true,\n messageId: data.id,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `Resend send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Sends multiple emails via the Resend API sequentially.\n *\n * @param options - The batch email options containing emails and error handling config\n * @returns A promise that resolves to the batch result with success/failure counts\n */\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n /**\n * Verifies the Resend API key by checking configured domains.\n *\n * @returns A promise that resolves to true if the API key is valid, false otherwise\n */\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/domains`, {\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Converts a Uint8Array to a base64-encoded string.\n *\n * Edge-compatible base64 encoding that works in all JavaScript runtimes.\n *\n * @param data - The binary data to encode\n * @returns The base64-encoded string\n */\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Creates a Resend provider instance.\n *\n * @param config - The provider configuration including API key and sender info\n * @returns A new ResendProvider instance\n */\nexport function createResendProvider(config: EmailProviderConfig): ResendProvider {\n return new ResendProvider(config);\n}\n","/**\n * @parsrun/email - SendGrid Provider\n * Edge-compatible SendGrid email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * SendGrid Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const sendgrid = new SendGridProvider({\n * apiKey: process.env.SENDGRID_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await sendgrid.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class SendGridProvider implements EmailProvider {\n /** Provider type identifier */\n readonly type = \"sendgrid\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.sendgrid.com/v3\";\n\n /**\n * Creates a new SendGridProvider instance.\n *\n * @param config - The provider configuration including API key and sender info\n */\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): { email: string; name?: string | undefined } {\n if (typeof address === \"string\") {\n return { email: address };\n }\n return address.name ? { email: address.email, name: address.name } : { email: address.email };\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): Array<{ email: string; name?: string | undefined }> {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a));\n }\n return [this.formatAddress(addresses)];\n }\n\n /**\n * Sends an email via the SendGrid API.\n *\n * @param options - The email options including recipient, subject, and content\n * @returns A promise that resolves to the send result with message ID if successful\n * @throws {EmailError} If the SendGrid API request fails\n */\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? { email: this.fromEmail, name: this.fromName }\n : { email: this.fromEmail };\n\n const personalization: {\n to: Array<{ email: string; name?: string | undefined }>;\n cc?: Array<{ email: string; name?: string | undefined }> | undefined;\n bcc?: Array<{ email: string; name?: string | undefined }> | undefined;\n headers?: Record<string, string> | undefined;\n } = {\n to: this.formatAddresses(options.to),\n };\n\n if (options.cc) {\n personalization.cc = this.formatAddresses(options.cc);\n }\n if (options.bcc) {\n personalization.bcc = this.formatAddresses(options.bcc);\n }\n if (options.headers) {\n personalization.headers = options.headers;\n }\n\n const payload: Record<string, unknown> = {\n personalizations: [personalization],\n from,\n subject: options.subject,\n content: [],\n };\n\n const content: Array<{ type: string; value: string }> = [];\n if (options.text) {\n content.push({ type: \"text/plain\", value: options.text });\n }\n if (options.html) {\n content.push({ type: \"text/html\", value: options.html });\n }\n payload[\"content\"] = content;\n\n if (options.replyTo) {\n payload[\"reply_to\"] = this.formatAddress(options.replyTo);\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"attachments\"] = options.attachments.map((att) => ({\n filename: att.filename,\n content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n type: att.contentType,\n content_id: att.contentId,\n disposition: att.contentId ? \"inline\" : \"attachment\",\n }));\n }\n\n if (options.scheduledAt) {\n payload[\"send_at\"] = Math.floor(options.scheduledAt.getTime() / 1000);\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/mail/send`, {\n method: \"POST\",\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n // SendGrid returns 202 for success with no body\n if (response.status === 202) {\n const messageId = response.headers.get(\"x-message-id\");\n return {\n success: true,\n messageId: messageId ?? undefined,\n };\n }\n\n const data = await response.json().catch(() => ({})) as { errors?: Array<{ message: string }> };\n const errorMessage = data.errors?.[0]?.message || `HTTP ${response.status}`;\n\n return {\n success: false,\n error: errorMessage,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `SendGrid send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Sends multiple emails via the SendGrid API sequentially.\n *\n * Note: SendGrid does not support true batch sending via the standard API,\n * so emails are sent one at a time.\n *\n * @param options - The batch email options containing emails and error handling config\n * @returns A promise that resolves to the batch result with success/failure counts\n */\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n /**\n * Verifies the SendGrid API key by checking API scopes.\n *\n * @returns A promise that resolves to true if the API key is valid, false otherwise\n */\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/scopes`, {\n headers: {\n \"Authorization\": `Bearer ${this.apiKey}`,\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Converts a Uint8Array to a base64-encoded string.\n *\n * @param data - The binary data to encode\n * @returns The base64-encoded string\n */\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Creates a SendGrid provider instance.\n *\n * @param config - The provider configuration including API key and sender info\n * @returns A new SendGridProvider instance\n */\nexport function createSendGridProvider(config: EmailProviderConfig): SendGridProvider {\n return new SendGridProvider(config);\n}\n","/**\n * @parsrun/email - Postmark Provider\n * Edge-compatible Postmark email provider\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\nimport { EmailError, EmailErrorCodes } from \"../types.js\";\n\n/**\n * Postmark Email Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const postmark = new PostmarkProvider({\n * apiKey: process.env.POSTMARK_API_KEY,\n * fromEmail: 'hello@example.com',\n * fromName: 'My App',\n * });\n *\n * await postmark.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * ```\n */\nexport class PostmarkProvider implements EmailProvider {\n /** Provider type identifier */\n readonly type = \"postmark\" as const;\n\n private apiKey: string;\n private fromEmail: string;\n private fromName: string | undefined;\n private baseUrl = \"https://api.postmarkapp.com\";\n\n /**\n * Creates a new PostmarkProvider instance.\n *\n * @param config - The provider configuration including API key (server token) and sender info\n */\n constructor(config: EmailProviderConfig) {\n this.apiKey = config.apiKey;\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a)).join(\",\");\n }\n return this.formatAddress(addresses);\n }\n\n /**\n * Sends an email via the Postmark API.\n *\n * @param options - The email options including recipient, subject, and content\n * @returns A promise that resolves to the send result with message ID if successful\n * @throws {EmailError} If the Postmark API request fails\n */\n async send(options: EmailOptions): Promise<EmailResult> {\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const payload: Record<string, unknown> = {\n From: from,\n To: this.formatAddresses(options.to),\n Subject: options.subject,\n };\n\n if (options.html) payload[\"HtmlBody\"] = options.html;\n if (options.text) payload[\"TextBody\"] = options.text;\n if (options.replyTo) payload[\"ReplyTo\"] = this.formatAddress(options.replyTo);\n if (options.cc) payload[\"Cc\"] = this.formatAddresses(options.cc);\n if (options.bcc) payload[\"Bcc\"] = this.formatAddresses(options.bcc);\n\n if (options.headers) {\n payload[\"Headers\"] = Object.entries(options.headers).map(([Name, Value]) => ({ Name, Value }));\n }\n\n if (options.tags) {\n // Postmark uses Tag field (single tag) and Metadata for custom data\n const tagEntries = Object.entries(options.tags);\n if (tagEntries.length > 0 && tagEntries[0]) {\n payload[\"Tag\"] = tagEntries[0][1];\n }\n payload[\"Metadata\"] = options.tags;\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload[\"Attachments\"] = options.attachments.map((att) => ({\n Name: att.filename,\n Content: typeof att.content === \"string\"\n ? att.content\n : this.uint8ArrayToBase64(att.content),\n ContentType: att.contentType || \"application/octet-stream\",\n ContentID: att.contentId,\n }));\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/email`, {\n method: \"POST\",\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n body: JSON.stringify(payload),\n });\n\n const data = await response.json() as {\n MessageID?: string;\n ErrorCode?: number;\n Message?: string;\n };\n\n if (!response.ok || data.ErrorCode) {\n return {\n success: false,\n error: data.Message || `HTTP ${response.status}`,\n data,\n };\n }\n\n return {\n success: true,\n messageId: data.MessageID,\n data,\n };\n } catch (err) {\n throw new EmailError(\n `Postmark send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Sends multiple emails via Postmark's batch API.\n *\n * Postmark supports native batch sending of up to 500 emails in a single request.\n *\n * @param options - The batch email options containing emails and error handling config\n * @returns A promise that resolves to the batch result with success/failure counts\n * @throws {EmailError} If the Postmark batch API request fails\n */\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n // Postmark supports batch sending up to 500 emails\n const batchPayload = options.emails.map((email) => {\n const from = email.from\n ? this.formatAddress(email.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const item: Record<string, unknown> = {\n From: from,\n To: this.formatAddresses(email.to),\n Subject: email.subject,\n };\n\n if (email.html) item[\"HtmlBody\"] = email.html;\n if (email.text) item[\"TextBody\"] = email.text;\n if (email.replyTo) item[\"ReplyTo\"] = this.formatAddress(email.replyTo);\n if (email.cc) item[\"Cc\"] = this.formatAddresses(email.cc);\n if (email.bcc) item[\"Bcc\"] = this.formatAddresses(email.bcc);\n\n return item;\n });\n\n try {\n const response = await fetch(`${this.baseUrl}/email/batch`, {\n method: \"POST\",\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json\",\n },\n body: JSON.stringify(batchPayload),\n });\n\n const data = await response.json() as Array<{\n MessageID?: string;\n ErrorCode?: number;\n Message?: string;\n }>;\n\n const results: EmailResult[] = data.map((item) => ({\n success: !item.ErrorCode,\n messageId: item.MessageID,\n error: item.ErrorCode ? item.Message : undefined,\n data: item,\n }));\n\n const successful = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n } catch (err) {\n throw new EmailError(\n `Postmark batch send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n EmailErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Verifies the Postmark server token by checking server info.\n *\n * @returns A promise that resolves to true if the server token is valid, false otherwise\n */\n async verify(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/server`, {\n headers: {\n \"X-Postmark-Server-Token\": this.apiKey,\n \"Accept\": \"application/json\",\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Converts a Uint8Array to a base64-encoded string.\n *\n * @param data - The binary data to encode\n * @returns The base64-encoded string\n */\n private uint8ArrayToBase64(data: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < data.length; i++) {\n const byte = data[i];\n if (byte !== undefined) {\n binary += String.fromCharCode(byte);\n }\n }\n return btoa(binary);\n }\n}\n\n/**\n * Creates a Postmark provider instance.\n *\n * @param config - The provider configuration including server token and sender info\n * @returns A new PostmarkProvider instance\n */\nexport function createPostmarkProvider(config: EmailProviderConfig): PostmarkProvider {\n return new PostmarkProvider(config);\n}\n","/**\n * @parsrun/email - Console Provider\n * Development/testing email provider that logs to console\n */\n\nimport type {\n BatchEmailOptions,\n BatchEmailResult,\n EmailAddress,\n EmailOptions,\n EmailProvider,\n EmailProviderConfig,\n EmailResult,\n} from \"../types.js\";\n\n/**\n * Console Email Provider\n * Logs emails to console instead of sending them.\n * Useful for development and testing.\n *\n * @example\n * ```typescript\n * const console = new ConsoleProvider({\n * apiKey: 'not-needed',\n * fromEmail: 'test@example.com',\n * fromName: 'Test App',\n * });\n *\n * await console.send({\n * to: 'user@example.com',\n * subject: 'Hello',\n * html: '<p>Hello World!</p>',\n * });\n * // Logs email details to console\n * ```\n */\nexport class ConsoleProvider implements EmailProvider {\n /** Provider type identifier */\n readonly type = \"console\" as const;\n\n private fromEmail: string;\n private fromName: string | undefined;\n private messageCounter = 0;\n\n /**\n * Creates a new ConsoleProvider instance.\n *\n * @param config - The provider configuration (apiKey is not required for console provider)\n */\n constructor(config: EmailProviderConfig) {\n this.fromEmail = config.fromEmail;\n this.fromName = config.fromName;\n }\n\n private formatAddress(address: string | EmailAddress): string {\n if (typeof address === \"string\") {\n return address;\n }\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(\n addresses: string | string[] | EmailAddress | EmailAddress[]\n ): string {\n if (Array.isArray(addresses)) {\n return addresses.map((a) => this.formatAddress(a)).join(\", \");\n }\n return this.formatAddress(addresses);\n }\n\n /**\n * Logs an email to the console instead of sending it.\n *\n * @param options - The email options to log\n * @returns A promise that resolves to a successful result with a generated message ID\n */\n async send(options: EmailOptions): Promise<EmailResult> {\n this.messageCounter++;\n const messageId = `console-${Date.now()}-${this.messageCounter}`;\n\n const from = options.from\n ? this.formatAddress(options.from)\n : this.fromName\n ? `${this.fromName} <${this.fromEmail}>`\n : this.fromEmail;\n\n const separator = \"─\".repeat(60);\n\n console.log(`\\n${separator}`);\n console.log(\"📧 EMAIL (Console Provider)\");\n console.log(separator);\n console.log(`Message ID: ${messageId}`);\n console.log(`From: ${from}`);\n console.log(`To: ${this.formatAddresses(options.to)}`);\n if (options.cc) {\n console.log(`CC: ${this.formatAddresses(options.cc)}`);\n }\n if (options.bcc) {\n console.log(`BCC: ${this.formatAddresses(options.bcc)}`);\n }\n if (options.replyTo) {\n console.log(`Reply-To: ${this.formatAddress(options.replyTo)}`);\n }\n console.log(`Subject: ${options.subject}`);\n\n if (options.headers) {\n console.log(`Headers: ${JSON.stringify(options.headers)}`);\n }\n if (options.tags) {\n console.log(`Tags: ${JSON.stringify(options.tags)}`);\n }\n if (options.scheduledAt) {\n console.log(`Scheduled: ${options.scheduledAt.toISOString()}`);\n }\n if (options.attachments && options.attachments.length > 0) {\n console.log(`Attachments:`);\n for (const att of options.attachments) {\n const size = typeof att.content === \"string\"\n ? att.content.length\n : att.content.length;\n console.log(` - ${att.filename} (${att.contentType || \"unknown\"}, ${size} bytes)`);\n }\n }\n\n console.log(separator);\n if (options.text) {\n console.log(\"TEXT CONTENT:\");\n console.log(options.text);\n }\n if (options.html) {\n console.log(\"HTML CONTENT:\");\n console.log(options.html);\n }\n console.log(`${separator}\\n`);\n\n return {\n success: true,\n messageId,\n };\n }\n\n /**\n * Logs multiple emails to the console.\n *\n * @param options - The batch email options containing emails to log\n * @returns A promise that resolves to the batch result with success/failure counts\n */\n async sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult> {\n const results: EmailResult[] = [];\n let successful = 0;\n let failed = 0;\n\n console.log(`\\n📬 BATCH EMAIL (${options.emails.length} emails)`);\n\n for (const email of options.emails) {\n try {\n const result = await this.send(email);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n console.log(`📬 BATCH COMPLETE: ${successful} sent, ${failed} failed\\n`);\n\n return {\n total: options.emails.length,\n successful,\n failed,\n results,\n };\n }\n\n /**\n * Verifies the provider configuration.\n *\n * For the console provider, this always returns true and logs a message.\n *\n * @returns A promise that always resolves to true\n */\n async verify(): Promise<boolean> {\n console.log(\"📧 Console email provider verified (always returns true)\");\n return true;\n }\n}\n\n/**\n * Creates a Console provider instance.\n *\n * @param config - The provider configuration\n * @returns A new ConsoleProvider instance\n */\nexport function createConsoleProvider(config: EmailProviderConfig): ConsoleProvider {\n return new ConsoleProvider(config);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -26,21 +26,57 @@ import '@parsrun/types';
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
declare class PostmarkProvider implements EmailProvider {
|
|
29
|
+
/** Provider type identifier */
|
|
29
30
|
readonly type: "postmark";
|
|
30
31
|
private apiKey;
|
|
31
32
|
private fromEmail;
|
|
32
33
|
private fromName;
|
|
33
34
|
private baseUrl;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new PostmarkProvider instance.
|
|
37
|
+
*
|
|
38
|
+
* @param config - The provider configuration including API key (server token) and sender info
|
|
39
|
+
*/
|
|
34
40
|
constructor(config: EmailProviderConfig);
|
|
35
41
|
private formatAddress;
|
|
36
42
|
private formatAddresses;
|
|
43
|
+
/**
|
|
44
|
+
* Sends an email via the Postmark API.
|
|
45
|
+
*
|
|
46
|
+
* @param options - The email options including recipient, subject, and content
|
|
47
|
+
* @returns A promise that resolves to the send result with message ID if successful
|
|
48
|
+
* @throws {EmailError} If the Postmark API request fails
|
|
49
|
+
*/
|
|
37
50
|
send(options: EmailOptions): Promise<EmailResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Sends multiple emails via Postmark's batch API.
|
|
53
|
+
*
|
|
54
|
+
* Postmark supports native batch sending of up to 500 emails in a single request.
|
|
55
|
+
*
|
|
56
|
+
* @param options - The batch email options containing emails and error handling config
|
|
57
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
58
|
+
* @throws {EmailError} If the Postmark batch API request fails
|
|
59
|
+
*/
|
|
38
60
|
sendBatch(options: BatchEmailOptions): Promise<BatchEmailResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Verifies the Postmark server token by checking server info.
|
|
63
|
+
*
|
|
64
|
+
* @returns A promise that resolves to true if the server token is valid, false otherwise
|
|
65
|
+
*/
|
|
39
66
|
verify(): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Converts a Uint8Array to a base64-encoded string.
|
|
69
|
+
*
|
|
70
|
+
* @param data - The binary data to encode
|
|
71
|
+
* @returns The base64-encoded string
|
|
72
|
+
*/
|
|
40
73
|
private uint8ArrayToBase64;
|
|
41
74
|
}
|
|
42
75
|
/**
|
|
43
|
-
*
|
|
76
|
+
* Creates a Postmark provider instance.
|
|
77
|
+
*
|
|
78
|
+
* @param config - The provider configuration including server token and sender info
|
|
79
|
+
* @returns A new PostmarkProvider instance
|
|
44
80
|
*/
|
|
45
81
|
declare function createPostmarkProvider(config: EmailProviderConfig): PostmarkProvider;
|
|
46
82
|
|
|
@@ -14,6 +14,13 @@ import {
|
|
|
14
14
|
emailConfig
|
|
15
15
|
} from "@parsrun/types";
|
|
16
16
|
var EmailError = class extends Error {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new EmailError instance.
|
|
19
|
+
*
|
|
20
|
+
* @param message - Human-readable error description
|
|
21
|
+
* @param code - Error code from EmailErrorCodes for programmatic handling
|
|
22
|
+
* @param cause - The underlying error that caused this error, if any
|
|
23
|
+
*/
|
|
17
24
|
constructor(message, code, cause) {
|
|
18
25
|
super(message);
|
|
19
26
|
this.code = code;
|
|
@@ -34,11 +41,17 @@ var EmailErrorCodes = {
|
|
|
34
41
|
|
|
35
42
|
// src/providers/postmark.ts
|
|
36
43
|
var PostmarkProvider = class {
|
|
44
|
+
/** Provider type identifier */
|
|
37
45
|
type = "postmark";
|
|
38
46
|
apiKey;
|
|
39
47
|
fromEmail;
|
|
40
48
|
fromName;
|
|
41
49
|
baseUrl = "https://api.postmarkapp.com";
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new PostmarkProvider instance.
|
|
52
|
+
*
|
|
53
|
+
* @param config - The provider configuration including API key (server token) and sender info
|
|
54
|
+
*/
|
|
42
55
|
constructor(config) {
|
|
43
56
|
this.apiKey = config.apiKey;
|
|
44
57
|
this.fromEmail = config.fromEmail;
|
|
@@ -59,6 +72,13 @@ var PostmarkProvider = class {
|
|
|
59
72
|
}
|
|
60
73
|
return this.formatAddress(addresses);
|
|
61
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Sends an email via the Postmark API.
|
|
77
|
+
*
|
|
78
|
+
* @param options - The email options including recipient, subject, and content
|
|
79
|
+
* @returns A promise that resolves to the send result with message ID if successful
|
|
80
|
+
* @throws {EmailError} If the Postmark API request fails
|
|
81
|
+
*/
|
|
62
82
|
async send(options) {
|
|
63
83
|
const from = options.from ? this.formatAddress(options.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
64
84
|
const payload = {
|
|
@@ -120,6 +140,15 @@ var PostmarkProvider = class {
|
|
|
120
140
|
);
|
|
121
141
|
}
|
|
122
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Sends multiple emails via Postmark's batch API.
|
|
145
|
+
*
|
|
146
|
+
* Postmark supports native batch sending of up to 500 emails in a single request.
|
|
147
|
+
*
|
|
148
|
+
* @param options - The batch email options containing emails and error handling config
|
|
149
|
+
* @returns A promise that resolves to the batch result with success/failure counts
|
|
150
|
+
* @throws {EmailError} If the Postmark batch API request fails
|
|
151
|
+
*/
|
|
123
152
|
async sendBatch(options) {
|
|
124
153
|
const batchPayload = options.emails.map((email) => {
|
|
125
154
|
const from = email.from ? this.formatAddress(email.from) : this.fromName ? `${this.fromName} <${this.fromEmail}>` : this.fromEmail;
|
|
@@ -168,6 +197,11 @@ var PostmarkProvider = class {
|
|
|
168
197
|
);
|
|
169
198
|
}
|
|
170
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Verifies the Postmark server token by checking server info.
|
|
202
|
+
*
|
|
203
|
+
* @returns A promise that resolves to true if the server token is valid, false otherwise
|
|
204
|
+
*/
|
|
171
205
|
async verify() {
|
|
172
206
|
try {
|
|
173
207
|
const response = await fetch(`${this.baseUrl}/server`, {
|
|
@@ -181,6 +215,12 @@ var PostmarkProvider = class {
|
|
|
181
215
|
return false;
|
|
182
216
|
}
|
|
183
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Converts a Uint8Array to a base64-encoded string.
|
|
220
|
+
*
|
|
221
|
+
* @param data - The binary data to encode
|
|
222
|
+
* @returns The base64-encoded string
|
|
223
|
+
*/
|
|
184
224
|
uint8ArrayToBase64(data) {
|
|
185
225
|
let binary = "";
|
|
186
226
|
for (let i = 0; i < data.length; i++) {
|