@upyo/ses 0.2.0-dev.19

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.
@@ -0,0 +1,258 @@
1
+ import { Message, Receipt, Transport, TransportOptions } from "@upyo/core";
2
+
3
+ //#region src/config.d.ts
4
+
5
+ /**
6
+ * Authentication configuration for AWS SES.
7
+ *
8
+ * This is a discriminated union type that supports two authentication methods:
9
+ *
10
+ * - `credentials`: Basic access key and secret key authentication
11
+ * - `session`: Temporary credentials with session token
12
+ *
13
+ * **Note**: IAM role assumption (`assumeRole`) is not currently supported.
14
+ * If you need to use IAM roles, perform the AssumeRole operation externally
15
+ * (e.g., using AWS CLI or SDK) and use the resulting temporary credentials
16
+ * with the `session` authentication type.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // Basic credentials
21
+ * const auth: SesAuthentication = {
22
+ * type: "credentials",
23
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
24
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
25
+ * };
26
+ *
27
+ * // Session credentials (from external AssumeRole)
28
+ * const sessionAuth: SesAuthentication = {
29
+ * type: "session",
30
+ * accessKeyId: "ASIAXYZ...",
31
+ * secretAccessKey: "abc123...",
32
+ * sessionToken: "FwoGZXIvYXdzE...",
33
+ * };
34
+ * ```
35
+ */
36
+ type SesAuthentication = {
37
+ /** Authentication type identifier. */
38
+ readonly type: "credentials";
39
+ /** AWS access key ID. */
40
+ readonly accessKeyId: string;
41
+ /** AWS secret access key. */
42
+ readonly secretAccessKey: string;
43
+ } | {
44
+ /** Authentication type identifier. */
45
+ readonly type: "session";
46
+ /** AWS access key ID for temporary credentials. */
47
+ readonly accessKeyId: string;
48
+ /** AWS secret access key for temporary credentials. */
49
+ readonly secretAccessKey: string;
50
+ /** AWS session token for temporary credentials. */
51
+ readonly sessionToken: string;
52
+ };
53
+ /**
54
+ * Configuration options for the Amazon SES transport.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const config: SesConfig = {
59
+ * authentication: {
60
+ * type: "credentials",
61
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
62
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
63
+ * },
64
+ * region: "us-east-1",
65
+ * timeout: 30000,
66
+ * retries: 3,
67
+ * batchSize: 25,
68
+ * defaultTags: {
69
+ * environment: "production",
70
+ * service: "notifications",
71
+ * },
72
+ * };
73
+ * ```
74
+ */
75
+ interface SesConfig {
76
+ /** AWS authentication configuration. */
77
+ readonly authentication: SesAuthentication;
78
+ /**
79
+ * AWS region.
80
+ * @default "us-east-1"
81
+ */
82
+ readonly region?: string;
83
+ /**
84
+ * Request timeout in milliseconds.
85
+ * @default 30000
86
+ */
87
+ readonly timeout?: number;
88
+ /**
89
+ * Number of retry attempts on failure.
90
+ * @default 3
91
+ */
92
+ readonly retries?: number;
93
+ /**
94
+ * Whether to validate SSL certificates.
95
+ * @default true
96
+ */
97
+ readonly validateSsl?: boolean;
98
+ /** Additional HTTP headers to include in requests. */
99
+ readonly headers?: Record<string, string>;
100
+ /** SES configuration set name for tracking and reputation management. */
101
+ readonly configurationSetName?: string;
102
+ /** Default tags to apply to all sent emails. */
103
+ readonly defaultTags?: Record<string, string>;
104
+ /**
105
+ * Maximum number of messages to send concurrently in sendMany().
106
+ * @default 50
107
+ */
108
+ readonly batchSize?: number;
109
+ }
110
+ /**
111
+ * Resolved SES configuration with all optional fields filled with default values.
112
+ *
113
+ * This type is returned by `createSesConfig()` and used internally by `SesTransport`.
114
+ * It ensures all required fields have values, making the transport implementation simpler.
115
+ */
116
+ type ResolvedSesConfig = Required<Omit<SesConfig, "configurationSetName" | "defaultTags" | "batchSize">> & {
117
+ /** SES configuration set name (optional) */
118
+ readonly configurationSetName?: string;
119
+ /** Default tags to apply to all emails (always defined, may be empty) */
120
+ readonly defaultTags: Record<string, string>;
121
+ /** Maximum concurrent messages in batch operations */
122
+ readonly batchSize: number;
123
+ };
124
+ /**
125
+ * Creates a resolved SES configuration with default values applied.
126
+ *
127
+ * This function takes a partial SES configuration and fills in default values
128
+ * for all optional fields, ensuring the transport has all necessary configuration.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const config = createSesConfig({
133
+ * authentication: {
134
+ * type: "credentials",
135
+ * accessKeyId: "AKIA...",
136
+ * secretAccessKey: "wJal..",
137
+ * },
138
+ * region: "eu-west-1",
139
+ * });
140
+ *
141
+ * // config.timeout is now 30000 (default)
142
+ * // config.retries is now 3 (default)
143
+ * // config.batchSize is now 50 (default)
144
+ * ```
145
+ *
146
+ * @param config The SES configuration object.
147
+ * @returns A resolved configuration with all defaults applied.
148
+ */
149
+ //#endregion
150
+ //#region src/ses-transport.d.ts
151
+ /**
152
+ * Amazon SES email transport implementation.
153
+ *
154
+ * This transport sends emails through the AWS Simple Email Service (SES) using
155
+ * the v2 API. It supports AWS Signature v4 authentication, configurable
156
+ * retries, and concurrent batch sending.
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * import { SesTransport } from "@upyo/ses";
161
+ * import { createMessage } from "@upyo/core";
162
+ *
163
+ * const transport = new SesTransport({
164
+ * authentication: {
165
+ * type: "credentials",
166
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
167
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
168
+ * },
169
+ * region: "us-east-1",
170
+ * });
171
+ *
172
+ * const message = createMessage({
173
+ * from: "sender@example.com",
174
+ * to: "recipient@example.com",
175
+ * subject: "Hello from SES",
176
+ * content: { text: "This is a test message" },
177
+ * });
178
+ *
179
+ * const receipt = await transport.send(message);
180
+ * if (receipt.successful) {
181
+ * console.log("Email sent with ID:", receipt.messageId);
182
+ * }
183
+ * ```
184
+ */
185
+ declare class SesTransport implements Transport {
186
+ /** Resolved configuration with defaults applied */
187
+ config: ResolvedSesConfig;
188
+ /** HTTP client for SES API requests */
189
+ private httpClient;
190
+ /**
191
+ * Creates a new SES transport instance.
192
+ *
193
+ * @param config SES configuration options.
194
+ */
195
+ constructor(config: SesConfig);
196
+ /**
197
+ * Sends a single email message through Amazon SES.
198
+ *
199
+ * This method converts the message to SES format, sends it via the SES v2 API,
200
+ * and returns a receipt indicating success or failure.
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const message = createMessage({
205
+ * from: "sender@example.com",
206
+ * to: "recipient@example.com",
207
+ * subject: "Hello",
208
+ * content: { text: "Hello, world!" },
209
+ * attachments: [{
210
+ * filename: "document.pdf",
211
+ * content: Promise.resolve(pdfBytes),
212
+ * contentType: "application/pdf",
213
+ * }],
214
+ * });
215
+ *
216
+ * const receipt = await transport.send(message);
217
+ * ```
218
+ *
219
+ * @param message The email message to send.
220
+ * @param options Optional transport options (e.g., abort signal).
221
+ * @returns A promise that resolves to a receipt with the result.
222
+ */
223
+ send(message: Message, options?: TransportOptions): Promise<Receipt>;
224
+ /**
225
+ * Sends multiple email messages concurrently through Amazon SES.
226
+ *
227
+ * This method processes messages in batches (configurable via `batchSize`)
228
+ * and sends each batch concurrently to improve performance. It yields
229
+ * receipts as they become available, allowing for streaming processing of
230
+ * results.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const messages = [
235
+ * createMessage({ from: "sender@example.com", to: "user1@example.com", subject: "Hello 1", content: { text: "Message 1" } }),
236
+ * createMessage({ from: "sender@example.com", to: "user2@example.com", subject: "Hello 2", content: { text: "Message 2" } }),
237
+ * createMessage({ from: "sender@example.com", to: "user3@example.com", subject: "Hello 3", content: { text: "Message 3" } }),
238
+ * ];
239
+ *
240
+ * for await (const receipt of transport.sendMany(messages)) {
241
+ * if (receipt.successful) {
242
+ * console.log("Sent:", receipt.messageId);
243
+ * } else {
244
+ * console.error("Failed:", receipt.errorMessages);
245
+ * }
246
+ * }
247
+ * ```
248
+ *
249
+ * @param messages An iterable or async iterable of messages to send.
250
+ * @param options Optional transport options (e.g., abort signal).
251
+ * @returns Individual receipts for each message as they complete.
252
+ */
253
+ sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt>;
254
+ private sendConcurrent;
255
+ private extractMessageId;
256
+ }
257
+ //#endregion
258
+ export { SesAuthentication, SesConfig, SesTransport };
@@ -0,0 +1,258 @@
1
+ import { Message, Receipt, Transport, TransportOptions } from "@upyo/core";
2
+
3
+ //#region src/config.d.ts
4
+
5
+ /**
6
+ * Authentication configuration for AWS SES.
7
+ *
8
+ * This is a discriminated union type that supports two authentication methods:
9
+ *
10
+ * - `credentials`: Basic access key and secret key authentication
11
+ * - `session`: Temporary credentials with session token
12
+ *
13
+ * **Note**: IAM role assumption (`assumeRole`) is not currently supported.
14
+ * If you need to use IAM roles, perform the AssumeRole operation externally
15
+ * (e.g., using AWS CLI or SDK) and use the resulting temporary credentials
16
+ * with the `session` authentication type.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // Basic credentials
21
+ * const auth: SesAuthentication = {
22
+ * type: "credentials",
23
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
24
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
25
+ * };
26
+ *
27
+ * // Session credentials (from external AssumeRole)
28
+ * const sessionAuth: SesAuthentication = {
29
+ * type: "session",
30
+ * accessKeyId: "ASIAXYZ...",
31
+ * secretAccessKey: "abc123...",
32
+ * sessionToken: "FwoGZXIvYXdzE...",
33
+ * };
34
+ * ```
35
+ */
36
+ type SesAuthentication = {
37
+ /** Authentication type identifier. */
38
+ readonly type: "credentials";
39
+ /** AWS access key ID. */
40
+ readonly accessKeyId: string;
41
+ /** AWS secret access key. */
42
+ readonly secretAccessKey: string;
43
+ } | {
44
+ /** Authentication type identifier. */
45
+ readonly type: "session";
46
+ /** AWS access key ID for temporary credentials. */
47
+ readonly accessKeyId: string;
48
+ /** AWS secret access key for temporary credentials. */
49
+ readonly secretAccessKey: string;
50
+ /** AWS session token for temporary credentials. */
51
+ readonly sessionToken: string;
52
+ };
53
+ /**
54
+ * Configuration options for the Amazon SES transport.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const config: SesConfig = {
59
+ * authentication: {
60
+ * type: "credentials",
61
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
62
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
63
+ * },
64
+ * region: "us-east-1",
65
+ * timeout: 30000,
66
+ * retries: 3,
67
+ * batchSize: 25,
68
+ * defaultTags: {
69
+ * environment: "production",
70
+ * service: "notifications",
71
+ * },
72
+ * };
73
+ * ```
74
+ */
75
+ interface SesConfig {
76
+ /** AWS authentication configuration. */
77
+ readonly authentication: SesAuthentication;
78
+ /**
79
+ * AWS region.
80
+ * @default "us-east-1"
81
+ */
82
+ readonly region?: string;
83
+ /**
84
+ * Request timeout in milliseconds.
85
+ * @default 30000
86
+ */
87
+ readonly timeout?: number;
88
+ /**
89
+ * Number of retry attempts on failure.
90
+ * @default 3
91
+ */
92
+ readonly retries?: number;
93
+ /**
94
+ * Whether to validate SSL certificates.
95
+ * @default true
96
+ */
97
+ readonly validateSsl?: boolean;
98
+ /** Additional HTTP headers to include in requests. */
99
+ readonly headers?: Record<string, string>;
100
+ /** SES configuration set name for tracking and reputation management. */
101
+ readonly configurationSetName?: string;
102
+ /** Default tags to apply to all sent emails. */
103
+ readonly defaultTags?: Record<string, string>;
104
+ /**
105
+ * Maximum number of messages to send concurrently in sendMany().
106
+ * @default 50
107
+ */
108
+ readonly batchSize?: number;
109
+ }
110
+ /**
111
+ * Resolved SES configuration with all optional fields filled with default values.
112
+ *
113
+ * This type is returned by `createSesConfig()` and used internally by `SesTransport`.
114
+ * It ensures all required fields have values, making the transport implementation simpler.
115
+ */
116
+ type ResolvedSesConfig = Required<Omit<SesConfig, "configurationSetName" | "defaultTags" | "batchSize">> & {
117
+ /** SES configuration set name (optional) */
118
+ readonly configurationSetName?: string;
119
+ /** Default tags to apply to all emails (always defined, may be empty) */
120
+ readonly defaultTags: Record<string, string>;
121
+ /** Maximum concurrent messages in batch operations */
122
+ readonly batchSize: number;
123
+ };
124
+ /**
125
+ * Creates a resolved SES configuration with default values applied.
126
+ *
127
+ * This function takes a partial SES configuration and fills in default values
128
+ * for all optional fields, ensuring the transport has all necessary configuration.
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const config = createSesConfig({
133
+ * authentication: {
134
+ * type: "credentials",
135
+ * accessKeyId: "AKIA...",
136
+ * secretAccessKey: "wJal..",
137
+ * },
138
+ * region: "eu-west-1",
139
+ * });
140
+ *
141
+ * // config.timeout is now 30000 (default)
142
+ * // config.retries is now 3 (default)
143
+ * // config.batchSize is now 50 (default)
144
+ * ```
145
+ *
146
+ * @param config The SES configuration object.
147
+ * @returns A resolved configuration with all defaults applied.
148
+ */
149
+ //#endregion
150
+ //#region src/ses-transport.d.ts
151
+ /**
152
+ * Amazon SES email transport implementation.
153
+ *
154
+ * This transport sends emails through the AWS Simple Email Service (SES) using
155
+ * the v2 API. It supports AWS Signature v4 authentication, configurable
156
+ * retries, and concurrent batch sending.
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * import { SesTransport } from "@upyo/ses";
161
+ * import { createMessage } from "@upyo/core";
162
+ *
163
+ * const transport = new SesTransport({
164
+ * authentication: {
165
+ * type: "credentials",
166
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
167
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
168
+ * },
169
+ * region: "us-east-1",
170
+ * });
171
+ *
172
+ * const message = createMessage({
173
+ * from: "sender@example.com",
174
+ * to: "recipient@example.com",
175
+ * subject: "Hello from SES",
176
+ * content: { text: "This is a test message" },
177
+ * });
178
+ *
179
+ * const receipt = await transport.send(message);
180
+ * if (receipt.successful) {
181
+ * console.log("Email sent with ID:", receipt.messageId);
182
+ * }
183
+ * ```
184
+ */
185
+ declare class SesTransport implements Transport {
186
+ /** Resolved configuration with defaults applied */
187
+ config: ResolvedSesConfig;
188
+ /** HTTP client for SES API requests */
189
+ private httpClient;
190
+ /**
191
+ * Creates a new SES transport instance.
192
+ *
193
+ * @param config SES configuration options.
194
+ */
195
+ constructor(config: SesConfig);
196
+ /**
197
+ * Sends a single email message through Amazon SES.
198
+ *
199
+ * This method converts the message to SES format, sends it via the SES v2 API,
200
+ * and returns a receipt indicating success or failure.
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const message = createMessage({
205
+ * from: "sender@example.com",
206
+ * to: "recipient@example.com",
207
+ * subject: "Hello",
208
+ * content: { text: "Hello, world!" },
209
+ * attachments: [{
210
+ * filename: "document.pdf",
211
+ * content: Promise.resolve(pdfBytes),
212
+ * contentType: "application/pdf",
213
+ * }],
214
+ * });
215
+ *
216
+ * const receipt = await transport.send(message);
217
+ * ```
218
+ *
219
+ * @param message The email message to send.
220
+ * @param options Optional transport options (e.g., abort signal).
221
+ * @returns A promise that resolves to a receipt with the result.
222
+ */
223
+ send(message: Message, options?: TransportOptions): Promise<Receipt>;
224
+ /**
225
+ * Sends multiple email messages concurrently through Amazon SES.
226
+ *
227
+ * This method processes messages in batches (configurable via `batchSize`)
228
+ * and sends each batch concurrently to improve performance. It yields
229
+ * receipts as they become available, allowing for streaming processing of
230
+ * results.
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const messages = [
235
+ * createMessage({ from: "sender@example.com", to: "user1@example.com", subject: "Hello 1", content: { text: "Message 1" } }),
236
+ * createMessage({ from: "sender@example.com", to: "user2@example.com", subject: "Hello 2", content: { text: "Message 2" } }),
237
+ * createMessage({ from: "sender@example.com", to: "user3@example.com", subject: "Hello 3", content: { text: "Message 3" } }),
238
+ * ];
239
+ *
240
+ * for await (const receipt of transport.sendMany(messages)) {
241
+ * if (receipt.successful) {
242
+ * console.log("Sent:", receipt.messageId);
243
+ * } else {
244
+ * console.error("Failed:", receipt.errorMessages);
245
+ * }
246
+ * }
247
+ * ```
248
+ *
249
+ * @param messages An iterable or async iterable of messages to send.
250
+ * @param options Optional transport options (e.g., abort signal).
251
+ * @returns Individual receipts for each message as they complete.
252
+ */
253
+ sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt>;
254
+ private sendConcurrent;
255
+ private extractMessageId;
256
+ }
257
+ //#endregion
258
+ export { SesAuthentication, SesConfig, SesTransport };