glasswork 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/email/compiler/code-generator.d.ts +11 -0
  2. package/dist/email/compiler/code-generator.d.ts.map +1 -0
  3. package/dist/email/compiler/code-generator.js +319 -0
  4. package/dist/email/compiler/code-generator.js.map +1 -0
  5. package/dist/email/compiler/compile-templates.d.ts +68 -0
  6. package/dist/email/compiler/compile-templates.d.ts.map +1 -0
  7. package/dist/email/compiler/compile-templates.js +156 -0
  8. package/dist/email/compiler/compile-templates.js.map +1 -0
  9. package/dist/email/compiler/compiler.d.ts +30 -0
  10. package/dist/email/compiler/compiler.d.ts.map +1 -0
  11. package/dist/email/compiler/compiler.js +510 -0
  12. package/dist/email/compiler/compiler.js.map +1 -0
  13. package/dist/email/compiler/index.d.ts +4 -0
  14. package/dist/email/compiler/index.d.ts.map +1 -0
  15. package/dist/email/compiler/index.js +3 -0
  16. package/dist/email/compiler/index.js.map +1 -0
  17. package/dist/email/compiler/tokenizer.d.ts +7 -0
  18. package/dist/email/compiler/tokenizer.d.ts.map +1 -0
  19. package/dist/email/compiler/tokenizer.js +154 -0
  20. package/dist/email/compiler/tokenizer.js.map +1 -0
  21. package/dist/email/compiler/type-extractor.d.ts +11 -0
  22. package/dist/email/compiler/type-extractor.d.ts.map +1 -0
  23. package/dist/email/compiler/type-extractor.js +296 -0
  24. package/dist/email/compiler/type-extractor.js.map +1 -0
  25. package/dist/email/compiler/types.d.ts +108 -0
  26. package/dist/email/compiler/types.d.ts.map +1 -0
  27. package/dist/email/compiler/types.js +2 -0
  28. package/dist/email/compiler/types.js.map +1 -0
  29. package/dist/email/config.d.ts +89 -0
  30. package/dist/email/config.d.ts.map +1 -0
  31. package/dist/email/config.js +55 -0
  32. package/dist/email/config.js.map +1 -0
  33. package/dist/email/email-service.d.ts +54 -0
  34. package/dist/email/email-service.d.ts.map +1 -0
  35. package/dist/email/email-service.js +94 -0
  36. package/dist/email/email-service.js.map +1 -0
  37. package/dist/email/index.d.ts +12 -0
  38. package/dist/email/index.d.ts.map +1 -0
  39. package/dist/email/index.js +23 -0
  40. package/dist/email/index.js.map +1 -0
  41. package/dist/email/template-registry.d.ts +83 -0
  42. package/dist/email/template-registry.d.ts.map +1 -0
  43. package/dist/email/template-registry.js +85 -0
  44. package/dist/email/template-registry.js.map +1 -0
  45. package/dist/email/templated-email-service.d.ts +59 -0
  46. package/dist/email/templated-email-service.d.ts.map +1 -0
  47. package/dist/email/templated-email-service.js +63 -0
  48. package/dist/email/templated-email-service.js.map +1 -0
  49. package/dist/email/transports/index.d.ts +3 -0
  50. package/dist/email/transports/index.d.ts.map +1 -0
  51. package/dist/email/transports/index.js +3 -0
  52. package/dist/email/transports/index.js.map +1 -0
  53. package/dist/email/transports/mock-transport.d.ts +74 -0
  54. package/dist/email/transports/mock-transport.d.ts.map +1 -0
  55. package/dist/email/transports/mock-transport.js +102 -0
  56. package/dist/email/transports/mock-transport.js.map +1 -0
  57. package/dist/email/transports/ses-transport.d.ts +65 -0
  58. package/dist/email/transports/ses-transport.d.ts.map +1 -0
  59. package/dist/email/transports/ses-transport.js +290 -0
  60. package/dist/email/transports/ses-transport.js.map +1 -0
  61. package/dist/email/types.d.ts +128 -0
  62. package/dist/email/types.d.ts.map +1 -0
  63. package/dist/email/types.js +2 -0
  64. package/dist/email/types.js.map +1 -0
  65. package/dist/email/webhooks/handler-factory.d.ts +41 -0
  66. package/dist/email/webhooks/handler-factory.d.ts.map +1 -0
  67. package/dist/email/webhooks/handler-factory.js +136 -0
  68. package/dist/email/webhooks/handler-factory.js.map +1 -0
  69. package/dist/email/webhooks/index.d.ts +6 -0
  70. package/dist/email/webhooks/index.d.ts.map +1 -0
  71. package/dist/email/webhooks/index.js +9 -0
  72. package/dist/email/webhooks/index.js.map +1 -0
  73. package/dist/email/webhooks/notification-parser.d.ts +45 -0
  74. package/dist/email/webhooks/notification-parser.d.ts.map +1 -0
  75. package/dist/email/webhooks/notification-parser.js +150 -0
  76. package/dist/email/webhooks/notification-parser.js.map +1 -0
  77. package/dist/email/webhooks/signature-verification.d.ts +38 -0
  78. package/dist/email/webhooks/signature-verification.d.ts.map +1 -0
  79. package/dist/email/webhooks/signature-verification.js +179 -0
  80. package/dist/email/webhooks/signature-verification.js.map +1 -0
  81. package/dist/email/webhooks/subscription-handler.d.ts +37 -0
  82. package/dist/email/webhooks/subscription-handler.d.ts.map +1 -0
  83. package/dist/email/webhooks/subscription-handler.js +99 -0
  84. package/dist/email/webhooks/subscription-handler.js.map +1 -0
  85. package/dist/email/webhooks/types.d.ts +187 -0
  86. package/dist/email/webhooks/types.d.ts.map +1 -0
  87. package/dist/email/webhooks/types.js +5 -0
  88. package/dist/email/webhooks/types.js.map +1 -0
  89. package/dist/index.d.ts +9 -0
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +22 -0
  92. package/dist/index.js.map +1 -1
  93. package/package.json +10 -2
