glasswork 0.10.0 → 0.12.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.
- package/dist/core/bootstrap.d.ts.map +1 -1
- package/dist/core/bootstrap.js +5 -0
- package/dist/core/bootstrap.js.map +1 -1
- package/dist/core/types.d.ts +11 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/email/compiler/compile-templates.d.ts +68 -0
- package/dist/email/compiler/compile-templates.d.ts.map +1 -0
- package/dist/email/compiler/compile-templates.js +156 -0
- package/dist/email/compiler/compile-templates.js.map +1 -0
- package/dist/email/compiler/compiler.d.ts +30 -0
- package/dist/email/compiler/compiler.d.ts.map +1 -0
- package/dist/email/compiler/compiler.js +510 -0
- package/dist/email/compiler/compiler.js.map +1 -0
- package/dist/email/compiler/index.d.ts +4 -0
- package/dist/email/compiler/index.d.ts.map +1 -0
- package/dist/email/compiler/index.js +3 -0
- package/dist/email/compiler/index.js.map +1 -0
- package/dist/email/compiler/tokenizer.d.ts +7 -0
- package/dist/email/compiler/tokenizer.d.ts.map +1 -0
- package/dist/email/compiler/tokenizer.js +154 -0
- package/dist/email/compiler/tokenizer.js.map +1 -0
- package/dist/email/compiler/type-extractor.d.ts +11 -0
- package/dist/email/compiler/type-extractor.d.ts.map +1 -0
- package/dist/email/compiler/type-extractor.js +296 -0
- package/dist/email/compiler/type-extractor.js.map +1 -0
- package/dist/email/compiler/types.d.ts +108 -0
- package/dist/email/compiler/types.d.ts.map +1 -0
- package/dist/email/compiler/types.js +2 -0
- package/dist/email/compiler/types.js.map +1 -0
- package/dist/email/config.d.ts +89 -0
- package/dist/email/config.d.ts.map +1 -0
- package/dist/email/config.js +55 -0
- package/dist/email/config.js.map +1 -0
- package/dist/email/email-service.d.ts +54 -0
- package/dist/email/email-service.d.ts.map +1 -0
- package/dist/email/email-service.js +94 -0
- package/dist/email/email-service.js.map +1 -0
- package/dist/email/index.d.ts +12 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +23 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/template-registry.d.ts +83 -0
- package/dist/email/template-registry.d.ts.map +1 -0
- package/dist/email/template-registry.js +85 -0
- package/dist/email/template-registry.js.map +1 -0
- package/dist/email/templated-email-service.d.ts +59 -0
- package/dist/email/templated-email-service.d.ts.map +1 -0
- package/dist/email/templated-email-service.js +63 -0
- package/dist/email/templated-email-service.js.map +1 -0
- package/dist/email/transports/index.d.ts +3 -0
- package/dist/email/transports/index.d.ts.map +1 -0
- package/dist/email/transports/index.js +3 -0
- package/dist/email/transports/index.js.map +1 -0
- package/dist/email/transports/mock-transport.d.ts +74 -0
- package/dist/email/transports/mock-transport.d.ts.map +1 -0
- package/dist/email/transports/mock-transport.js +102 -0
- package/dist/email/transports/mock-transport.js.map +1 -0
- package/dist/email/transports/ses-transport.d.ts +65 -0
- package/dist/email/transports/ses-transport.d.ts.map +1 -0
- package/dist/email/transports/ses-transport.js +290 -0
- package/dist/email/transports/ses-transport.js.map +1 -0
- package/dist/email/types.d.ts +128 -0
- package/dist/email/types.d.ts.map +1 -0
- package/dist/email/types.js +2 -0
- package/dist/email/types.js.map +1 -0
- package/dist/email/webhooks/handler-factory.d.ts +41 -0
- package/dist/email/webhooks/handler-factory.d.ts.map +1 -0
- package/dist/email/webhooks/handler-factory.js +136 -0
- package/dist/email/webhooks/handler-factory.js.map +1 -0
- package/dist/email/webhooks/index.d.ts +6 -0
- package/dist/email/webhooks/index.d.ts.map +1 -0
- package/dist/email/webhooks/index.js +9 -0
- package/dist/email/webhooks/index.js.map +1 -0
- package/dist/email/webhooks/notification-parser.d.ts +45 -0
- package/dist/email/webhooks/notification-parser.d.ts.map +1 -0
- package/dist/email/webhooks/notification-parser.js +150 -0
- package/dist/email/webhooks/notification-parser.js.map +1 -0
- package/dist/email/webhooks/signature-verification.d.ts +38 -0
- package/dist/email/webhooks/signature-verification.d.ts.map +1 -0
- package/dist/email/webhooks/signature-verification.js +179 -0
- package/dist/email/webhooks/signature-verification.js.map +1 -0
- package/dist/email/webhooks/subscription-handler.d.ts +37 -0
- package/dist/email/webhooks/subscription-handler.d.ts.map +1 -0
- package/dist/email/webhooks/subscription-handler.js +99 -0
- package/dist/email/webhooks/subscription-handler.js.map +1 -0
- package/dist/email/webhooks/types.d.ts +187 -0
- package/dist/email/webhooks/types.d.ts.map +1 -0
- package/dist/email/webhooks/types.js +5 -0
- package/dist/email/webhooks/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/list-query/builder.d.ts +5 -0
- package/dist/list-query/builder.d.ts.map +1 -1
- package/dist/list-query/builder.js +11 -3
- package/dist/list-query/builder.js.map +1 -1
- package/dist/list-query/validator.d.ts +3 -3
- package/dist/list-query/validator.d.ts.map +1 -1
- package/dist/list-query/validator.js.map +1 -1
- package/dist/middleware/rate-limit.d.ts +5 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +31 -0
- package/dist/middleware/rate-limit.js.map +1 -1
- package/dist/utils/get-client-ip.d.ts.map +1 -1
- package/dist/utils/get-client-ip.js +15 -10
- package/dist/utils/get-client-ip.js.map +1 -1
- package/package.json +25 -17
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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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"}
|