@parsrun/email 0.1.30 → 0.1.32

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.
@@ -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
- * Create a Postmark provider
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++) {