@@ -0,0 +1,63 @@
1
+ import { EmailService } from './email-service.js';
2
+ /**
3
+ * Templated email service with type-safe template sending
4
+ *
5
+ * Extends the base EmailService with template-aware sending methods.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Create service with templates
10
+ * const emailService = new TemplatedEmailService({
11
+ * config: { transport, from: 'noreply@example.com' },
12
+ * templates,
13
+ * });
14
+ *
15
+ * // Send with full type safety
16
+ * await emailService.send('welcome', {
17
+ * to: 'user@example.com',
18
+ * context: { name: 'Alice', verificationLink: '...' },
19
+ * });
20
+ * ```
21
+ */
22
+ export class TemplatedEmailService extends EmailService {
23
+ templates;
24
+ constructor(options) {
25
+ super(options.config, options.onSent);
26
+ this.templates = options.templates;
27
+ }
28
+ /**
29
+ * Sends a templated email
30
+ *
31
+ * @param template - Template name (type-safe)
32
+ * @param options - Send options including recipient and context
33
+ * @returns The send result with message ID
34
+ */
35
+ async send(template, options) {
36
+ // Render the template
37
+ const { html, text } = this.templates.render(template, options.context);
38
+ // Get default subject if not provided
39
+ const subject = options.subject || this.templates.getSubject(template);
40
+ if (!subject) {
41
+ throw new Error(`No subject provided and template "${template}" has no default subject`);
42
+ }
43
+ // Send using the base service
44
+ return this.sendRaw({
45
+ to: options.to,
46
+ subject,
47
+ html,
48
+ text,
49
+ cc: options.cc,
50
+ bcc: options.bcc,
51
+ }, {
52
+ from: options.from,
53
+ replyTo: options.replyTo,
54
+ });
55
+ }
56
+ /**
57
+ * Gets the template registry
58
+ */
59
+ getTemplates() {
60
+ return this.templates;
61
+ }
62
+ }
63
+ //# sourceMappingURL=templated-email-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templated-email-service.js","sourceRoot":"","sources":["../../src/email/templated-email-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,oBAAoB,CAAC;AAkBpE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,qBAEX,SAAQ,YAAY;IACH,SAAS,CAA+B;IAEzD,YAAY,OAIX;QACC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,CACR,QAAe,EACf,OAEC;QAED,sBAAsB;QACtB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAExE,sCAAsC;QACtC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,0BAA0B,CAAC,CAAC;QAC3F,CAAC;QAED,8BAA8B;QAC9B,OAAO,IAAI,CAAC,OAAO,CACjB;YACE,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,OAAO;YACP,IAAI;YACJ,IAAI;YACJ,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,EACD;YACE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { MockTransport, type StoredEmail } from './mock-transport.js';
2
+ export { SESTransport } from './ses-transport.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/email/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { MockTransport } from './mock-transport.js';
2
+ export { SESTransport } from './ses-transport.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/email/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAoB,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { EmailMessage, EmailResult, EmailTransport } from '../types.js';
2
+ /**
3
+ * Stored email for inspection in tests
4
+ */
5
+ export interface StoredEmail {
6
+ /** The original message */
7
+ message: EmailMessage;
8
+ /** The result returned */
9
+ result: EmailResult;
10
+ /** Timestamp when the email was "sent" */
11
+ sentAt: Date;
12
+ }
13
+ /**
14
+ * Mock email transport for testing
15
+ *
16
+ * Stores all sent emails in memory for inspection.
17
+ * Does not actually send any emails.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { MockTransport } from '@glasswork/email/testing';
22
+ *
23
+ * const transport = new MockTransport();
24
+ * const emailService = new EmailService({ transport, from: 'test@example.com' });
25
+ *
26
+ * await emailService.sendRaw({
27
+ * to: 'user@example.com',
28
+ * subject: 'Test',
29
+ * html: '<p>Hello</p>',
30
+ * });
31
+ *
32
+ * expect(transport.sentEmails).toHaveLength(1);
33
+ * expect(transport.sentEmails[0].message.to).toBe('user@example.com');
34
+ * ```
35
+ */
36
+ export declare class MockTransport implements EmailTransport {
37
+ readonly name = "mock";
38
+ /** All emails that have been "sent" */
39
+ readonly sentEmails: StoredEmail[];
40
+ /** Counter for generating message IDs */
41
+ private messageIdCounter;
42
+ /** Whether to simulate failures */
43
+ private shouldFail;
44
+ private failureError;
45
+ /**
46
+ * Sends an email (stores it in memory)
47
+ */
48
+ send(message: EmailMessage): Promise<EmailResult>;
49
+ /**
50
+ * Clears all stored emails
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * Makes the next send() call fail with an error
55
+ */
56
+ simulateFailure(error?: Error): void;
57
+ /**
58
+ * Gets the last sent email
59
+ */
60
+ get lastEmail(): StoredEmail | undefined;
61
+ /**
62
+ * Gets emails sent to a specific address
63
+ */
64
+ getEmailsTo(address: string): StoredEmail[];
65
+ /**
66
+ * Gets emails with a specific subject
67
+ */
68
+ getEmailsWithSubject(subject: string): StoredEmail[];
69
+ /**
70
+ * Checks if any email was sent to the given address
71
+ */
72
+ hasSentTo(address: string): boolean;
73
+ }
74
+ //# sourceMappingURL=mock-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-transport.d.ts","sourceRoot":"","sources":["../../../src/email/transports/mock-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,OAAO,EAAE,YAAY,CAAC;IACtB,0BAA0B;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,0CAA0C;IAC1C,MAAM,EAAE,IAAI,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,IAAI,UAAU;IAEvB,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,WAAW,EAAE,CAAM;IAExC,yCAAyC;IACzC,OAAO,CAAC,gBAAgB,CAAK;IAE7B,mCAAmC;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAsB;IAE1C;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAyBvD;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,eAAe,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAKpC;;OAEG;IACH,IAAI,SAAS,IAAI,WAAW,GAAG,SAAS,CAEvC;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE;IAU3C;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE;IAIpD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAGpC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Mock email transport for testing
3
+ *
4
+ * Stores all sent emails in memory for inspection.
5
+ * Does not actually send any emails.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { MockTransport } from '@glasswork/email/testing';
10
+ *
11
+ * const transport = new MockTransport();
12
+ * const emailService = new EmailService({ transport, from: 'test@example.com' });
13
+ *
14
+ * await emailService.sendRaw({
15
+ * to: 'user@example.com',
16
+ * subject: 'Test',
17
+ * html: '<p>Hello</p>',
18
+ * });
19
+ *
20
+ * expect(transport.sentEmails).toHaveLength(1);
21
+ * expect(transport.sentEmails[0].message.to).toBe('user@example.com');
22
+ * ```
23
+ */
24
+ export class MockTransport {
25
+ name = 'mock';
26
+ /** All emails that have been "sent" */
27
+ sentEmails = [];
28
+ /** Counter for generating message IDs */
29
+ messageIdCounter = 0;
30
+ /** Whether to simulate failures */
31
+ shouldFail = false;
32
+ failureError = null;
33
+ /**
34
+ * Sends an email (stores it in memory)
35
+ */
36
+ async send(message) {
37
+ if (this.shouldFail) {
38
+ const error = this.failureError || new Error('Mock transport failure');
39
+ this.shouldFail = false;
40
+ this.failureError = null;
41
+ throw error;
42
+ }
43
+ const result = {
44
+ messageId: `mock-${++this.messageIdCounter}-${Date.now()}`,
45
+ success: true,
46
+ metadata: {
47
+ provider: 'mock',
48
+ },
49
+ };
50
+ this.sentEmails.push({
51
+ message,
52
+ result,
53
+ sentAt: new Date(),
54
+ });
55
+ return result;
56
+ }
57
+ /**
58
+ * Clears all stored emails
59
+ */
60
+ clear() {
61
+ this.sentEmails.length = 0;
62
+ this.messageIdCounter = 0;
63
+ }
64
+ /**
65
+ * Makes the next send() call fail with an error
66
+ */
67
+ simulateFailure(error) {
68
+ this.shouldFail = true;
69
+ this.failureError = error || null;
70
+ }
71
+ /**
72
+ * Gets the last sent email
73
+ */
74
+ get lastEmail() {
75
+ return this.sentEmails[this.sentEmails.length - 1];
76
+ }
77
+ /**
78
+ * Gets emails sent to a specific address
79
+ */
80
+ getEmailsTo(address) {
81
+ return this.sentEmails.filter((email) => {
82
+ const to = email.message.to;
83
+ if (Array.isArray(to)) {
84
+ return to.includes(address);
85
+ }
86
+ return to === address;
87
+ });
88
+ }
89
+ /**
90
+ * Gets emails with a specific subject
91
+ */
92
+ getEmailsWithSubject(subject) {
93
+ return this.sentEmails.filter((email) => email.message.subject === subject);
94
+ }
95
+ /**
96
+ * Checks if any email was sent to the given address
97
+ */
98
+ hasSentTo(address) {
99
+ return this.getEmailsTo(address).length > 0;
100
+ }
101
+ }
102
+ //# sourceMappingURL=mock-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-transport.js","sourceRoot":"","sources":["../../../src/email/transports/mock-transport.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,MAAM,CAAC;IAEvB,uCAAuC;IAC9B,UAAU,GAAkB,EAAE,CAAC;IAExC,yCAAyC;IACjC,gBAAgB,GAAG,CAAC,CAAC;IAE7B,mCAAmC;IAC3B,UAAU,GAAG,KAAK,CAAC;IACnB,YAAY,GAAiB,IAAI,CAAC;IAE1C;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,OAAqB;QAC9B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAgB;YAC1B,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE;YAC1D,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE;gBACR,QAAQ,EAAE,MAAM;aACjB;SACF,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YACnB,OAAO;YACP,MAAM;YACN,MAAM,EAAE,IAAI,IAAI,EAAE;SACnB,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,KAAa;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,KAAK,IAAI,IAAI,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,OAAe;QACzB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACtC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;gBACtB,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;YACD,OAAO,EAAE,KAAK,OAAO,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,OAAe;QAClC,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,OAAe;QACvB,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9C,CAAC;CACF"}
@@ -0,0 +1,65 @@
1
+ import type { EmailMessage, EmailResult, EmailTransport, SESTransportConfig } from '../types.js';
2
+ /**
3
+ * AWS SES email transport
4
+ *
5
+ * Sends emails using AWS Simple Email Service (SES).
6
+ * Requires @aws-sdk/client-sesv2 as a peer dependency.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { SESTransport } from '@glasswork/email';
11
+ *
12
+ * const transport = new SESTransport({
13
+ * region: 'eu-west-1',
14
+ * configurationSet: 'my-config-set',
15
+ * });
16
+ * ```
17
+ */
18
+ export declare class SESTransport implements EmailTransport {
19
+ readonly name = "ses";
20
+ private client;
21
+ private readonly config;
22
+ constructor(config: SESTransportConfig);
23
+ /**
24
+ * Lazily initializes the SES client
25
+ */
26
+ private getClient;
27
+ send(message: EmailMessage): Promise<EmailResult>;
28
+ /**
29
+ * Sends a simple email without attachments
30
+ */
31
+ private sendSimpleEmail;
32
+ /**
33
+ * Sends a raw MIME email with attachments
34
+ */
35
+ private sendRawEmail;
36
+ /**
37
+ * Builds a MIME multipart message with attachments
38
+ */
39
+ private buildMimeMessage;
40
+ /**
41
+ * Adds MIME headers to the message
42
+ */
43
+ private addMimeHeaders;
44
+ /**
45
+ * Adds body parts (text and HTML) to the message
46
+ */
47
+ private addBodyParts;
48
+ /**
49
+ * Adds attachments to the message
50
+ */
51
+ private addAttachments;
52
+ /**
53
+ * Adds a single attachment to the message
54
+ */
55
+ private addSingleAttachment;
56
+ /**
57
+ * Encodes a header value for MIME (handles non-ASCII characters)
58
+ */
59
+ private encodeHeader;
60
+ /**
61
+ * Encodes content as quoted-printable
62
+ */
63
+ private encodeQuotedPrintable;
64
+ }
65
+ //# sourceMappingURL=ses-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ses-transport.d.ts","sourceRoot":"","sources":["../../../src/email/transports/ses-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjG;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,SAAS;IACtB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAEhC,MAAM,EAAE,kBAAkB;IAItC;;OAEG;YACW,SAAS;IAqBjB,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAYvD;;OAEG;YACW,eAAe;IAiE7B;;OAEG;YACW,YAAY;IAoD1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACH,OAAO,CAAC,cAAc;IAoBtB;;OAEG;IACH,OAAO,CAAC,YAAY;IA0BpB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACH,OAAO,CAAC,qBAAqB;CAsB9B"}
@@ -0,0 +1,290 @@
1
+ /**
2
+ * AWS SES email transport
3
+ *
4
+ * Sends emails using AWS Simple Email Service (SES).
5
+ * Requires @aws-sdk/client-sesv2 as a peer dependency.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { SESTransport } from '@glasswork/email';
10
+ *
11
+ * const transport = new SESTransport({
12
+ * region: 'eu-west-1',
13
+ * configurationSet: 'my-config-set',
14
+ * });
15
+ * ```
16
+ */
17
+ export class SESTransport {
18
+ name = 'ses';
19
+ client = null;
20
+ config;
21
+ constructor(config) {
22
+ this.config = config;
23
+ }
24
+ /**
25
+ * Lazily initializes the SES client
26
+ */
27
+ async getClient() {
28
+ if (this.client) {
29
+ return this.client;
30
+ }
31
+ if (this.config.client) {
32
+ this.client = this.config.client;
33
+ return this.client;
34
+ }
35
+ if (!this.client) {
36
+ // Dynamic import to avoid bundling AWS SDK when not used
37
+ const { SESv2Client } = await import('@aws-sdk/client-sesv2');
38
+ this.client = new SESv2Client({
39
+ region: this.config.region,
40
+ ...(this.config.endpoint && { endpoint: this.config.endpoint }),
41
+ });
42
+ }
43
+ return this.client;
44
+ }
45
+ async send(message) {
46
+ const client = await this.getClient();
47
+ // If there are attachments or custom headers, use raw email format
48
+ if ((message.attachments && message.attachments.length > 0) || message.headers) {
49
+ return this.sendRawEmail(client, message);
50
+ }
51
+ // Otherwise use simple email format
52
+ return this.sendSimpleEmail(client, message);
53
+ }
54
+ /**
55
+ * Sends a simple email without attachments
56
+ */
57
+ async sendSimpleEmail(client, message) {
58
+ const { SendEmailCommand } = this.config.sendEmailCommand !== undefined
59
+ ? { SendEmailCommand: this.config.sendEmailCommand }
60
+ : await import('@aws-sdk/client-sesv2');
61
+ const toAddresses = Array.isArray(message.to) ? message.to : [message.to];
62
+ const ccAddresses = message.cc
63
+ ? Array.isArray(message.cc)
64
+ ? message.cc
65
+ : [message.cc]
66
+ : undefined;
67
+ const bccAddresses = message.bcc
68
+ ? Array.isArray(message.bcc)
69
+ ? message.bcc
70
+ : [message.bcc]
71
+ : undefined;
72
+ const command = new SendEmailCommand({
73
+ FromEmailAddress: message.from,
74
+ ReplyToAddresses: message.replyTo ? [message.replyTo] : undefined,
75
+ Destination: {
76
+ ToAddresses: toAddresses,
77
+ CcAddresses: ccAddresses,
78
+ BccAddresses: bccAddresses,
79
+ },
80
+ Content: {
81
+ Simple: {
82
+ Subject: {
83
+ Data: message.subject,
84
+ Charset: 'UTF-8',
85
+ },
86
+ Body: {
87
+ Html: {
88
+ Data: message.html,
89
+ Charset: 'UTF-8',
90
+ },
91
+ ...(message.text && {
92
+ Text: {
93
+ Data: message.text,
94
+ Charset: 'UTF-8',
95
+ },
96
+ }),
97
+ },
98
+ },
99
+ },
100
+ ConfigurationSetName: this.config.configurationSet,
101
+ });
102
+ const result = await client.send(command);
103
+ if (!result.MessageId) {
104
+ throw new Error('SES did not return a message ID');
105
+ }
106
+ return {
107
+ messageId: result.MessageId,
108
+ success: true,
109
+ metadata: {
110
+ provider: 'ses',
111
+ region: this.config.region,
112
+ },
113
+ };
114
+ }
115
+ /**
116
+ * Sends a raw MIME email with attachments
117
+ */
118
+ async sendRawEmail(client, message) {
119
+ const { SendEmailCommand } = this.config.sendEmailCommand !== undefined
120
+ ? { SendEmailCommand: this.config.sendEmailCommand }
121
+ : await import('@aws-sdk/client-sesv2');
122
+ const rawMessage = this.buildMimeMessage(message);
123
+ const toAddresses = Array.isArray(message.to) ? message.to : [message.to];
124
+ const ccAddresses = message.cc
125
+ ? Array.isArray(message.cc)
126
+ ? message.cc
127
+ : [message.cc]
128
+ : undefined;
129
+ const bccAddresses = message.bcc
130
+ ? Array.isArray(message.bcc)
131
+ ? message.bcc
132
+ : [message.bcc]
133
+ : undefined;
134
+ const command = new SendEmailCommand({
135
+ FromEmailAddress: message.from,
136
+ Destination: {
137
+ ToAddresses: toAddresses,
138
+ CcAddresses: ccAddresses,
139
+ BccAddresses: bccAddresses,
140
+ },
141
+ Content: {
142
+ Raw: {
143
+ Data: new TextEncoder().encode(rawMessage),
144
+ },
145
+ },
146
+ ConfigurationSetName: this.config.configurationSet,
147
+ });
148
+ const result = await client.send(command);
149
+ if (!result.MessageId) {
150
+ throw new Error('SES did not return a message ID');
151
+ }
152
+ return {
153
+ messageId: result.MessageId,
154
+ success: true,
155
+ metadata: {
156
+ provider: 'ses',
157
+ region: this.config.region,
158
+ hasAttachments: true,
159
+ },
160
+ };
161
+ }
162
+ /**
163
+ * Builds a MIME multipart message with attachments
164
+ */
165
+ buildMimeMessage(message) {
166
+ const boundary = `----=_Part_${Date.now()}_${Math.random().toString(36).slice(2)}`;
167
+ const lines = [];
168
+ this.addMimeHeaders(lines, message, boundary);
169
+ this.addBodyParts(lines, message, boundary);
170
+ this.addAttachments(lines, message, boundary);
171
+ lines.push(`--${boundary}--`);
172
+ return lines.join('\r\n');
173
+ }
174
+ /**
175
+ * Adds MIME headers to the message
176
+ */
177
+ addMimeHeaders(lines, message, boundary) {
178
+ lines.push(`From: ${message.from}`);
179
+ lines.push(`To: ${Array.isArray(message.to) ? message.to.join(', ') : message.to}`);
180
+ if (message.cc) {
181
+ lines.push(`Cc: ${Array.isArray(message.cc) ? message.cc.join(', ') : message.cc}`);
182
+ }
183
+ if (message.replyTo) {
184
+ lines.push(`Reply-To: ${message.replyTo}`);
185
+ }
186
+ lines.push(`Subject: ${this.encodeHeader(message.subject)}`);
187
+ if (message.headers) {
188
+ for (const [headerName, headerValue] of Object.entries(message.headers)) {
189
+ lines.push(`${headerName}: ${headerValue}`);
190
+ }
191
+ }
192
+ lines.push('MIME-Version: 1.0');
193
+ lines.push(`Content-Type: multipart/mixed; boundary="${boundary}"`);
194
+ lines.push('');
195
+ }
196
+ /**
197
+ * Adds body parts (text and HTML) to the message
198
+ */
199
+ addBodyParts(lines, message, boundary) {
200
+ const altBoundary = `----=_Alt_${Date.now()}_${Math.random().toString(36).slice(2)}`;
201
+ lines.push(`--${boundary}`);
202
+ lines.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`);
203
+ lines.push('');
204
+ // Plain text part
205
+ if (message.text) {
206
+ lines.push(`--${altBoundary}`);
207
+ lines.push('Content-Type: text/plain; charset=UTF-8');
208
+ lines.push('Content-Transfer-Encoding: quoted-printable');
209
+ lines.push('');
210
+ lines.push(this.encodeQuotedPrintable(message.text));
211
+ lines.push('');
212
+ }
213
+ // HTML part
214
+ lines.push(`--${altBoundary}`);
215
+ lines.push('Content-Type: text/html; charset=UTF-8');
216
+ lines.push('Content-Transfer-Encoding: quoted-printable');
217
+ lines.push('');
218
+ lines.push(this.encodeQuotedPrintable(message.html));
219
+ lines.push('');
220
+ lines.push(`--${altBoundary}--`);
221
+ }
222
+ /**
223
+ * Adds attachments to the message
224
+ */
225
+ addAttachments(lines, message, boundary) {
226
+ if (!message.attachments) {
227
+ return;
228
+ }
229
+ for (const attachment of message.attachments) {
230
+ this.addSingleAttachment(lines, attachment, boundary);
231
+ }
232
+ }
233
+ /**
234
+ * Adds a single attachment to the message
235
+ */
236
+ addSingleAttachment(lines, attachment, boundary) {
237
+ lines.push(`--${boundary}`);
238
+ lines.push(`Content-Type: ${attachment.contentType || 'application/octet-stream'}; name="${attachment.filename}"`);
239
+ lines.push('Content-Transfer-Encoding: base64');
240
+ lines.push(`Content-Disposition: ${attachment.disposition || 'attachment'}; filename="${attachment.filename}"`);
241
+ if (attachment.contentId) {
242
+ lines.push(`Content-ID: <${attachment.contentId}>`);
243
+ }
244
+ lines.push('');
245
+ const content = typeof attachment.content === 'string'
246
+ ? attachment.content
247
+ : Buffer.from(attachment.content).toString('base64');
248
+ // Split base64 content into 76-character lines
249
+ for (let i = 0; i < content.length; i += 76) {
250
+ lines.push(content.slice(i, i + 76));
251
+ }
252
+ lines.push('');
253
+ }
254
+ /**
255
+ * Encodes a header value for MIME (handles non-ASCII characters)
256
+ */
257
+ encodeHeader(value) {
258
+ // Check if encoding is needed
259
+ if (/^[\x20-\x7E]*$/.test(value)) {
260
+ return value;
261
+ }
262
+ // Use RFC 2047 encoding
263
+ const encoded = Buffer.from(value, 'utf-8').toString('base64');
264
+ return `=?UTF-8?B?${encoded}?=`;
265
+ }
266
+ /**
267
+ * Encodes content as quoted-printable
268
+ */
269
+ encodeQuotedPrintable(text) {
270
+ return text
271
+ .split('')
272
+ .map((char) => {
273
+ const code = char.charCodeAt(0);
274
+ if ((code >= 33 && code <= 60) ||
275
+ (code >= 62 && code <= 126) ||
276
+ char === ' ' ||
277
+ char === '\t') {
278
+ return char;
279
+ }
280
+ if (char === '\r' || char === '\n') {
281
+ return char;
282
+ }
283
+ // Encode as =XX
284
+ return `=${code.toString(16).toUpperCase().padStart(2, '0')}`;
285
+ })
286
+ .join('')
287
+ .replace(/(.{75})/g, '$1=\r\n'); // Soft line breaks
288
+ }
289
+ }
290
+ //# sourceMappingURL=ses-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ses-transport.js","sourceRoot":"","sources":["../../../src/email/transports/ses-transport.ts"],"names":[],"mappings":"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"}