@upyo/mailgun 0.5.0-dev.87 → 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 +111 -13
- package/dist/index.d.cts +27 -5
- package/dist/index.d.ts +27 -5
- package/dist/index.js +89 -13
- 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
|
/**
|
|
@@ -76,6 +100,8 @@ var MailgunHttpClient = class {
|
|
|
76
100
|
* @param url The URL to make the request to.
|
|
77
101
|
* @param options Fetch options.
|
|
78
102
|
* @returns Promise that resolves to the parsed response.
|
|
103
|
+
* @throws {MailgunApiError} If Mailgun returns an error response or all
|
|
104
|
+
* retry attempts are exhausted.
|
|
79
105
|
*/
|
|
80
106
|
async makeRequest(url, options) {
|
|
81
107
|
let lastError = null;
|
|
@@ -87,7 +113,7 @@ var MailgunHttpClient = class {
|
|
|
87
113
|
try {
|
|
88
114
|
errorMessage = JSON.parse(text)?.message;
|
|
89
115
|
} catch {}
|
|
90
|
-
throw new MailgunApiError(errorMessage || text || `HTTP ${response.status}`, response.status);
|
|
116
|
+
throw new MailgunApiError(errorMessage || truncateErrorBody(text) || `HTTP ${response.status}`, response.status, (0, __upyo_core.parseRetryAfter)(response.headers.get("Retry-After")), attempt + 1);
|
|
91
117
|
}
|
|
92
118
|
try {
|
|
93
119
|
return JSON.parse(text);
|
|
@@ -96,10 +122,15 @@ var MailgunHttpClient = class {
|
|
|
96
122
|
}
|
|
97
123
|
} catch (error) {
|
|
98
124
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
125
|
+
if (options.signal?.aborted) throw createAbortError(options.signal);
|
|
126
|
+
if (isAbortError$1(error)) throw error;
|
|
99
127
|
if (error instanceof MailgunApiError && error.statusCode && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
100
|
-
if (attempt === this.config.retries)
|
|
128
|
+
if (attempt === this.config.retries) {
|
|
129
|
+
if (lastError instanceof MailgunApiError) throw lastError;
|
|
130
|
+
throw new MailgunApiError(lastError.message, void 0, void 0, attempt + 1);
|
|
131
|
+
}
|
|
101
132
|
const delay = Math.pow(2, attempt) * 1e3;
|
|
102
|
-
await
|
|
133
|
+
await sleep(delay, options.signal);
|
|
103
134
|
}
|
|
104
135
|
throw lastError || /* @__PURE__ */ new Error("Request failed after all retries");
|
|
105
136
|
}
|
|
@@ -109,6 +140,8 @@ var MailgunHttpClient = class {
|
|
|
109
140
|
* @param url The URL to make the request to.
|
|
110
141
|
* @param options Fetch options.
|
|
111
142
|
* @returns Promise that resolves to the fetch response.
|
|
143
|
+
* @throws {Error} If the configured request timeout is reached.
|
|
144
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
112
145
|
*/
|
|
113
146
|
async fetchWithAuth(url, options) {
|
|
114
147
|
const headers = new Headers(options.headers);
|
|
@@ -117,30 +150,80 @@ var MailgunHttpClient = class {
|
|
|
117
150
|
for (const [key, value] of Object.entries(this.config.headers)) headers.set(key, value);
|
|
118
151
|
const controller = new AbortController();
|
|
119
152
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
120
|
-
|
|
121
|
-
if (options.signal) signal = AbortSignal.any([controller.signal, options.signal]);
|
|
153
|
+
const combinedSignal = (0, __upyo_core.combineSignals)(controller.signal, options.signal);
|
|
122
154
|
try {
|
|
123
155
|
return await globalThis.fetch(url, {
|
|
124
156
|
...options,
|
|
125
157
|
headers,
|
|
126
|
-
signal
|
|
158
|
+
signal: combinedSignal.signal
|
|
127
159
|
});
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`Mailgun API request timed out after ${this.config.timeout} ms.`);
|
|
162
|
+
throw error;
|
|
128
163
|
} finally {
|
|
164
|
+
combinedSignal.cleanup();
|
|
129
165
|
clearTimeout(timeoutId);
|
|
130
166
|
}
|
|
131
167
|
}
|
|
132
168
|
};
|
|
133
169
|
/**
|
|
134
|
-
*
|
|
170
|
+
* Error thrown when a Mailgun API request fails.
|
|
171
|
+
*
|
|
172
|
+
* @since 0.5.0
|
|
135
173
|
*/
|
|
136
174
|
var MailgunApiError = class extends Error {
|
|
175
|
+
/**
|
|
176
|
+
* HTTP status code returned by Mailgun, if the request reached the API.
|
|
177
|
+
*/
|
|
137
178
|
statusCode;
|
|
138
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Retry delay from Mailgun's `Retry-After` response header.
|
|
181
|
+
*/
|
|
182
|
+
retryAfterMilliseconds;
|
|
183
|
+
/**
|
|
184
|
+
* Number of attempts made before this error was produced.
|
|
185
|
+
*/
|
|
186
|
+
attempts;
|
|
187
|
+
/**
|
|
188
|
+
* Creates a Mailgun API error.
|
|
189
|
+
*
|
|
190
|
+
* @param message Error message.
|
|
191
|
+
* @param statusCode HTTP status code returned by Mailgun.
|
|
192
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
193
|
+
* @param attempts Number of attempts made before this error.
|
|
194
|
+
*/
|
|
195
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
139
196
|
super(message);
|
|
140
197
|
this.name = "MailgunApiError";
|
|
141
198
|
this.statusCode = statusCode;
|
|
199
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
200
|
+
this.attempts = attempts;
|
|
142
201
|
}
|
|
143
202
|
};
|
|
203
|
+
function isAbortError$1(error) {
|
|
204
|
+
return error instanceof Error && error.name === "AbortError";
|
|
205
|
+
}
|
|
206
|
+
function sleep(milliseconds, signal) {
|
|
207
|
+
if (signal?.aborted) return Promise.reject(createAbortError(signal));
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
function abort() {
|
|
210
|
+
clearTimeout(timeoutId);
|
|
211
|
+
signal?.removeEventListener("abort", abort);
|
|
212
|
+
reject(createAbortError(signal));
|
|
213
|
+
}
|
|
214
|
+
const timeoutId = setTimeout(() => {
|
|
215
|
+
signal?.removeEventListener("abort", abort);
|
|
216
|
+
resolve();
|
|
217
|
+
}, milliseconds);
|
|
218
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function createAbortError(signal) {
|
|
222
|
+
return signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
223
|
+
}
|
|
224
|
+
function truncateErrorBody(text) {
|
|
225
|
+
return text.length > 500 ? `${text.slice(0, 500)}...` : text;
|
|
226
|
+
}
|
|
144
227
|
|
|
145
228
|
//#endregion
|
|
146
229
|
//#region src/message-converter.ts
|
|
@@ -267,6 +350,7 @@ function isStandardHeader(headerName) {
|
|
|
267
350
|
* ```
|
|
268
351
|
*/
|
|
269
352
|
var MailgunTransport = class {
|
|
353
|
+
id = "mailgun";
|
|
270
354
|
/**
|
|
271
355
|
* The resolved Mailgun configuration used by this transport.
|
|
272
356
|
*/
|
|
@@ -322,14 +406,13 @@ var MailgunTransport = class {
|
|
|
322
406
|
const response = await this.httpClient.sendMessage(formData, options?.signal);
|
|
323
407
|
return {
|
|
324
408
|
successful: true,
|
|
325
|
-
messageId: response.id
|
|
409
|
+
messageId: response.id,
|
|
410
|
+
provider: "mailgun"
|
|
326
411
|
};
|
|
327
412
|
} catch (error) {
|
|
413
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
328
414
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
329
|
-
return
|
|
330
|
-
successful: false,
|
|
331
|
-
errorMessages: [errorMessage]
|
|
332
|
-
};
|
|
415
|
+
return createMailgunFailure(errorMessage, error);
|
|
333
416
|
}
|
|
334
417
|
}
|
|
335
418
|
/**
|
|
@@ -397,6 +480,21 @@ var MailgunTransport = class {
|
|
|
397
480
|
}
|
|
398
481
|
}
|
|
399
482
|
};
|
|
483
|
+
function createMailgunFailure(message, error) {
|
|
484
|
+
if (error instanceof MailgunApiError) return (0, __upyo_core.createFailedReceipt)(message, {
|
|
485
|
+
provider: "mailgun",
|
|
486
|
+
statusCode: error.statusCode,
|
|
487
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
488
|
+
attempts: error.attempts
|
|
489
|
+
});
|
|
490
|
+
return (0, __upyo_core.createFailedReceipt)(message, { provider: "mailgun" });
|
|
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
|
+
}
|
|
400
498
|
|
|
401
499
|
//#endregion
|
|
402
500
|
exports.MailgunApiError = MailgunApiError;
|
package/dist/index.d.cts
CHANGED
|
@@ -132,7 +132,8 @@ type ResolvedMailgunConfig = Required<MailgunConfig>;
|
|
|
132
132
|
* }
|
|
133
133
|
* ```
|
|
134
134
|
*/
|
|
135
|
-
declare class MailgunTransport implements Transport {
|
|
135
|
+
declare class MailgunTransport implements Transport<"mailgun"> {
|
|
136
|
+
readonly id = "mailgun";
|
|
136
137
|
/**
|
|
137
138
|
* The resolved Mailgun configuration used by this transport.
|
|
138
139
|
*/
|
|
@@ -177,7 +178,7 @@ declare class MailgunTransport implements Transport {
|
|
|
177
178
|
* @returns A promise that resolves to a receipt indicating success or
|
|
178
179
|
* failure.
|
|
179
180
|
*/
|
|
180
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
181
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"mailgun">>;
|
|
181
182
|
/**
|
|
182
183
|
* Sends multiple email messages efficiently via Mailgun API.
|
|
183
184
|
*
|
|
@@ -230,17 +231,38 @@ declare class MailgunTransport implements Transport {
|
|
|
230
231
|
* cancellation.
|
|
231
232
|
* @returns An async iterable of receipts, one for each message.
|
|
232
233
|
*/
|
|
233
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
234
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"mailgun">>;
|
|
234
235
|
}
|
|
235
236
|
//#endregion
|
|
236
237
|
//#region src/http-client.d.ts
|
|
237
238
|
|
|
238
239
|
/**
|
|
239
|
-
*
|
|
240
|
+
* Error thrown when a Mailgun API request fails.
|
|
241
|
+
*
|
|
242
|
+
* @since 0.5.0
|
|
240
243
|
*/
|
|
241
244
|
declare class MailgunApiError extends Error {
|
|
245
|
+
/**
|
|
246
|
+
* HTTP status code returned by Mailgun, if the request reached the API.
|
|
247
|
+
*/
|
|
242
248
|
statusCode?: number;
|
|
243
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Retry delay from Mailgun's `Retry-After` response header.
|
|
251
|
+
*/
|
|
252
|
+
retryAfterMilliseconds?: number;
|
|
253
|
+
/**
|
|
254
|
+
* Number of attempts made before this error was produced.
|
|
255
|
+
*/
|
|
256
|
+
attempts?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Creates a Mailgun API error.
|
|
259
|
+
*
|
|
260
|
+
* @param message Error message.
|
|
261
|
+
* @param statusCode HTTP status code returned by Mailgun.
|
|
262
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
263
|
+
* @param attempts Number of attempts made before this error.
|
|
264
|
+
*/
|
|
265
|
+
constructor(message: string, statusCode?: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
244
266
|
}
|
|
245
267
|
//#endregion
|
|
246
268
|
export { MailgunApiError, MailgunConfig, MailgunTransport };
|
package/dist/index.d.ts
CHANGED
|
@@ -132,7 +132,8 @@ type ResolvedMailgunConfig = Required<MailgunConfig>;
|
|
|
132
132
|
* }
|
|
133
133
|
* ```
|
|
134
134
|
*/
|
|
135
|
-
declare class MailgunTransport implements Transport {
|
|
135
|
+
declare class MailgunTransport implements Transport<"mailgun"> {
|
|
136
|
+
readonly id = "mailgun";
|
|
136
137
|
/**
|
|
137
138
|
* The resolved Mailgun configuration used by this transport.
|
|
138
139
|
*/
|
|
@@ -177,7 +178,7 @@ declare class MailgunTransport implements Transport {
|
|
|
177
178
|
* @returns A promise that resolves to a receipt indicating success or
|
|
178
179
|
* failure.
|
|
179
180
|
*/
|
|
180
|
-
send(message: Message, options?: TransportOptions): Promise<Receipt
|
|
181
|
+
send(message: Message, options?: TransportOptions): Promise<Receipt<"mailgun">>;
|
|
181
182
|
/**
|
|
182
183
|
* Sends multiple email messages efficiently via Mailgun API.
|
|
183
184
|
*
|
|
@@ -230,17 +231,38 @@ declare class MailgunTransport implements Transport {
|
|
|
230
231
|
* cancellation.
|
|
231
232
|
* @returns An async iterable of receipts, one for each message.
|
|
232
233
|
*/
|
|
233
|
-
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt
|
|
234
|
+
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<"mailgun">>;
|
|
234
235
|
}
|
|
235
236
|
//#endregion
|
|
236
237
|
//#region src/http-client.d.ts
|
|
237
238
|
|
|
238
239
|
/**
|
|
239
|
-
*
|
|
240
|
+
* Error thrown when a Mailgun API request fails.
|
|
241
|
+
*
|
|
242
|
+
* @since 0.5.0
|
|
240
243
|
*/
|
|
241
244
|
declare class MailgunApiError extends Error {
|
|
245
|
+
/**
|
|
246
|
+
* HTTP status code returned by Mailgun, if the request reached the API.
|
|
247
|
+
*/
|
|
242
248
|
statusCode?: number;
|
|
243
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Retry delay from Mailgun's `Retry-After` response header.
|
|
251
|
+
*/
|
|
252
|
+
retryAfterMilliseconds?: number;
|
|
253
|
+
/**
|
|
254
|
+
* Number of attempts made before this error was produced.
|
|
255
|
+
*/
|
|
256
|
+
attempts?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Creates a Mailgun API error.
|
|
259
|
+
*
|
|
260
|
+
* @param message Error message.
|
|
261
|
+
* @param statusCode HTTP status code returned by Mailgun.
|
|
262
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
263
|
+
* @param attempts Number of attempts made before this error.
|
|
264
|
+
*/
|
|
265
|
+
constructor(message: string, statusCode?: number, retryAfterMilliseconds?: number, attempts?: number);
|
|
244
266
|
}
|
|
245
267
|
//#endregion
|
|
246
268
|
export { MailgunApiError, MailgunConfig, MailgunTransport };
|
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 Mailgun configuration by applying default values to optional fields.
|
|
@@ -75,6 +77,8 @@ var MailgunHttpClient = class {
|
|
|
75
77
|
* @param url The URL to make the request to.
|
|
76
78
|
* @param options Fetch options.
|
|
77
79
|
* @returns Promise that resolves to the parsed response.
|
|
80
|
+
* @throws {MailgunApiError} If Mailgun returns an error response or all
|
|
81
|
+
* retry attempts are exhausted.
|
|
78
82
|
*/
|
|
79
83
|
async makeRequest(url, options) {
|
|
80
84
|
let lastError = null;
|
|
@@ -86,7 +90,7 @@ var MailgunHttpClient = class {
|
|
|
86
90
|
try {
|
|
87
91
|
errorMessage = JSON.parse(text)?.message;
|
|
88
92
|
} catch {}
|
|
89
|
-
throw new MailgunApiError(errorMessage || text || `HTTP ${response.status}`, response.status);
|
|
93
|
+
throw new MailgunApiError(errorMessage || truncateErrorBody(text) || `HTTP ${response.status}`, response.status, parseRetryAfter(response.headers.get("Retry-After")), attempt + 1);
|
|
90
94
|
}
|
|
91
95
|
try {
|
|
92
96
|
return JSON.parse(text);
|
|
@@ -95,10 +99,15 @@ var MailgunHttpClient = class {
|
|
|
95
99
|
}
|
|
96
100
|
} catch (error) {
|
|
97
101
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
102
|
+
if (options.signal?.aborted) throw createAbortError(options.signal);
|
|
103
|
+
if (isAbortError$1(error)) throw error;
|
|
98
104
|
if (error instanceof MailgunApiError && error.statusCode && error.statusCode >= 400 && error.statusCode < 500) throw error;
|
|
99
|
-
if (attempt === this.config.retries)
|
|
105
|
+
if (attempt === this.config.retries) {
|
|
106
|
+
if (lastError instanceof MailgunApiError) throw lastError;
|
|
107
|
+
throw new MailgunApiError(lastError.message, void 0, void 0, attempt + 1);
|
|
108
|
+
}
|
|
100
109
|
const delay = Math.pow(2, attempt) * 1e3;
|
|
101
|
-
await
|
|
110
|
+
await sleep(delay, options.signal);
|
|
102
111
|
}
|
|
103
112
|
throw lastError || /* @__PURE__ */ new Error("Request failed after all retries");
|
|
104
113
|
}
|
|
@@ -108,6 +117,8 @@ var MailgunHttpClient = class {
|
|
|
108
117
|
* @param url The URL to make the request to.
|
|
109
118
|
* @param options Fetch options.
|
|
110
119
|
* @returns Promise that resolves to the fetch response.
|
|
120
|
+
* @throws {Error} If the configured request timeout is reached.
|
|
121
|
+
* @throws {DOMException} If the caller aborts the request.
|
|
111
122
|
*/
|
|
112
123
|
async fetchWithAuth(url, options) {
|
|
113
124
|
const headers = new Headers(options.headers);
|
|
@@ -116,30 +127,80 @@ var MailgunHttpClient = class {
|
|
|
116
127
|
for (const [key, value] of Object.entries(this.config.headers)) headers.set(key, value);
|
|
117
128
|
const controller = new AbortController();
|
|
118
129
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
119
|
-
|
|
120
|
-
if (options.signal) signal = AbortSignal.any([controller.signal, options.signal]);
|
|
130
|
+
const combinedSignal = combineSignals(controller.signal, options.signal);
|
|
121
131
|
try {
|
|
122
132
|
return await globalThis.fetch(url, {
|
|
123
133
|
...options,
|
|
124
134
|
headers,
|
|
125
|
-
signal
|
|
135
|
+
signal: combinedSignal.signal
|
|
126
136
|
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (isAbortError$1(error) && controller.signal.aborted && !options.signal?.aborted) throw new Error(`Mailgun API request timed out after ${this.config.timeout} ms.`);
|
|
139
|
+
throw error;
|
|
127
140
|
} finally {
|
|
141
|
+
combinedSignal.cleanup();
|
|
128
142
|
clearTimeout(timeoutId);
|
|
129
143
|
}
|
|
130
144
|
}
|
|
131
145
|
};
|
|
132
146
|
/**
|
|
133
|
-
*
|
|
147
|
+
* Error thrown when a Mailgun API request fails.
|
|
148
|
+
*
|
|
149
|
+
* @since 0.5.0
|
|
134
150
|
*/
|
|
135
151
|
var MailgunApiError = class extends Error {
|
|
152
|
+
/**
|
|
153
|
+
* HTTP status code returned by Mailgun, if the request reached the API.
|
|
154
|
+
*/
|
|
136
155
|
statusCode;
|
|
137
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Retry delay from Mailgun's `Retry-After` response header.
|
|
158
|
+
*/
|
|
159
|
+
retryAfterMilliseconds;
|
|
160
|
+
/**
|
|
161
|
+
* Number of attempts made before this error was produced.
|
|
162
|
+
*/
|
|
163
|
+
attempts;
|
|
164
|
+
/**
|
|
165
|
+
* Creates a Mailgun API error.
|
|
166
|
+
*
|
|
167
|
+
* @param message Error message.
|
|
168
|
+
* @param statusCode HTTP status code returned by Mailgun.
|
|
169
|
+
* @param retryAfterMilliseconds Retry delay from the response.
|
|
170
|
+
* @param attempts Number of attempts made before this error.
|
|
171
|
+
*/
|
|
172
|
+
constructor(message, statusCode, retryAfterMilliseconds, attempts) {
|
|
138
173
|
super(message);
|
|
139
174
|
this.name = "MailgunApiError";
|
|
140
175
|
this.statusCode = statusCode;
|
|
176
|
+
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
|
177
|
+
this.attempts = attempts;
|
|
141
178
|
}
|
|
142
179
|
};
|
|
180
|
+
function isAbortError$1(error) {
|
|
181
|
+
return error instanceof Error && error.name === "AbortError";
|
|
182
|
+
}
|
|
183
|
+
function sleep(milliseconds, signal) {
|
|
184
|
+
if (signal?.aborted) return Promise.reject(createAbortError(signal));
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
function abort() {
|
|
187
|
+
clearTimeout(timeoutId);
|
|
188
|
+
signal?.removeEventListener("abort", abort);
|
|
189
|
+
reject(createAbortError(signal));
|
|
190
|
+
}
|
|
191
|
+
const timeoutId = setTimeout(() => {
|
|
192
|
+
signal?.removeEventListener("abort", abort);
|
|
193
|
+
resolve();
|
|
194
|
+
}, milliseconds);
|
|
195
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function createAbortError(signal) {
|
|
199
|
+
return signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
200
|
+
}
|
|
201
|
+
function truncateErrorBody(text) {
|
|
202
|
+
return text.length > 500 ? `${text.slice(0, 500)}...` : text;
|
|
203
|
+
}
|
|
143
204
|
|
|
144
205
|
//#endregion
|
|
145
206
|
//#region src/message-converter.ts
|
|
@@ -266,6 +327,7 @@ function isStandardHeader(headerName) {
|
|
|
266
327
|
* ```
|
|
267
328
|
*/
|
|
268
329
|
var MailgunTransport = class {
|
|
330
|
+
id = "mailgun";
|
|
269
331
|
/**
|
|
270
332
|
* The resolved Mailgun configuration used by this transport.
|
|
271
333
|
*/
|
|
@@ -321,14 +383,13 @@ var MailgunTransport = class {
|
|
|
321
383
|
const response = await this.httpClient.sendMessage(formData, options?.signal);
|
|
322
384
|
return {
|
|
323
385
|
successful: true,
|
|
324
|
-
messageId: response.id
|
|
386
|
+
messageId: response.id,
|
|
387
|
+
provider: "mailgun"
|
|
325
388
|
};
|
|
326
389
|
} catch (error) {
|
|
390
|
+
if (isCallerAbort(error, options?.signal)) throw error;
|
|
327
391
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
328
|
-
return
|
|
329
|
-
successful: false,
|
|
330
|
-
errorMessages: [errorMessage]
|
|
331
|
-
};
|
|
392
|
+
return createMailgunFailure(errorMessage, error);
|
|
332
393
|
}
|
|
333
394
|
}
|
|
334
395
|
/**
|
|
@@ -396,6 +457,21 @@ var MailgunTransport = class {
|
|
|
396
457
|
}
|
|
397
458
|
}
|
|
398
459
|
};
|
|
460
|
+
function createMailgunFailure(message, error) {
|
|
461
|
+
if (error instanceof MailgunApiError) return createFailedReceipt(message, {
|
|
462
|
+
provider: "mailgun",
|
|
463
|
+
statusCode: error.statusCode,
|
|
464
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
465
|
+
attempts: error.attempts
|
|
466
|
+
});
|
|
467
|
+
return createFailedReceipt(message, { provider: "mailgun" });
|
|
468
|
+
}
|
|
469
|
+
function isCallerAbort(error, signal) {
|
|
470
|
+
return signal?.aborted === true && (isAbortError(error) || error === signal.reason);
|
|
471
|
+
}
|
|
472
|
+
function isAbortError(error) {
|
|
473
|
+
return error instanceof Error && error.name === "AbortError";
|
|
474
|
+
}
|
|
399
475
|
|
|
400
476
|
//#endregion
|
|
401
477
|
export { MailgunApiError, MailgunTransport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/mailgun",
|
|
3
|
-
"version": "0.5.0
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Mailgun 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
|
}
|