@upyo/lettermint 0.5.0-dev.136 → 0.5.0-dev.156
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 +94 -25
- package/dist/index.d.cts +22 -5
- package/dist/index.d.ts +22 -5
- package/dist/index.js +72 -25
- 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
|
/**
|
|
@@ -33,16 +57,22 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
33
57
|
*/
|
|
34
58
|
var LettermintApiError = class extends Error {
|
|
35
59
|
statusCode;
|
|
60
|
+
retryAfterMilliseconds;
|
|
61
|
+
attempts;
|
|
36
62
|
/**
|
|
37
63
|
* Creates a Lettermint API error.
|
|
38
64
|
*
|
|
39
65
|
* @param message Error message.
|
|
40
66
|
* @param statusCode HTTP status code.
|
|
67
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
68
|
+
* @param attempts Number of attempts made before this error.
|
|
41
69
|
*/
|
|
42
|
-
constructor(message, statusCode) {
|
|
70
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
43
71
|
super(message);
|
|
44
72
|
this.name = "LettermintApiError";
|
|
45
73
|
this.statusCode = statusCode;
|
|
74
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
75
|
+
this.attempts = attempts;
|
|
46
76
|
}
|
|
47
77
|
};
|
|
48
78
|
/**
|
|
@@ -51,16 +81,29 @@ var LettermintApiError = class extends Error {
|
|
|
51
81
|
* @since 0.5.0
|
|
52
82
|
*/
|
|
53
83
|
var LettermintTimeoutError = class extends Error {
|
|
84
|
+
/**
|
|
85
|
+
* Request timeout in milliseconds.
|
|
86
|
+
*
|
|
87
|
+
* @since 0.5.0
|
|
88
|
+
*/
|
|
54
89
|
timeout;
|
|
55
90
|
/**
|
|
91
|
+
* Number of attempts made before this error was produced.
|
|
92
|
+
*
|
|
93
|
+
* @since 0.5.0
|
|
94
|
+
*/
|
|
95
|
+
attempts;
|
|
96
|
+
/**
|
|
56
97
|
* Creates a Lettermint request timeout error.
|
|
57
98
|
*
|
|
58
99
|
* @param timeout Request timeout in milliseconds.
|
|
100
|
+
* @param attempts Number of attempts made before this error.
|
|
59
101
|
*/
|
|
60
|
-
constructor(timeout) {
|
|
102
|
+
constructor(timeout, attempts) {
|
|
61
103
|
super(`Lettermint API request timed out after ${timeout} ms.`);
|
|
62
104
|
this.name = "LettermintTimeoutError";
|
|
63
105
|
this.timeout = timeout;
|
|
106
|
+
this.attempts = attempts;
|
|
64
107
|
}
|
|
65
108
|
};
|
|
66
109
|
/**
|
|
@@ -109,7 +152,7 @@ var LettermintHttpClient = class {
|
|
|
109
152
|
try {
|
|
110
153
|
const response = await this.fetchWithAuth(url, body, signal, idempotencyKey);
|
|
111
154
|
const text = await response.text();
|
|
112
|
-
if (!response.ok) throw new LettermintApiError(parseErrorMessage(text, response.status), response.status);
|
|
155
|
+
if (!response.ok) throw new LettermintApiError(parseErrorMessage(text, response.status), response.status, (0, __upyo_core.parseRetryAfter)(response.headers.get("Retry-After")), attempt + 1);
|
|
113
156
|
try {
|
|
114
157
|
return JSON.parse(text);
|
|
115
158
|
} catch (error) {
|
|
@@ -119,7 +162,7 @@ var LettermintHttpClient = class {
|
|
|
119
162
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
120
163
|
if (error instanceof LettermintApiError && !isRetryable(error)) throw error;
|
|
121
164
|
if (error instanceof Error && error.name === "AbortError" && signal?.aborted) throw error;
|
|
122
|
-
if (attempt === this.config.retries) throw lastError;
|
|
165
|
+
if (attempt === this.config.retries) throw withAttempts(lastError, attempt + 1);
|
|
123
166
|
await sleep(calculateRetryDelay(attempt), signal);
|
|
124
167
|
}
|
|
125
168
|
}
|
|
@@ -151,6 +194,11 @@ var LettermintHttpClient = class {
|
|
|
151
194
|
}
|
|
152
195
|
}
|
|
153
196
|
};
|
|
197
|
+
function withAttempts(error, attempts) {
|
|
198
|
+
if (error instanceof LettermintTimeoutError) return new LettermintTimeoutError(error.timeout, attempts);
|
|
199
|
+
if (error instanceof LettermintApiError) return error;
|
|
200
|
+
return Object.assign(error, { attempts });
|
|
201
|
+
}
|
|
154
202
|
function isRetryable(error) {
|
|
155
203
|
return error.statusCode === 408 || error.statusCode === 429 || error.statusCode >= 500;
|
|
156
204
|
}
|
|
@@ -348,6 +396,7 @@ const MAX_BATCH_SIZE = 500;
|
|
|
348
396
|
* @since 0.5.0
|
|
349
397
|
*/
|
|
350
398
|
var LettermintTransport = class {
|
|
399
|
+
id = "lettermint";
|
|
351
400
|
/**
|
|
352
401
|
* The resolved Lettermint configuration used by this transport.
|
|
353
402
|
*/
|
|
@@ -379,10 +428,7 @@ var LettermintTransport = class {
|
|
|
379
428
|
return responseToReceipt(response);
|
|
380
429
|
} catch (error) {
|
|
381
430
|
if (isAbortError(error)) throw error;
|
|
382
|
-
return
|
|
383
|
-
successful: false,
|
|
384
|
-
errorMessages: [error instanceof Error ? error.message : String(error)]
|
|
385
|
-
};
|
|
431
|
+
return createLettermintFailure(error instanceof Error ? error.message : String(error), error);
|
|
386
432
|
}
|
|
387
433
|
}
|
|
388
434
|
/**
|
|
@@ -420,10 +466,7 @@ var LettermintTransport = class {
|
|
|
420
466
|
batchData.push(await convertMessage(message, this.config));
|
|
421
467
|
receipts.push(void 0);
|
|
422
468
|
} catch (error) {
|
|
423
|
-
receipts.push(
|
|
424
|
-
successful: false,
|
|
425
|
-
errorMessages: [error instanceof Error ? error.message : String(error)]
|
|
426
|
-
});
|
|
469
|
+
receipts.push(createLettermintFailure(error instanceof Error ? error.message : String(error), error));
|
|
427
470
|
}
|
|
428
471
|
if (batchData.length === 0) {
|
|
429
472
|
for (const receipt of receipts) if (receipt !== void 0) yield receipt;
|
|
@@ -450,10 +493,7 @@ var LettermintTransport = class {
|
|
|
450
493
|
yield receipt;
|
|
451
494
|
continue;
|
|
452
495
|
}
|
|
453
|
-
yield {
|
|
454
|
-
successful: false,
|
|
455
|
-
errorMessages: [errorMessage]
|
|
456
|
-
};
|
|
496
|
+
yield { ...createLettermintFailure(errorMessage, error) };
|
|
457
497
|
}
|
|
458
498
|
}
|
|
459
499
|
}
|
|
@@ -465,18 +505,47 @@ function hasIdempotencyKey(message) {
|
|
|
465
505
|
return message.idempotencyKey != null && message.idempotencyKey !== "";
|
|
466
506
|
}
|
|
467
507
|
function responseToReceipt(response) {
|
|
468
|
-
if (response?.message_id == null || response.message_id === "") return {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
508
|
+
if (response?.message_id == null || response.message_id === "") return (0, __upyo_core.createFailedReceipt)("Lettermint response is missing a message ID.", {
|
|
509
|
+
provider: "lettermint",
|
|
510
|
+
category: "unknown",
|
|
511
|
+
code: "lettermint.missing_message_id",
|
|
512
|
+
retryable: false
|
|
513
|
+
});
|
|
472
514
|
if (isSuccessfulStatus(response.status)) return {
|
|
473
515
|
successful: true,
|
|
474
|
-
messageId: response.message_id
|
|
475
|
-
|
|
476
|
-
return {
|
|
477
|
-
successful: false,
|
|
478
|
-
errorMessages: [`Lettermint reported message status "${response.status}".`]
|
|
516
|
+
messageId: response.message_id,
|
|
517
|
+
provider: "lettermint"
|
|
479
518
|
};
|
|
519
|
+
return (0, __upyo_core.createFailedReceipt)(`Lettermint reported message status "${response.status}".`, {
|
|
520
|
+
provider: "lettermint",
|
|
521
|
+
category: "rejected",
|
|
522
|
+
code: `lettermint.${response.status}`,
|
|
523
|
+
retryable: response.status === "soft_bounced"
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
function createLettermintFailure(message, error) {
|
|
527
|
+
if (error instanceof LettermintApiError) return (0, __upyo_core.createFailedReceipt)(message, {
|
|
528
|
+
provider: "lettermint",
|
|
529
|
+
statusCode: error.statusCode,
|
|
530
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
531
|
+
attempts: error.attempts
|
|
532
|
+
});
|
|
533
|
+
if (error instanceof LettermintTimeoutError) return (0, __upyo_core.createFailedReceipt)(message, {
|
|
534
|
+
provider: "lettermint",
|
|
535
|
+
category: "timeout",
|
|
536
|
+
code: "timeout",
|
|
537
|
+
retryable: true,
|
|
538
|
+
attempts: error.attempts
|
|
539
|
+
});
|
|
540
|
+
return (0, __upyo_core.createFailedReceipt)(message, {
|
|
541
|
+
provider: "lettermint",
|
|
542
|
+
attempts: getErrorAttempts(error)
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
function getErrorAttempts(error) {
|
|
546
|
+
if (typeof error !== "object" || error == null || !("attempts" in error)) return void 0;
|
|
547
|
+
const attempts = error.attempts;
|
|
548
|
+
return typeof attempts === "number" ? attempts : void 0;
|
|
480
549
|
}
|
|
481
550
|
function isSuccessfulStatus(status) {
|
|
482
551
|
switch (status) {
|
package/dist/index.d.cts
CHANGED
|
@@ -126,7 +126,8 @@ declare function createLettermintConfig(config: LettermintConfig): ResolvedLette
|
|
|
126
126
|
*
|
|
127
127
|
* @since 0.5.0
|
|
128
128
|
*/
|
|
129
|
-
declare class LettermintTransport implements Transport {
|
|
129
|
+
declare class LettermintTransport implements Transport<"lettermint"> {
|
|
130
|
+
readonly id = "lettermint";
|
|
130
131
|
/**
|
|
131
132
|
* The resolved Lettermint configuration used by this transport.
|
|
132
133
|
*/
|
|
@@ -145,7 +146,7 @@ declare class LettermintTransport implements Transport {
|
|
|
145
146
|
* @param options Optional transport options including `AbortSignal`.
|
|
146
147
|
* @returns A receipt indicating success or failure.
|
|
147
148
|
*/
|
|
148
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
149
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"lettermint">>;
|
|
149
150
|
/**
|
|
150
151
|
* Sends multiple email messages via Lettermint batch API.
|
|
151
152
|
*
|
|
@@ -155,7 +156,7 @@ declare class LettermintTransport implements Transport {
|
|
|
155
156
|
* @param options Optional transport options including `AbortSignal`.
|
|
156
157
|
* @returns An async iterable of receipts, one for each message.
|
|
157
158
|
*/
|
|
158
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
159
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"lettermint">>;
|
|
159
160
|
private sendBatch;
|
|
160
161
|
}
|
|
161
162
|
//#endregion
|
|
@@ -203,13 +204,17 @@ interface LettermintError {
|
|
|
203
204
|
*/
|
|
204
205
|
declare class LettermintApiError extends Error {
|
|
205
206
|
readonly statusCode: number;
|
|
207
|
+
readonly retryAfterMilliseconds?: number;
|
|
208
|
+
readonly attempts?: number;
|
|
206
209
|
/**
|
|
207
210
|
* Creates a Lettermint API error.
|
|
208
211
|
*
|
|
209
212
|
* @param message Error message.
|
|
210
213
|
* @param statusCode HTTP status code.
|
|
214
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
215
|
+
* @param attempts Number of attempts made before this error.
|
|
211
216
|
*/
|
|
212
|
-
constructor(message: string, statusCode: number);
|
|
217
|
+
constructor(message: string, statusCode: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
213
218
|
}
|
|
214
219
|
/**
|
|
215
220
|
* Lettermint request timeout error.
|
|
@@ -217,13 +222,25 @@ declare class LettermintApiError extends Error {
|
|
|
217
222
|
* @since 0.5.0
|
|
218
223
|
*/
|
|
219
224
|
declare class LettermintTimeoutError extends Error {
|
|
225
|
+
/**
|
|
226
|
+
* Request timeout in milliseconds.
|
|
227
|
+
*
|
|
228
|
+
* @since 0.5.0
|
|
229
|
+
*/
|
|
220
230
|
readonly timeout: number;
|
|
231
|
+
/**
|
|
232
|
+
* Number of attempts made before this error was produced.
|
|
233
|
+
*
|
|
234
|
+
* @since 0.5.0
|
|
235
|
+
*/
|
|
236
|
+
readonly attempts?: number;
|
|
221
237
|
/**
|
|
222
238
|
* Creates a Lettermint request timeout error.
|
|
223
239
|
*
|
|
224
240
|
* @param timeout Request timeout in milliseconds.
|
|
241
|
+
* @param attempts Number of attempts made before this error.
|
|
225
242
|
*/
|
|
226
|
-
constructor(timeout: number);
|
|
243
|
+
constructor(timeout: number, attempts?: number);
|
|
227
244
|
}
|
|
228
245
|
/**
|
|
229
246
|
* HTTP client wrapper for Lettermint API requests.
|
package/dist/index.d.ts
CHANGED
|
@@ -126,7 +126,8 @@ declare function createLettermintConfig(config: LettermintConfig): ResolvedLette
|
|
|
126
126
|
*
|
|
127
127
|
* @since 0.5.0
|
|
128
128
|
*/
|
|
129
|
-
declare class LettermintTransport implements Transport {
|
|
129
|
+
declare class LettermintTransport implements Transport<"lettermint"> {
|
|
130
|
+
readonly id = "lettermint";
|
|
130
131
|
/**
|
|
131
132
|
* The resolved Lettermint configuration used by this transport.
|
|
132
133
|
*/
|
|
@@ -145,7 +146,7 @@ declare class LettermintTransport implements Transport {
|
|
|
145
146
|
* @param options Optional transport options including `AbortSignal`.
|
|
146
147
|
* @returns A receipt indicating success or failure.
|
|
147
148
|
*/
|
|
148
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
149
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"lettermint">>;
|
|
149
150
|
/**
|
|
150
151
|
* Sends multiple email messages via Lettermint batch API.
|
|
151
152
|
*
|
|
@@ -155,7 +156,7 @@ declare class LettermintTransport implements Transport {
|
|
|
155
156
|
* @param options Optional transport options including `AbortSignal`.
|
|
156
157
|
* @returns An async iterable of receipts, one for each message.
|
|
157
158
|
*/
|
|
158
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
159
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"lettermint">>;
|
|
159
160
|
private sendBatch;
|
|
160
161
|
}
|
|
161
162
|
//#endregion
|
|
@@ -203,13 +204,17 @@ interface LettermintError {
|
|
|
203
204
|
*/
|
|
204
205
|
declare class LettermintApiError extends Error {
|
|
205
206
|
readonly statusCode: number;
|
|
207
|
+
readonly retryAfterMilliseconds?: number;
|
|
208
|
+
readonly attempts?: number;
|
|
206
209
|
/**
|
|
207
210
|
* Creates a Lettermint API error.
|
|
208
211
|
*
|
|
209
212
|
* @param message Error message.
|
|
210
213
|
* @param statusCode HTTP status code.
|
|
214
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
215
|
+
* @param attempts Number of attempts made before this error.
|
|
211
216
|
*/
|
|
212
|
-
constructor(message: string, statusCode: number);
|
|
217
|
+
constructor(message: string, statusCode: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
213
218
|
}
|
|
214
219
|
/**
|
|
215
220
|
* Lettermint request timeout error.
|
|
@@ -217,13 +222,25 @@ declare class LettermintApiError extends Error {
|
|
|
217
222
|
* @since 0.5.0
|
|
218
223
|
*/
|
|
219
224
|
declare class LettermintTimeoutError extends Error {
|
|
225
|
+
/**
|
|
226
|
+
* Request timeout in milliseconds.
|
|
227
|
+
*
|
|
228
|
+
* @since 0.5.0
|
|
229
|
+
*/
|
|
220
230
|
readonly timeout: number;
|
|
231
|
+
/**
|
|
232
|
+
* Number of attempts made before this error was produced.
|
|
233
|
+
*
|
|
234
|
+
* @since 0.5.0
|
|
235
|
+
*/
|
|
236
|
+
readonly attempts?: number;
|
|
221
237
|
/**
|
|
222
238
|
* Creates a Lettermint request timeout error.
|
|
223
239
|
*
|
|
224
240
|
* @param timeout Request timeout in milliseconds.
|
|
241
|
+
* @param attempts Number of attempts made before this error.
|
|
225
242
|
*/
|
|
226
|
-
constructor(timeout: number);
|
|
243
|
+
constructor(timeout: number, attempts?: number);
|
|
227
244
|
}
|
|
228
245
|
/**
|
|
229
246
|
* HTTP client wrapper for Lettermint API requests.
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createFailedReceipt, parseRetryAfter } from "@upyo/core";
|
|
2
|
+
|
|
1
3
|
//#region src/config.ts
|
|
2
4
|
/**
|
|
3
5
|
* Creates a resolved Lettermint configuration by applying default values.
|
|
@@ -32,16 +34,22 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
32
34
|
*/
|
|
33
35
|
var LettermintApiError = class extends Error {
|
|
34
36
|
statusCode;
|
|
37
|
+
retryAfterMilliseconds;
|
|
38
|
+
attempts;
|
|
35
39
|
/**
|
|
36
40
|
* Creates a Lettermint API error.
|
|
37
41
|
*
|
|
38
42
|
* @param message Error message.
|
|
39
43
|
* @param statusCode HTTP status code.
|
|
44
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
45
|
+
* @param attempts Number of attempts made before this error.
|
|
40
46
|
*/
|
|
41
|
-
constructor(message, statusCode) {
|
|
47
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
42
48
|
super(message);
|
|
43
49
|
this.name = "LettermintApiError";
|
|
44
50
|
this.statusCode = statusCode;
|
|
51
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
52
|
+
this.attempts = attempts;
|
|
45
53
|
}
|
|
46
54
|
};
|
|
47
55
|
/**
|
|
@@ -50,16 +58,29 @@ var LettermintApiError = class extends Error {
|
|
|
50
58
|
* @since 0.5.0
|
|
51
59
|
*/
|
|
52
60
|
var LettermintTimeoutError = class extends Error {
|
|
61
|
+
/**
|
|
62
|
+
* Request timeout in milliseconds.
|
|
63
|
+
*
|
|
64
|
+
* @since 0.5.0
|
|
65
|
+
*/
|
|
53
66
|
timeout;
|
|
54
67
|
/**
|
|
68
|
+
* Number of attempts made before this error was produced.
|
|
69
|
+
*
|
|
70
|
+
* @since 0.5.0
|
|
71
|
+
*/
|
|
72
|
+
attempts;
|
|
73
|
+
/**
|
|
55
74
|
* Creates a Lettermint request timeout error.
|
|
56
75
|
*
|
|
57
76
|
* @param timeout Request timeout in milliseconds.
|
|
77
|
+
* @param attempts Number of attempts made before this error.
|
|
58
78
|
*/
|
|
59
|
-
constructor(timeout) {
|
|
79
|
+
constructor(timeout, attempts) {
|
|
60
80
|
super(`Lettermint API request timed out after ${timeout} ms.`);
|
|
61
81
|
this.name = "LettermintTimeoutError";
|
|
62
82
|
this.timeout = timeout;
|
|
83
|
+
this.attempts = attempts;
|
|
63
84
|
}
|
|
64
85
|
};
|
|
65
86
|
/**
|
|
@@ -108,7 +129,7 @@ var LettermintHttpClient = class {
|
|
|
108
129
|
try {
|
|
109
130
|
const response = await this.fetchWithAuth(url, body, signal, idempotencyKey);
|
|
110
131
|
const text = await response.text();
|
|
111
|
-
if (!response.ok) throw new LettermintApiError(parseErrorMessage(text, response.status), response.status);
|
|
132
|
+
if (!response.ok) throw new LettermintApiError(parseErrorMessage(text, response.status), response.status, parseRetryAfter(response.headers.get("Retry-After")), attempt + 1);
|
|
112
133
|
try {
|
|
113
134
|
return JSON.parse(text);
|
|
114
135
|
} catch (error) {
|
|
@@ -118,7 +139,7 @@ var LettermintHttpClient = class {
|
|
|
118
139
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
119
140
|
if (error instanceof LettermintApiError && !isRetryable(error)) throw error;
|
|
120
141
|
if (error instanceof Error && error.name === "AbortError" && signal?.aborted) throw error;
|
|
121
|
-
if (attempt === this.config.retries) throw lastError;
|
|
142
|
+
if (attempt === this.config.retries) throw withAttempts(lastError, attempt + 1);
|
|
122
143
|
await sleep(calculateRetryDelay(attempt), signal);
|
|
123
144
|
}
|
|
124
145
|
}
|
|
@@ -150,6 +171,11 @@ var LettermintHttpClient = class {
|
|
|
150
171
|
}
|
|
151
172
|
}
|
|
152
173
|
};
|
|
174
|
+
function withAttempts(error, attempts) {
|
|
175
|
+
if (error instanceof LettermintTimeoutError) return new LettermintTimeoutError(error.timeout, attempts);
|
|
176
|
+
if (error instanceof LettermintApiError) return error;
|
|
177
|
+
return Object.assign(error, { attempts });
|
|
178
|
+
}
|
|
153
179
|
function isRetryable(error) {
|
|
154
180
|
return error.statusCode === 408 || error.statusCode === 429 || error.statusCode >= 500;
|
|
155
181
|
}
|
|
@@ -347,6 +373,7 @@ const MAX_BATCH_SIZE = 500;
|
|
|
347
373
|
* @since 0.5.0
|
|
348
374
|
*/
|
|
349
375
|
var LettermintTransport = class {
|
|
376
|
+
id = "lettermint";
|
|
350
377
|
/**
|
|
351
378
|
* The resolved Lettermint configuration used by this transport.
|
|
352
379
|
*/
|
|
@@ -378,10 +405,7 @@ var LettermintTransport = class {
|
|
|
378
405
|
return responseToReceipt(response);
|
|
379
406
|
} catch (error) {
|
|
380
407
|
if (isAbortError(error)) throw error;
|
|
381
|
-
return
|
|
382
|
-
successful: false,
|
|
383
|
-
errorMessages: [error instanceof Error ? error.message : String(error)]
|
|
384
|
-
};
|
|
408
|
+
return createLettermintFailure(error instanceof Error ? error.message : String(error), error);
|
|
385
409
|
}
|
|
386
410
|
}
|
|
387
411
|
/**
|
|
@@ -419,10 +443,7 @@ var LettermintTransport = class {
|
|
|
419
443
|
batchData.push(await convertMessage(message, this.config));
|
|
420
444
|
receipts.push(void 0);
|
|
421
445
|
} catch (error) {
|
|
422
|
-
receipts.push(
|
|
423
|
-
successful: false,
|
|
424
|
-
errorMessages: [error instanceof Error ? error.message : String(error)]
|
|
425
|
-
});
|
|
446
|
+
receipts.push(createLettermintFailure(error instanceof Error ? error.message : String(error), error));
|
|
426
447
|
}
|
|
427
448
|
if (batchData.length === 0) {
|
|
428
449
|
for (const receipt of receipts) if (receipt !== void 0) yield receipt;
|
|
@@ -449,10 +470,7 @@ var LettermintTransport = class {
|
|
|
449
470
|
yield receipt;
|
|
450
471
|
continue;
|
|
451
472
|
}
|
|
452
|
-
yield {
|
|
453
|
-
successful: false,
|
|
454
|
-
errorMessages: [errorMessage]
|
|
455
|
-
};
|
|
473
|
+
yield { ...createLettermintFailure(errorMessage, error) };
|
|
456
474
|
}
|
|
457
475
|
}
|
|
458
476
|
}
|
|
@@ -464,18 +482,47 @@ function hasIdempotencyKey(message) {
|
|
|
464
482
|
return message.idempotencyKey != null && message.idempotencyKey !== "";
|
|
465
483
|
}
|
|
466
484
|
function responseToReceipt(response) {
|
|
467
|
-
if (response?.message_id == null || response.message_id === "") return {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
485
|
+
if (response?.message_id == null || response.message_id === "") return createFailedReceipt("Lettermint response is missing a message ID.", {
|
|
486
|
+
provider: "lettermint",
|
|
487
|
+
category: "unknown",
|
|
488
|
+
code: "lettermint.missing_message_id",
|
|
489
|
+
retryable: false
|
|
490
|
+
});
|
|
471
491
|
if (isSuccessfulStatus(response.status)) return {
|
|
472
492
|
successful: true,
|
|
473
|
-
messageId: response.message_id
|
|
474
|
-
|
|
475
|
-
return {
|
|
476
|
-
successful: false,
|
|
477
|
-
errorMessages: [`Lettermint reported message status "${response.status}".`]
|
|
493
|
+
messageId: response.message_id,
|
|
494
|
+
provider: "lettermint"
|
|
478
495
|
};
|
|
496
|
+
return createFailedReceipt(`Lettermint reported message status "${response.status}".`, {
|
|
497
|
+
provider: "lettermint",
|
|
498
|
+
category: "rejected",
|
|
499
|
+
code: `lettermint.${response.status}`,
|
|
500
|
+
retryable: response.status === "soft_bounced"
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
function createLettermintFailure(message, error) {
|
|
504
|
+
if (error instanceof LettermintApiError) return createFailedReceipt(message, {
|
|
505
|
+
provider: "lettermint",
|
|
506
|
+
statusCode: error.statusCode,
|
|
507
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
508
|
+
attempts: error.attempts
|
|
509
|
+
});
|
|
510
|
+
if (error instanceof LettermintTimeoutError) return createFailedReceipt(message, {
|
|
511
|
+
provider: "lettermint",
|
|
512
|
+
category: "timeout",
|
|
513
|
+
code: "timeout",
|
|
514
|
+
retryable: true,
|
|
515
|
+
attempts: error.attempts
|
|
516
|
+
});
|
|
517
|
+
return createFailedReceipt(message, {
|
|
518
|
+
provider: "lettermint",
|
|
519
|
+
attempts: getErrorAttempts(error)
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
function getErrorAttempts(error) {
|
|
523
|
+
if (typeof error !== "object" || error == null || !("attempts" in error)) return void 0;
|
|
524
|
+
const attempts = error.attempts;
|
|
525
|
+
return typeof attempts === "number" ? attempts : void 0;
|
|
479
526
|
}
|
|
480
527
|
function isSuccessfulStatus(status) {
|
|
481
528
|
switch (status) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/lettermint",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.156",
|
|
4
4
|
"description": "Lettermint transport for Upyo email library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -53,18 +53,13 @@
|
|
|
53
53
|
},
|
|
54
54
|
"sideEffects": false,
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@upyo/core": "0.5.0-dev.
|
|
56
|
+
"@upyo/core": "0.5.0-dev.156+edad9790"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@dotenvx/dotenvx": "^1.47.3",
|
|
60
59
|
"tsdown": "^0.12.7",
|
|
61
60
|
"typescript": "5.8.3"
|
|
62
61
|
},
|
|
63
62
|
"scripts": {
|
|
64
|
-
"
|
|
65
|
-
"prepublish": "tsdown",
|
|
66
|
-
"test": "tsdown && dotenvx run --ignore=MISSING_ENV_FILE -- node --experimental-transform-types --test",
|
|
67
|
-
"test:bun": "tsdown && bun test --timeout=30000 --env-file=.env",
|
|
68
|
-
"test:deno": "deno test --allow-env --allow-net --env-file=.env"
|
|
63
|
+
"prepublish": "mise run --no-deps :build"
|
|
69
64
|
}
|
|
70
65
|
}
|