@upyo/ses 0.5.0-dev.86 → 0.5.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/index.cjs +104 -16
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +82 -16
- package/package.json +3 -8
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const __upyo_core = __toESM(require("@upyo/core"));
|
|
1
25
|
|
|
2
26
|
//#region src/config.ts
|
|
3
27
|
/**
|
|
@@ -56,6 +80,16 @@ var SesHttpClient = class {
|
|
|
56
80
|
signal
|
|
57
81
|
});
|
|
58
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Makes an HTTP request to the SES API with retry logic.
|
|
85
|
+
*
|
|
86
|
+
* @param url The URL to make the request to.
|
|
87
|
+
* @param options Fetch options.
|
|
88
|
+
* @returns Promise that resolves to the parsed response.
|
|
89
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
90
|
+
* @throws {SesApiError} If SES returns a client error or all retry attempts
|
|
91
|
+
* are exhausted.
|
|
92
|
+
*/
|
|
59
93
|
async makeRequest(url, options) {
|
|
60
94
|
let lastError = null;
|
|
61
95
|
for (let attempt = 0; attempt <= this.config.retries; attempt++) try {
|
|
@@ -72,16 +106,30 @@ var SesHttpClient = class {
|
|
|
72
106
|
} catch {
|
|
73
107
|
errorData = { message: text || `HTTP ${response.status}` };
|
|
74
108
|
}
|
|
75
|
-
throw new SesApiError(errorData.message || `HTTP ${response.status}`, response.status, errorData.errors);
|
|
109
|
+
throw new SesApiError(errorData.message || `HTTP ${response.status}`, response.status, errorData.errors, (0, __upyo_core.parseRetryAfter)(response.headers.get("Retry-After")), attempt + 1);
|
|
76
110
|
} catch (error) {
|
|
77
111
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
112
|
+
if (options.signal?.aborted) throw createAbortError(options.signal);
|
|
113
|
+
if (isAbortError$1(error)) throw error;
|
|
78
114
|
if (error instanceof SesApiError && error.statusCode && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
79
|
-
if (attempt === this.config.retries)
|
|
115
|
+
if (attempt === this.config.retries) {
|
|
116
|
+
if (lastError instanceof SesApiError) throw lastError;
|
|
117
|
+
throw new SesApiError(lastError.message, void 0, void 0, void 0, attempt + 1);
|
|
118
|
+
}
|
|
80
119
|
const delay = Math.pow(2, attempt) * 1e3;
|
|
81
|
-
await
|
|
120
|
+
await sleep(delay, options.signal);
|
|
82
121
|
}
|
|
83
122
|
throw lastError || /* @__PURE__ */ new Error("Request failed after all retries");
|
|
84
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Makes a signed fetch request to the SES API.
|
|
126
|
+
*
|
|
127
|
+
* @param url The URL to make the request to.
|
|
128
|
+
* @param options Fetch options.
|
|
129
|
+
* @returns Promise that resolves to the fetch response.
|
|
130
|
+
* @throws {Error} If the configured request timeout is reached.
|
|
131
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
132
|
+
*/
|
|
85
133
|
async fetchWithAuth(url, options) {
|
|
86
134
|
const credentials = await this.getCredentials();
|
|
87
135
|
const headers = new Headers(options.headers);
|
|
@@ -92,19 +140,18 @@ var SesHttpClient = class {
|
|
|
92
140
|
for (const [key, value] of Object.entries(this.config.headers)) signedHeaders.set(key, value);
|
|
93
141
|
const controller = new AbortController();
|
|
94
142
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
95
|
-
|
|
96
|
-
if (options.signal) {
|
|
97
|
-
signal = options.signal;
|
|
98
|
-
if (options.signal.aborted) controller.abort();
|
|
99
|
-
else options.signal.addEventListener("abort", () => controller.abort());
|
|
100
|
-
}
|
|
143
|
+
const combinedSignal = (0, __upyo_core.combineSignals)(controller.signal, options.signal);
|
|
101
144
|
try {
|
|
102
145
|
return await globalThis.fetch(url, {
|
|
103
146
|
...options,
|
|
104
147
|
headers: this.headersToRecord(signedHeaders),
|
|
105
|
-
signal
|
|
148
|
+
signal: combinedSignal.signal
|
|
106
149
|
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`SES API request timed out after ${this.config.timeout} ms.`);
|
|
152
|
+
throw error;
|
|
107
153
|
} finally {
|
|
154
|
+
combinedSignal.cleanup();
|
|
108
155
|
clearTimeout(timeoutId);
|
|
109
156
|
}
|
|
110
157
|
}
|
|
@@ -190,14 +237,39 @@ var SesHttpClient = class {
|
|
|
190
237
|
return record;
|
|
191
238
|
}
|
|
192
239
|
};
|
|
240
|
+
function isAbortError$1(error) {
|
|
241
|
+
return error instanceof Error && error.name === "AbortError";
|
|
242
|
+
}
|
|
243
|
+
function sleep(milliseconds, signal) {
|
|
244
|
+
if (signal?.aborted) return Promise.reject(createAbortError(signal));
|
|
245
|
+
return new Promise((resolve, reject) => {
|
|
246
|
+
function abort() {
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
signal?.removeEventListener("abort", abort);
|
|
249
|
+
reject(createAbortError(signal));
|
|
250
|
+
}
|
|
251
|
+
const timeoutId = setTimeout(() => {
|
|
252
|
+
signal?.removeEventListener("abort", abort);
|
|
253
|
+
resolve();
|
|
254
|
+
}, milliseconds);
|
|
255
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function createAbortError(signal) {
|
|
259
|
+
return signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
260
|
+
}
|
|
193
261
|
var SesApiError = class extends Error {
|
|
194
262
|
statusCode;
|
|
195
263
|
errors;
|
|
196
|
-
|
|
264
|
+
retryAfterMilliseconds;
|
|
265
|
+
attempts;
|
|
266
|
+
constructor(message, statusCode, errors, retryAfterMilliseconds, attempts) {
|
|
197
267
|
super(message);
|
|
198
268
|
this.name = "SesApiError";
|
|
199
269
|
this.statusCode = statusCode;
|
|
200
270
|
this.errors = errors;
|
|
271
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
272
|
+
this.attempts = attempts;
|
|
201
273
|
}
|
|
202
274
|
};
|
|
203
275
|
|
|
@@ -311,6 +383,7 @@ function formatAddress(address) {
|
|
|
311
383
|
* @since 0.2.0
|
|
312
384
|
*/
|
|
313
385
|
var SesTransport = class {
|
|
386
|
+
id = "ses";
|
|
314
387
|
/** Resolved configuration with defaults applied */
|
|
315
388
|
config;
|
|
316
389
|
/** HTTP client for SES API requests */
|
|
@@ -360,14 +433,13 @@ var SesTransport = class {
|
|
|
360
433
|
const messageId = this.extractMessageId(response);
|
|
361
434
|
return {
|
|
362
435
|
successful: true,
|
|
363
|
-
messageId
|
|
436
|
+
messageId,
|
|
437
|
+
provider: "ses"
|
|
364
438
|
};
|
|
365
439
|
} catch (error) {
|
|
440
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
366
441
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
367
|
-
return
|
|
368
|
-
successful: false,
|
|
369
|
-
errorMessages: [errorMessage]
|
|
370
|
-
};
|
|
442
|
+
return createSesFailure(errorMessage, error);
|
|
371
443
|
}
|
|
372
444
|
}
|
|
373
445
|
/**
|
|
@@ -430,6 +502,22 @@ var SesTransport = class {
|
|
|
430
502
|
return `ses-${timestamp}-${random}`;
|
|
431
503
|
}
|
|
432
504
|
};
|
|
505
|
+
function createSesFailure(message, error) {
|
|
506
|
+
if (error instanceof SesApiError) return (0, __upyo_core.createFailedReceipt)(message, {
|
|
507
|
+
provider: "ses",
|
|
508
|
+
statusCode: error.statusCode,
|
|
509
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
510
|
+
providerDetails: error.errors,
|
|
511
|
+
attempts: error.attempts
|
|
512
|
+
});
|
|
513
|
+
return (0, __upyo_core.createFailedReceipt)(message, { provider: "ses" });
|
|
514
|
+
}
|
|
515
|
+
function isCallerAbort(error, signal) {
|
|
516
|
+
return signal?.aborted === true && (isAbortError(error) || error === signal.reason);
|
|
517
|
+
}
|
|
518
|
+
function isAbortError(error) {
|
|
519
|
+
return error instanceof Error && error.name === "AbortError";
|
|
520
|
+
}
|
|
433
521
|
|
|
434
522
|
//#endregion
|
|
435
523
|
exports.SesTransport = SesTransport;
|
package/dist/index.d.cts
CHANGED
|
@@ -188,7 +188,8 @@ type ResolvedSesConfig = Required<Omit<SesConfig, "configurationSetName" | "defa
|
|
|
188
188
|
*
|
|
189
189
|
* @since 0.2.0
|
|
190
190
|
*/
|
|
191
|
-
declare class SesTransport implements Transport {
|
|
191
|
+
declare class SesTransport implements Transport<"ses"> {
|
|
192
|
+
readonly id = "ses";
|
|
192
193
|
/** Resolved configuration with defaults applied */
|
|
193
194
|
config: ResolvedSesConfig;
|
|
194
195
|
/** HTTP client for SES API requests */
|
|
@@ -226,7 +227,7 @@ declare class SesTransport implements Transport {
|
|
|
226
227
|
* @param options Optional transport options (e.g., abort signal).
|
|
227
228
|
* @returns A promise that resolves to a receipt with the result.
|
|
228
229
|
*/
|
|
229
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
230
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"ses">>;
|
|
230
231
|
/**
|
|
231
232
|
* Sends multiple email messages concurrently through Amazon SES.
|
|
232
233
|
*
|
|
@@ -256,7 +257,7 @@ declare class SesTransport implements Transport {
|
|
|
256
257
|
* @param options Optional transport options (e.g., abort signal).
|
|
257
258
|
* @returns Individual receipts for each message as they complete.
|
|
258
259
|
*/
|
|
259
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
260
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"ses">>;
|
|
260
261
|
private sendConcurrent;
|
|
261
262
|
private extractMessageId;
|
|
262
263
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -188,7 +188,8 @@ type ResolvedSesConfig = Required<Omit<SesConfig, "configurationSetName" | "defa
|
|
|
188
188
|
*
|
|
189
189
|
* @since 0.2.0
|
|
190
190
|
*/
|
|
191
|
-
declare class SesTransport implements Transport {
|
|
191
|
+
declare class SesTransport implements Transport<"ses"> {
|
|
192
|
+
readonly id = "ses";
|
|
192
193
|
/** Resolved configuration with defaults applied */
|
|
193
194
|
config: ResolvedSesConfig;
|
|
194
195
|
/** HTTP client for SES API requests */
|
|
@@ -226,7 +227,7 @@ declare class SesTransport implements Transport {
|
|
|
226
227
|
* @param options Optional transport options (e.g., abort signal).
|
|
227
228
|
* @returns A promise that resolves to a receipt with the result.
|
|
228
229
|
*/
|
|
229
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
230
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"ses">>;
|
|
230
231
|
/**
|
|
231
232
|
* Sends multiple email messages concurrently through Amazon SES.
|
|
232
233
|
*
|
|
@@ -256,7 +257,7 @@ declare class SesTransport implements Transport {
|
|
|
256
257
|
* @param options Optional transport options (e.g., abort signal).
|
|
257
258
|
* @returns Individual receipts for each message as they complete.
|
|
258
259
|
*/
|
|
259
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
260
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"ses">>;
|
|
260
261
|
private sendConcurrent;
|
|
261
262
|
private extractMessageId;
|
|
262
263
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { combineSignals, createFailedReceipt, parseRetryAfter } from "@upyo/core";
|
|
2
|
+
|
|
1
3
|
//#region src/config.ts
|
|
2
4
|
/**
|
|
3
5
|
* Creates a resolved SES configuration with default values applied.
|
|
@@ -55,6 +57,16 @@ var SesHttpClient = class {
|
|
|
55
57
|
signal
|
|
56
58
|
});
|
|
57
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Makes an HTTP request to the SES API with retry logic.
|
|
62
|
+
*
|
|
63
|
+
* @param url The URL to make the request to.
|
|
64
|
+
* @param options Fetch options.
|
|
65
|
+
* @returns Promise that resolves to the parsed response.
|
|
66
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
67
|
+
* @throws {SesApiError} If SES returns a client error or all retry attempts
|
|
68
|
+
* are exhausted.
|
|
69
|
+
*/
|
|
58
70
|
async makeRequest(url, options) {
|
|
59
71
|
let lastError = null;
|
|
60
72
|
for (let attempt = 0; attempt <= this.config.retries; attempt++) try {
|
|
@@ -71,16 +83,30 @@ var SesHttpClient = class {
|
|
|
71
83
|
} catch {
|
|
72
84
|
errorData = { message: text || `HTTP ${response.status}` };
|
|
73
85
|
}
|
|
74
|
-
throw new SesApiError(errorData.message || `HTTP ${response.status}`, response.status, errorData.errors);
|
|
86
|
+
throw new SesApiError(errorData.message || `HTTP ${response.status}`, response.status, errorData.errors, parseRetryAfter(response.headers.get("Retry-After")), attempt + 1);
|
|
75
87
|
} catch (error) {
|
|
76
88
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
89
|
+
if (options.signal?.aborted) throw createAbortError(options.signal);
|
|
90
|
+
if (isAbortError$1(error)) throw error;
|
|
77
91
|
if (error instanceof SesApiError && error.statusCode && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
78
|
-
if (attempt === this.config.retries)
|
|
92
|
+
if (attempt === this.config.retries) {
|
|
93
|
+
if (lastError instanceof SesApiError) throw lastError;
|
|
94
|
+
throw new SesApiError(lastError.message, void 0, void 0, void 0, attempt + 1);
|
|
95
|
+
}
|
|
79
96
|
const delay = Math.pow(2, attempt) * 1e3;
|
|
80
|
-
await
|
|
97
|
+
await sleep(delay, options.signal);
|
|
81
98
|
}
|
|
82
99
|
throw lastError || /* @__PURE__ */ new Error("Request failed after all retries");
|
|
83
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Makes a signed fetch request to the SES API.
|
|
103
|
+
*
|
|
104
|
+
* @param url The URL to make the request to.
|
|
105
|
+
* @param options Fetch options.
|
|
106
|
+
* @returns Promise that resolves to the fetch response.
|
|
107
|
+
* @throws {Error} If the configured request timeout is reached.
|
|
108
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
109
|
+
*/
|
|
84
110
|
async fetchWithAuth(url, options) {
|
|
85
111
|
const credentials = await this.getCredentials();
|
|
86
112
|
const headers = new Headers(options.headers);
|
|
@@ -91,19 +117,18 @@ var SesHttpClient = class {
|
|
|
91
117
|
for (const [key, value] of Object.entries(this.config.headers)) signedHeaders.set(key, value);
|
|
92
118
|
const controller = new AbortController();
|
|
93
119
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
94
|
-
|
|
95
|
-
if (options.signal) {
|
|
96
|
-
signal = options.signal;
|
|
97
|
-
if (options.signal.aborted) controller.abort();
|
|
98
|
-
else options.signal.addEventListener("abort", () => controller.abort());
|
|
99
|
-
}
|
|
120
|
+
const combinedSignal = combineSignals(controller.signal, options.signal);
|
|
100
121
|
try {
|
|
101
122
|
return await globalThis.fetch(url, {
|
|
102
123
|
...options,
|
|
103
124
|
headers: this.headersToRecord(signedHeaders),
|
|
104
|
-
signal
|
|
125
|
+
signal: combinedSignal.signal
|
|
105
126
|
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`SES API request timed out after ${this.config.timeout} ms.`);
|
|
129
|
+
throw error;
|
|
106
130
|
} finally {
|
|
131
|
+
combinedSignal.cleanup();
|
|
107
132
|
clearTimeout(timeoutId);
|
|
108
133
|
}
|
|
109
134
|
}
|
|
@@ -189,14 +214,39 @@ var SesHttpClient = class {
|
|
|
189
214
|
return record;
|
|
190
215
|
}
|
|
191
216
|
};
|
|
217
|
+
function isAbortError$1(error) {
|
|
218
|
+
return error instanceof Error && error.name === "AbortError";
|
|
219
|
+
}
|
|
220
|
+
function sleep(milliseconds, signal) {
|
|
221
|
+
if (signal?.aborted) return Promise.reject(createAbortError(signal));
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
function abort() {
|
|
224
|
+
clearTimeout(timeoutId);
|
|
225
|
+
signal?.removeEventListener("abort", abort);
|
|
226
|
+
reject(createAbortError(signal));
|
|
227
|
+
}
|
|
228
|
+
const timeoutId = setTimeout(() => {
|
|
229
|
+
signal?.removeEventListener("abort", abort);
|
|
230
|
+
resolve();
|
|
231
|
+
}, milliseconds);
|
|
232
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function createAbortError(signal) {
|
|
236
|
+
return signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
237
|
+
}
|
|
192
238
|
var SesApiError = class extends Error {
|
|
193
239
|
statusCode;
|
|
194
240
|
errors;
|
|
195
|
-
|
|
241
|
+
retryAfterMilliseconds;
|
|
242
|
+
attempts;
|
|
243
|
+
constructor(message, statusCode, errors, retryAfterMilliseconds, attempts) {
|
|
196
244
|
super(message);
|
|
197
245
|
this.name = "SesApiError";
|
|
198
246
|
this.statusCode = statusCode;
|
|
199
247
|
this.errors = errors;
|
|
248
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
249
|
+
this.attempts = attempts;
|
|
200
250
|
}
|
|
201
251
|
};
|
|
202
252
|
|
|
@@ -310,6 +360,7 @@ function formatAddress(address) {
|
|
|
310
360
|
* @since 0.2.0
|
|
311
361
|
*/
|
|
312
362
|
var SesTransport = class {
|
|
363
|
+
id = "ses";
|
|
313
364
|
/** Resolved configuration with defaults applied */
|
|
314
365
|
config;
|
|
315
366
|
/** HTTP client for SES API requests */
|
|
@@ -359,14 +410,13 @@ var SesTransport = class {
|
|
|
359
410
|
const messageId = this.extractMessageId(response);
|
|
360
411
|
return {
|
|
361
412
|
successful: true,
|
|
362
|
-
messageId
|
|
413
|
+
messageId,
|
|
414
|
+
provider: "ses"
|
|
363
415
|
};
|
|
364
416
|
} catch (error) {
|
|
417
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
365
418
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
366
|
-
return
|
|
367
|
-
successful: false,
|
|
368
|
-
errorMessages: [errorMessage]
|
|
369
|
-
};
|
|
419
|
+
return createSesFailure(errorMessage, error);
|
|
370
420
|
}
|
|
371
421
|
}
|
|
372
422
|
/**
|
|
@@ -429,6 +479,22 @@ var SesTransport = class {
|
|
|
429
479
|
return `ses-${timestamp}-${random}`;
|
|
430
480
|
}
|
|
431
481
|
};
|
|
482
|
+
function createSesFailure(message, error) {
|
|
483
|
+
if (error instanceof SesApiError) return createFailedReceipt(message, {
|
|
484
|
+
provider: "ses",
|
|
485
|
+
statusCode: error.statusCode,
|
|
486
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
487
|
+
providerDetails: error.errors,
|
|
488
|
+
attempts: error.attempts
|
|
489
|
+
});
|
|
490
|
+
return createFailedReceipt(message, { provider: "ses" });
|
|
491
|
+
}
|
|
492
|
+
function isCallerAbort(error, signal) {
|
|
493
|
+
return signal?.aborted === true && (isAbortError(error) || error === signal.reason);
|
|
494
|
+
}
|
|
495
|
+
function isAbortError(error) {
|
|
496
|
+
return error instanceof Error && error.name === "AbortError";
|
|
497
|
+
}
|
|
432
498
|
|
|
433
499
|
//#endregion
|
|
434
500
|
export { SesTransport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/ses",
|
|
3
|
-
"version": "0.5.0
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Amazon SES transport for Upyo email library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -55,18 +55,13 @@
|
|
|
55
55
|
},
|
|
56
56
|
"sideEffects": false,
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@upyo/core": "0.5.0
|
|
58
|
+
"@upyo/core": "0.5.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@dotenvx/dotenvx": "^1.47.3",
|
|
62
61
|
"tsdown": "^0.12.7",
|
|
63
62
|
"typescript": "5.8.3"
|
|
64
63
|
},
|
|
65
64
|
"scripts": {
|
|
66
|
-
"
|
|
67
|
-
"prepublish": "tsdown",
|
|
68
|
-
"test": "tsdown && dotenvx run --ignore=MISSING_ENV_FILE -- node --experimental-transform-types --test",
|
|
69
|
-
"test:bun": "tsdown && bun test --timeout=30000 --env-file=.env",
|
|
70
|
-
"test:deno": "deno test --allow-env --allow-net --env-file=.env"
|
|
65
|
+
"prepublish": "mise run --no-deps :build"
|
|
71
66
|
}
|
|
72
67
|
}
|