@upyo/resend 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 +98 -24
- package/dist/index.d.cts +28 -6
- package/dist/index.d.ts +28 -6
- package/dist/index.js +76 -24
- 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
|
/**
|
|
@@ -25,14 +49,37 @@ function createResendConfig(config) {
|
|
|
25
49
|
//#endregion
|
|
26
50
|
//#region src/http-client.ts
|
|
27
51
|
/**
|
|
28
|
-
*
|
|
52
|
+
* Error thrown when a Resend API request fails.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.5.0
|
|
29
55
|
*/
|
|
30
56
|
var ResendApiError = class extends Error {
|
|
57
|
+
/**
|
|
58
|
+
* HTTP status code returned by Resend, if the request reached the API.
|
|
59
|
+
*/
|
|
31
60
|
statusCode;
|
|
32
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Retry delay from Resend's `Retry-After` response header.
|
|
63
|
+
*/
|
|
64
|
+
retryAfterMilliseconds;
|
|
65
|
+
/**
|
|
66
|
+
* Number of attempts made before this error was produced.
|
|
67
|
+
*/
|
|
68
|
+
attempts;
|
|
69
|
+
/**
|
|
70
|
+
* Creates a Resend API error.
|
|
71
|
+
*
|
|
72
|
+
* @param message Error message.
|
|
73
|
+
* @param statusCode HTTP status code returned by Resend.
|
|
74
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
75
|
+
* @param attempts Number of attempts made before this error.
|
|
76
|
+
*/
|
|
77
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
33
78
|
super(message);
|
|
34
79
|
this.name = "ResendApiError";
|
|
35
80
|
this.statusCode = statusCode;
|
|
81
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
82
|
+
this.attempts = attempts;
|
|
36
83
|
}
|
|
37
84
|
};
|
|
38
85
|
/**
|
|
@@ -102,7 +149,10 @@ var ResendHttpClient = class {
|
|
|
102
149
|
const errorBody = JSON.parse(text);
|
|
103
150
|
errorMessage = errorBody.message;
|
|
104
151
|
} catch {}
|
|
105
|
-
|
|
152
|
+
const parsedErrorMessage = errorMessage === "" ? void 0 : errorMessage;
|
|
153
|
+
const responseMessage = truncateErrorBody(text);
|
|
154
|
+
const fallbackMessage = responseMessage === "" ? void 0 : responseMessage;
|
|
155
|
+
throw new ResendApiError(parsedErrorMessage ?? fallbackMessage ?? `HTTP ${response.status}`, response.status, (0, __upyo_core.parseRetryAfter)(response.headers.get("Retry-After")), attempt + 1);
|
|
106
156
|
}
|
|
107
157
|
try {
|
|
108
158
|
return JSON.parse(text);
|
|
@@ -110,10 +160,14 @@ var ResendHttpClient = class {
|
|
|
110
160
|
throw new Error(`Invalid JSON response from Resend API: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
111
161
|
}
|
|
112
162
|
} catch (error) {
|
|
163
|
+
if (isCallerAbort$1(error, options.signal)) throw error;
|
|
113
164
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
114
|
-
if (error instanceof ResendApiError && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
165
|
+
if (error instanceof ResendApiError && error.statusCode !== void 0 && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
115
166
|
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
116
|
-
if (attempt === this.config.retries)
|
|
167
|
+
if (attempt === this.config.retries) {
|
|
168
|
+
if (lastError instanceof ResendApiError) throw lastError;
|
|
169
|
+
throw new ResendApiError(lastError.message, void 0, void 0, attempt + 1);
|
|
170
|
+
}
|
|
117
171
|
const backoffMs = Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
118
172
|
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
119
173
|
}
|
|
@@ -132,26 +186,32 @@ var ResendHttpClient = class {
|
|
|
132
186
|
for (const [key, value] of Object.entries(this.config.headers)) headers.set(key, value);
|
|
133
187
|
const controller = new AbortController();
|
|
134
188
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
135
|
-
|
|
136
|
-
if (options.signal) {
|
|
137
|
-
const combinedController = new AbortController();
|
|
138
|
-
const onAbort = () => combinedController.abort();
|
|
139
|
-
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
140
|
-
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
141
|
-
signal = combinedController.signal;
|
|
142
|
-
} else signal = controller.signal;
|
|
189
|
+
const combinedSignal = (0, __upyo_core.combineSignals)(controller.signal, options.signal);
|
|
143
190
|
try {
|
|
144
191
|
const response = await fetch(url, {
|
|
145
192
|
...options,
|
|
146
193
|
headers,
|
|
147
|
-
signal
|
|
194
|
+
signal: combinedSignal.signal
|
|
148
195
|
});
|
|
149
196
|
return response;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`Resend API request timed out after ${this.config.timeout} ms.`);
|
|
199
|
+
throw error;
|
|
150
200
|
} finally {
|
|
201
|
+
combinedSignal.cleanup();
|
|
151
202
|
clearTimeout(timeoutId);
|
|
152
203
|
}
|
|
153
204
|
}
|
|
154
205
|
};
|
|
206
|
+
function isAbortError$1(error) {
|
|
207
|
+
return error instanceof Error && error.name === "AbortError";
|
|
208
|
+
}
|
|
209
|
+
function isCallerAbort$1(error, signal) {
|
|
210
|
+
return signal?.aborted === true && (isAbortError$1(error) || error === signal.reason);
|
|
211
|
+
}
|
|
212
|
+
function truncateErrorBody(text) {
|
|
213
|
+
return text.length > 500 ? `${text.slice(0, 500)}...` : text;
|
|
214
|
+
}
|
|
155
215
|
|
|
156
216
|
//#endregion
|
|
157
217
|
//#region src/message-converter.ts
|
|
@@ -339,6 +399,7 @@ function generateIdempotencyKey() {
|
|
|
339
399
|
* ```
|
|
340
400
|
*/
|
|
341
401
|
var ResendTransport = class {
|
|
402
|
+
id = "resend";
|
|
342
403
|
/**
|
|
343
404
|
* The resolved Resend configuration used by this transport.
|
|
344
405
|
*/
|
|
@@ -396,14 +457,13 @@ var ResendTransport = class {
|
|
|
396
457
|
const response = await this.httpClient.sendMessage(emailData, options?.signal, idempotencyKey);
|
|
397
458
|
return {
|
|
398
459
|
successful: true,
|
|
399
|
-
messageId: response.id
|
|
460
|
+
messageId: response.id,
|
|
461
|
+
provider: "resend"
|
|
400
462
|
};
|
|
401
463
|
} catch (error) {
|
|
464
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
402
465
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
403
|
-
return
|
|
404
|
-
successful: false,
|
|
405
|
-
errorMessages: [errorMessage]
|
|
406
|
-
};
|
|
466
|
+
return createResendFailure(errorMessage, error);
|
|
407
467
|
}
|
|
408
468
|
}
|
|
409
469
|
/**
|
|
@@ -512,14 +572,13 @@ var ResendTransport = class {
|
|
|
512
572
|
const response = await this.httpClient.sendBatch(batchData, options?.signal, idempotencyKey);
|
|
513
573
|
for (const result of response.data) yield {
|
|
514
574
|
successful: true,
|
|
515
|
-
messageId: result.id
|
|
575
|
+
messageId: result.id,
|
|
576
|
+
provider: "resend"
|
|
516
577
|
};
|
|
517
578
|
} catch (error) {
|
|
579
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
518
580
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
519
|
-
for (let i = 0; i < messages.length; i++) yield
|
|
520
|
-
successful: false,
|
|
521
|
-
errorMessages: [errorMessage]
|
|
522
|
-
};
|
|
581
|
+
for (let i = 0; i < messages.length; i++) yield createResendFailure(errorMessage, error);
|
|
523
582
|
}
|
|
524
583
|
}
|
|
525
584
|
/**
|
|
@@ -549,6 +608,21 @@ var ResendTransport = class {
|
|
|
549
608
|
return chunks;
|
|
550
609
|
}
|
|
551
610
|
};
|
|
611
|
+
function createResendFailure(message, error) {
|
|
612
|
+
if (error instanceof ResendApiError) return (0, __upyo_core.createFailedReceipt)(message, {
|
|
613
|
+
provider: "resend",
|
|
614
|
+
statusCode: error.statusCode,
|
|
615
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
616
|
+
attempts: error.attempts
|
|
617
|
+
});
|
|
618
|
+
return (0, __upyo_core.createFailedReceipt)(message, { provider: "resend" });
|
|
619
|
+
}
|
|
620
|
+
function isAbortError(error) {
|
|
621
|
+
return error instanceof Error && error.name === "AbortError";
|
|
622
|
+
}
|
|
623
|
+
function isCallerAbort(error, signal) {
|
|
624
|
+
return signal?.aborted === true && (isAbortError(error) || error === signal.reason);
|
|
625
|
+
}
|
|
552
626
|
|
|
553
627
|
//#endregion
|
|
554
628
|
exports.ResendTransport = ResendTransport;
|
package/dist/index.d.cts
CHANGED
|
@@ -99,7 +99,8 @@ type ResolvedResendConfig = Required<ResendConfig>;
|
|
|
99
99
|
* }
|
|
100
100
|
* ```
|
|
101
101
|
*/
|
|
102
|
-
declare class ResendTransport implements Transport {
|
|
102
|
+
declare class ResendTransport implements Transport<"resend"> {
|
|
103
|
+
readonly id = "resend";
|
|
103
104
|
/**
|
|
104
105
|
* The resolved Resend configuration used by this transport.
|
|
105
106
|
*/
|
|
@@ -145,7 +146,7 @@ declare class ResendTransport implements Transport {
|
|
|
145
146
|
* @returns A promise that resolves to a receipt indicating success or
|
|
146
147
|
* failure.
|
|
147
148
|
*/
|
|
148
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
149
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"resend">>;
|
|
149
150
|
/**
|
|
150
151
|
* Sends multiple email messages efficiently via Resend API.
|
|
151
152
|
*
|
|
@@ -200,7 +201,7 @@ declare class ResendTransport implements Transport {
|
|
|
200
201
|
* cancellation.
|
|
201
202
|
* @returns An async iterable of receipts, one for each message.
|
|
202
203
|
*/
|
|
203
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
204
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"resend">>;
|
|
204
205
|
/**
|
|
205
206
|
* Optimized batch sending that chooses the best strategy based on message features.
|
|
206
207
|
*
|
|
@@ -274,11 +275,32 @@ interface ResendError {
|
|
|
274
275
|
name?: string;
|
|
275
276
|
}
|
|
276
277
|
/**
|
|
277
|
-
*
|
|
278
|
+
* Error thrown when a Resend API request fails.
|
|
279
|
+
*
|
|
280
|
+
* @since 0.5.0
|
|
278
281
|
*/
|
|
279
282
|
declare class ResendApiError extends Error {
|
|
280
|
-
|
|
281
|
-
|
|
283
|
+
/**
|
|
284
|
+
* HTTP status code returned by Resend, if the request reached the API.
|
|
285
|
+
*/
|
|
286
|
+
readonly statusCode?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Retry delay from Resend's `Retry-After` response header.
|
|
289
|
+
*/
|
|
290
|
+
readonly retryAfterMilliseconds?: number;
|
|
291
|
+
/**
|
|
292
|
+
* Number of attempts made before this error was produced.
|
|
293
|
+
*/
|
|
294
|
+
readonly attempts?: number;
|
|
295
|
+
/**
|
|
296
|
+
* Creates a Resend API error.
|
|
297
|
+
*
|
|
298
|
+
* @param message Error message.
|
|
299
|
+
* @param statusCode HTTP status code returned by Resend.
|
|
300
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
301
|
+
* @param attempts Number of attempts made before this error.
|
|
302
|
+
*/
|
|
303
|
+
constructor(message: string, statusCode?: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
282
304
|
}
|
|
283
305
|
/**
|
|
284
306
|
* HTTP client wrapper for Resend API requests.
|
package/dist/index.d.ts
CHANGED
|
@@ -99,7 +99,8 @@ type ResolvedResendConfig = Required<ResendConfig>;
|
|
|
99
99
|
* }
|
|
100
100
|
* ```
|
|
101
101
|
*/
|
|
102
|
-
declare class ResendTransport implements Transport {
|
|
102
|
+
declare class ResendTransport implements Transport<"resend"> {
|
|
103
|
+
readonly id = "resend";
|
|
103
104
|
/**
|
|
104
105
|
* The resolved Resend configuration used by this transport.
|
|
105
106
|
*/
|
|
@@ -145,7 +146,7 @@ declare class ResendTransport implements Transport {
|
|
|
145
146
|
* @returns A promise that resolves to a receipt indicating success or
|
|
146
147
|
* failure.
|
|
147
148
|
*/
|
|
148
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
149
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"resend">>;
|
|
149
150
|
/**
|
|
150
151
|
* Sends multiple email messages efficiently via Resend API.
|
|
151
152
|
*
|
|
@@ -200,7 +201,7 @@ declare class ResendTransport implements Transport {
|
|
|
200
201
|
* cancellation.
|
|
201
202
|
* @returns An async iterable of receipts, one for each message.
|
|
202
203
|
*/
|
|
203
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
204
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"resend">>;
|
|
204
205
|
/**
|
|
205
206
|
* Optimized batch sending that chooses the best strategy based on message features.
|
|
206
207
|
*
|
|
@@ -274,11 +275,32 @@ interface ResendError {
|
|
|
274
275
|
name?: string;
|
|
275
276
|
}
|
|
276
277
|
/**
|
|
277
|
-
*
|
|
278
|
+
* Error thrown when a Resend API request fails.
|
|
279
|
+
*
|
|
280
|
+
* @since 0.5.0
|
|
278
281
|
*/
|
|
279
282
|
declare class ResendApiError extends Error {
|
|
280
|
-
|
|
281
|
-
|
|
283
|
+
/**
|
|
284
|
+
* HTTP status code returned by Resend, if the request reached the API.
|
|
285
|
+
*/
|
|
286
|
+
readonly statusCode?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Retry delay from Resend's `Retry-After` response header.
|
|
289
|
+
*/
|
|
290
|
+
readonly retryAfterMilliseconds?: number;
|
|
291
|
+
/**
|
|
292
|
+
* Number of attempts made before this error was produced.
|
|
293
|
+
*/
|
|
294
|
+
readonly attempts?: number;
|
|
295
|
+
/**
|
|
296
|
+
* Creates a Resend API error.
|
|
297
|
+
*
|
|
298
|
+
* @param message Error message.
|
|
299
|
+
* @param statusCode HTTP status code returned by Resend.
|
|
300
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
301
|
+
* @param attempts Number of attempts made before this error.
|
|
302
|
+
*/
|
|
303
|
+
constructor(message: string, statusCode?: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
282
304
|
}
|
|
283
305
|
/**
|
|
284
306
|
* HTTP client wrapper for Resend API requests.
|
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 Resend configuration by applying default values to optional fields.
|
|
@@ -24,14 +26,37 @@ function createResendConfig(config) {
|
|
|
24
26
|
//#endregion
|
|
25
27
|
//#region src/http-client.ts
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
29
|
+
* Error thrown when a Resend API request fails.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.5.0
|
|
28
32
|
*/
|
|
29
33
|
var ResendApiError = class extends Error {
|
|
34
|
+
/**
|
|
35
|
+
* HTTP status code returned by Resend, if the request reached the API.
|
|
36
|
+
*/
|
|
30
37
|
statusCode;
|
|
31
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Retry delay from Resend's `Retry-After` response header.
|
|
40
|
+
*/
|
|
41
|
+
retryAfterMilliseconds;
|
|
42
|
+
/**
|
|
43
|
+
* Number of attempts made before this error was produced.
|
|
44
|
+
*/
|
|
45
|
+
attempts;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a Resend API error.
|
|
48
|
+
*
|
|
49
|
+
* @param message Error message.
|
|
50
|
+
* @param statusCode HTTP status code returned by Resend.
|
|
51
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
52
|
+
* @param attempts Number of attempts made before this error.
|
|
53
|
+
*/
|
|
54
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
32
55
|
super(message);
|
|
33
56
|
this.name = "ResendApiError";
|
|
34
57
|
this.statusCode = statusCode;
|
|
58
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
59
|
+
this.attempts = attempts;
|
|
35
60
|
}
|
|
36
61
|
};
|
|
37
62
|
/**
|
|
@@ -101,7 +126,10 @@ var ResendHttpClient = class {
|
|
|
101
126
|
const errorBody = JSON.parse(text);
|
|
102
127
|
errorMessage = errorBody.message;
|
|
103
128
|
} catch {}
|
|
104
|
-
|
|
129
|
+
const parsedErrorMessage = errorMessage === "" ? void 0 : errorMessage;
|
|
130
|
+
const responseMessage = truncateErrorBody(text);
|
|
131
|
+
const fallbackMessage = responseMessage === "" ? void 0 : responseMessage;
|
|
132
|
+
throw new ResendApiError(parsedErrorMessage ?? fallbackMessage ?? `HTTP ${response.status}`, response.status, parseRetryAfter(response.headers.get("Retry-After")), attempt + 1);
|
|
105
133
|
}
|
|
106
134
|
try {
|
|
107
135
|
return JSON.parse(text);
|
|
@@ -109,10 +137,14 @@ var ResendHttpClient = class {
|
|
|
109
137
|
throw new Error(`Invalid JSON response from Resend API: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
110
138
|
}
|
|
111
139
|
} catch (error) {
|
|
140
|
+
if (isCallerAbort$1(error, options.signal)) throw error;
|
|
112
141
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
113
|
-
if (error instanceof ResendApiError && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
142
|
+
if (error instanceof ResendApiError && error.statusCode !== void 0 && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
114
143
|
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
115
|
-
if (attempt === this.config.retries)
|
|
144
|
+
if (attempt === this.config.retries) {
|
|
145
|
+
if (lastError instanceof ResendApiError) throw lastError;
|
|
146
|
+
throw new ResendApiError(lastError.message, void 0, void 0, attempt + 1);
|
|
147
|
+
}
|
|
116
148
|
const backoffMs = Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
117
149
|
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
118
150
|
}
|
|
@@ -131,26 +163,32 @@ var ResendHttpClient = class {
|
|
|
131
163
|
for (const [key, value] of Object.entries(this.config.headers)) headers.set(key, value);
|
|
132
164
|
const controller = new AbortController();
|
|
133
165
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
134
|
-
|
|
135
|
-
if (options.signal) {
|
|
136
|
-
const combinedController = new AbortController();
|
|
137
|
-
const onAbort = () => combinedController.abort();
|
|
138
|
-
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
139
|
-
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
140
|
-
signal = combinedController.signal;
|
|
141
|
-
} else signal = controller.signal;
|
|
166
|
+
const combinedSignal = combineSignals(controller.signal, options.signal);
|
|
142
167
|
try {
|
|
143
168
|
const response = await fetch(url, {
|
|
144
169
|
...options,
|
|
145
170
|
headers,
|
|
146
|
-
signal
|
|
171
|
+
signal: combinedSignal.signal
|
|
147
172
|
});
|
|
148
173
|
return response;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`Resend API request timed out after ${this.config.timeout} ms.`);
|
|
176
|
+
throw error;
|
|
149
177
|
} finally {
|
|
178
|
+
combinedSignal.cleanup();
|
|
150
179
|
clearTimeout(timeoutId);
|
|
151
180
|
}
|
|
152
181
|
}
|
|
153
182
|
};
|
|
183
|
+
function isAbortError$1(error) {
|
|
184
|
+
return error instanceof Error && error.name === "AbortError";
|
|
185
|
+
}
|
|
186
|
+
function isCallerAbort$1(error, signal) {
|
|
187
|
+
return signal?.aborted === true && (isAbortError$1(error) || error === signal.reason);
|
|
188
|
+
}
|
|
189
|
+
function truncateErrorBody(text) {
|
|
190
|
+
return text.length > 500 ? `${text.slice(0, 500)}...` : text;
|
|
191
|
+
}
|
|
154
192
|
|
|
155
193
|
//#endregion
|
|
156
194
|
//#region src/message-converter.ts
|
|
@@ -338,6 +376,7 @@ function generateIdempotencyKey() {
|
|
|
338
376
|
* ```
|
|
339
377
|
*/
|
|
340
378
|
var ResendTransport = class {
|
|
379
|
+
id = "resend";
|
|
341
380
|
/**
|
|
342
381
|
* The resolved Resend configuration used by this transport.
|
|
343
382
|
*/
|
|
@@ -395,14 +434,13 @@ var ResendTransport = class {
|
|
|
395
434
|
const response = await this.httpClient.sendMessage(emailData, options?.signal, idempotencyKey);
|
|
396
435
|
return {
|
|
397
436
|
successful: true,
|
|
398
|
-
messageId: response.id
|
|
437
|
+
messageId: response.id,
|
|
438
|
+
provider: "resend"
|
|
399
439
|
};
|
|
400
440
|
} catch (error) {
|
|
441
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
401
442
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
402
|
-
return
|
|
403
|
-
successful: false,
|
|
404
|
-
errorMessages: [errorMessage]
|
|
405
|
-
};
|
|
443
|
+
return createResendFailure(errorMessage, error);
|
|
406
444
|
}
|
|
407
445
|
}
|
|
408
446
|
/**
|
|
@@ -511,14 +549,13 @@ var ResendTransport = class {
|
|
|
511
549
|
const response = await this.httpClient.sendBatch(batchData, options?.signal, idempotencyKey);
|
|
512
550
|
for (const result of response.data) yield {
|
|
513
551
|
successful: true,
|
|
514
|
-
messageId: result.id
|
|
552
|
+
messageId: result.id,
|
|
553
|
+
provider: "resend"
|
|
515
554
|
};
|
|
516
555
|
} catch (error) {
|
|
556
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
517
557
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
518
|
-
for (let i = 0; i < messages.length; i++) yield
|
|
519
|
-
successful: false,
|
|
520
|
-
errorMessages: [errorMessage]
|
|
521
|
-
};
|
|
558
|
+
for (let i = 0; i < messages.length; i++) yield createResendFailure(errorMessage, error);
|
|
522
559
|
}
|
|
523
560
|
}
|
|
524
561
|
/**
|
|
@@ -548,6 +585,21 @@ var ResendTransport = class {
|
|
|
548
585
|
return chunks;
|
|
549
586
|
}
|
|
550
587
|
};
|
|
588
|
+
function createResendFailure(message, error) {
|
|
589
|
+
if (error instanceof ResendApiError) return createFailedReceipt(message, {
|
|
590
|
+
provider: "resend",
|
|
591
|
+
statusCode: error.statusCode,
|
|
592
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
593
|
+
attempts: error.attempts
|
|
594
|
+
});
|
|
595
|
+
return createFailedReceipt(message, { provider: "resend" });
|
|
596
|
+
}
|
|
597
|
+
function isAbortError(error) {
|
|
598
|
+
return error instanceof Error && error.name === "AbortError";
|
|
599
|
+
}
|
|
600
|
+
function isCallerAbort(error, signal) {
|
|
601
|
+
return signal?.aborted === true && (isAbortError(error) || error === signal.reason);
|
|
602
|
+
}
|
|
551
603
|
|
|
552
604
|
//#endregion
|
|
553
605
|
export { ResendTransport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/resend",
|
|
3
|
-
"version": "0.5.0
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Resend 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
|
|
56
|
+
"@upyo/core": "0.5.0"
|
|
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
|
}
|