@upyo/pool 0.5.0-dev.168 → 0.5.0-dev.172
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 +24 -38
- package/dist/index.js +24 -38
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -328,6 +328,7 @@ var PoolTransport = class {
|
|
|
328
328
|
const attemptedIndices = /* @__PURE__ */ new Set();
|
|
329
329
|
const errorMessages = [];
|
|
330
330
|
const errors = [];
|
|
331
|
+
let checkCallerAbortBeforeFailure = false;
|
|
331
332
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
332
333
|
if (options?.signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
|
|
333
334
|
const selection = this.strategy.select(message, this.config.transports, attemptedIndices);
|
|
@@ -351,24 +352,29 @@ var PoolTransport = class {
|
|
|
351
352
|
if (receipt.successful) return receipt;
|
|
352
353
|
errorMessages.push(...receipt.errorMessages);
|
|
353
354
|
errors.push(...getReceiptErrors(receipt, selection.entry.transport.id));
|
|
355
|
+
checkCallerAbortBeforeFailure = true;
|
|
354
356
|
} catch (error) {
|
|
355
357
|
if (abortedByCaller && isCallerAbort(error, options?.signal)) throw error;
|
|
356
358
|
const thrownErrors = getThrownReceiptErrors(error, selection.entry.transport.id);
|
|
357
359
|
if (thrownErrors.length > 0) {
|
|
358
360
|
errorMessages.push(...thrownErrors.map((item) => item.message));
|
|
359
361
|
errors.push(...thrownErrors);
|
|
362
|
+
checkCallerAbortBeforeFailure = true;
|
|
360
363
|
continue;
|
|
361
364
|
}
|
|
362
365
|
const timeoutMessage = "Transport send timed out.";
|
|
363
|
-
const
|
|
366
|
+
const abortError = isAbortError(error);
|
|
367
|
+
const errorMessage = abortError ? timeoutMessage : error instanceof Error ? error.message : String(error);
|
|
364
368
|
errorMessages.push(errorMessage);
|
|
365
369
|
errors.push((0, __upyo_core.createReceiptError)(errorMessage, {
|
|
366
370
|
provider: selection.entry.transport.id,
|
|
367
|
-
category:
|
|
368
|
-
retryable:
|
|
371
|
+
category: abortError ? "timeout" : void 0,
|
|
372
|
+
retryable: abortError ? true : void 0
|
|
369
373
|
}));
|
|
374
|
+
checkCallerAbortBeforeFailure ||= !abortError;
|
|
370
375
|
}
|
|
371
376
|
}
|
|
377
|
+
if (checkCallerAbortBeforeFailure) options?.signal?.throwIfAborted();
|
|
372
378
|
return (0, __upyo_core.createFailedReceipt)(errorMessages.length > 0 ? errorMessages : ["All transports failed to send the message."], {
|
|
373
379
|
provider: "pool",
|
|
374
380
|
errors: errors.length > 0 ? errors : void 0,
|
|
@@ -450,7 +456,7 @@ var PoolTransport = class {
|
|
|
450
456
|
if (options.signal.aborted) markCallerAbort();
|
|
451
457
|
else options.signal.addEventListener("abort", markCallerAbort, { once: true });
|
|
452
458
|
cleanupAbortSource = () => options.signal?.removeEventListener("abort", markCallerAbort);
|
|
453
|
-
const combinedSignal = combineSignals(timeoutController.signal, options.signal);
|
|
459
|
+
const combinedSignal = (0, __upyo_core.combineSignals)(timeoutController.signal, options.signal);
|
|
454
460
|
signal = combinedSignal.signal;
|
|
455
461
|
cleanupCombinedSignal = combinedSignal.cleanup;
|
|
456
462
|
}
|
|
@@ -471,32 +477,6 @@ var PoolTransport = class {
|
|
|
471
477
|
};
|
|
472
478
|
}
|
|
473
479
|
};
|
|
474
|
-
function combineSignals(timeoutSignal, externalSignal) {
|
|
475
|
-
if (typeof AbortSignal.any === "function") return {
|
|
476
|
-
signal: AbortSignal.any([timeoutSignal, externalSignal]),
|
|
477
|
-
cleanup: () => {}
|
|
478
|
-
};
|
|
479
|
-
const controller = new AbortController();
|
|
480
|
-
const abort = (signal) => {
|
|
481
|
-
controller.abort(getAbortReason(signal));
|
|
482
|
-
};
|
|
483
|
-
const abortTimeout = () => abort(timeoutSignal);
|
|
484
|
-
const abortExternal = () => abort(externalSignal);
|
|
485
|
-
timeoutSignal.addEventListener("abort", abortTimeout, { once: true });
|
|
486
|
-
externalSignal.addEventListener("abort", abortExternal, { once: true });
|
|
487
|
-
if (timeoutSignal.aborted) abortTimeout();
|
|
488
|
-
else if (externalSignal.aborted) abortExternal();
|
|
489
|
-
return {
|
|
490
|
-
signal: controller.signal,
|
|
491
|
-
cleanup: () => {
|
|
492
|
-
timeoutSignal.removeEventListener("abort", abortTimeout);
|
|
493
|
-
externalSignal.removeEventListener("abort", abortExternal);
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
function getAbortReason(signal) {
|
|
498
|
-
return signal.reason ?? createAbortError();
|
|
499
|
-
}
|
|
500
480
|
function createAbortError() {
|
|
501
481
|
return new DOMException("The operation was aborted.", "AbortError");
|
|
502
482
|
}
|
|
@@ -504,20 +484,26 @@ function isCallerAbort(error, signal) {
|
|
|
504
484
|
return isAbortError(error) || error === signal?.reason;
|
|
505
485
|
}
|
|
506
486
|
function getReceiptErrors(receipt, provider) {
|
|
507
|
-
if (receipt.errors != null && receipt.errors.length > 0) return receipt.errors.map((error) => error
|
|
508
|
-
...error,
|
|
509
|
-
provider
|
|
510
|
-
} : error);
|
|
487
|
+
if (receipt.errors != null && receipt.errors.length > 0) return receipt.errors.map((error) => withReceiptErrorProvider(error, provider));
|
|
511
488
|
return receipt.errorMessages.map((message) => (0, __upyo_core.createReceiptError)(message, { provider: receipt.provider ?? provider }));
|
|
512
489
|
}
|
|
513
490
|
function getThrownReceiptErrors(error, provider) {
|
|
514
|
-
if (isReceiptError(error)) return [error
|
|
515
|
-
...error,
|
|
516
|
-
provider
|
|
517
|
-
} : error];
|
|
491
|
+
if (isReceiptError(error)) return [withReceiptErrorProvider(error, provider)];
|
|
518
492
|
if (isFailedReceipt(error)) return getReceiptErrors(error, provider);
|
|
519
493
|
return [];
|
|
520
494
|
}
|
|
495
|
+
function withReceiptErrorProvider(error, provider) {
|
|
496
|
+
return {
|
|
497
|
+
message: error.message,
|
|
498
|
+
code: error.code,
|
|
499
|
+
category: error.category,
|
|
500
|
+
retryable: error.retryable,
|
|
501
|
+
provider: error.provider ?? provider,
|
|
502
|
+
statusCode: error.statusCode,
|
|
503
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
504
|
+
providerDetails: error.providerDetails
|
|
505
|
+
};
|
|
506
|
+
}
|
|
521
507
|
function isReceiptError(value) {
|
|
522
508
|
return typeof value === "object" && value != null && typeof value.message === "string" && typeof value.code === "string" && typeof value.retryable === "boolean" && typeof value.category === "string";
|
|
523
509
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFailedReceipt, createReceiptError } from "@upyo/core";
|
|
1
|
+
import { combineSignals, createFailedReceipt, createReceiptError } from "@upyo/core";
|
|
2
2
|
|
|
3
3
|
//#region src/config.ts
|
|
4
4
|
/**
|
|
@@ -305,6 +305,7 @@ var PoolTransport = class {
|
|
|
305
305
|
const attemptedIndices = /* @__PURE__ */ new Set();
|
|
306
306
|
const errorMessages = [];
|
|
307
307
|
const errors = [];
|
|
308
|
+
let checkCallerAbortBeforeFailure = false;
|
|
308
309
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
309
310
|
if (options?.signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
|
|
310
311
|
const selection = this.strategy.select(message, this.config.transports, attemptedIndices);
|
|
@@ -328,24 +329,29 @@ var PoolTransport = class {
|
|
|
328
329
|
if (receipt.successful) return receipt;
|
|
329
330
|
errorMessages.push(...receipt.errorMessages);
|
|
330
331
|
errors.push(...getReceiptErrors(receipt, selection.entry.transport.id));
|
|
332
|
+
checkCallerAbortBeforeFailure = true;
|
|
331
333
|
} catch (error) {
|
|
332
334
|
if (abortedByCaller && isCallerAbort(error, options?.signal)) throw error;
|
|
333
335
|
const thrownErrors = getThrownReceiptErrors(error, selection.entry.transport.id);
|
|
334
336
|
if (thrownErrors.length > 0) {
|
|
335
337
|
errorMessages.push(...thrownErrors.map((item) => item.message));
|
|
336
338
|
errors.push(...thrownErrors);
|
|
339
|
+
checkCallerAbortBeforeFailure = true;
|
|
337
340
|
continue;
|
|
338
341
|
}
|
|
339
342
|
const timeoutMessage = "Transport send timed out.";
|
|
340
|
-
const
|
|
343
|
+
const abortError = isAbortError(error);
|
|
344
|
+
const errorMessage = abortError ? timeoutMessage : error instanceof Error ? error.message : String(error);
|
|
341
345
|
errorMessages.push(errorMessage);
|
|
342
346
|
errors.push(createReceiptError(errorMessage, {
|
|
343
347
|
provider: selection.entry.transport.id,
|
|
344
|
-
category:
|
|
345
|
-
retryable:
|
|
348
|
+
category: abortError ? "timeout" : void 0,
|
|
349
|
+
retryable: abortError ? true : void 0
|
|
346
350
|
}));
|
|
351
|
+
checkCallerAbortBeforeFailure ||= !abortError;
|
|
347
352
|
}
|
|
348
353
|
}
|
|
354
|
+
if (checkCallerAbortBeforeFailure) options?.signal?.throwIfAborted();
|
|
349
355
|
return createFailedReceipt(errorMessages.length > 0 ? errorMessages : ["All transports failed to send the message."], {
|
|
350
356
|
provider: "pool",
|
|
351
357
|
errors: errors.length > 0 ? errors : void 0,
|
|
@@ -448,32 +454,6 @@ var PoolTransport = class {
|
|
|
448
454
|
};
|
|
449
455
|
}
|
|
450
456
|
};
|
|
451
|
-
function combineSignals(timeoutSignal, externalSignal) {
|
|
452
|
-
if (typeof AbortSignal.any === "function") return {
|
|
453
|
-
signal: AbortSignal.any([timeoutSignal, externalSignal]),
|
|
454
|
-
cleanup: () => {}
|
|
455
|
-
};
|
|
456
|
-
const controller = new AbortController();
|
|
457
|
-
const abort = (signal) => {
|
|
458
|
-
controller.abort(getAbortReason(signal));
|
|
459
|
-
};
|
|
460
|
-
const abortTimeout = () => abort(timeoutSignal);
|
|
461
|
-
const abortExternal = () => abort(externalSignal);
|
|
462
|
-
timeoutSignal.addEventListener("abort", abortTimeout, { once: true });
|
|
463
|
-
externalSignal.addEventListener("abort", abortExternal, { once: true });
|
|
464
|
-
if (timeoutSignal.aborted) abortTimeout();
|
|
465
|
-
else if (externalSignal.aborted) abortExternal();
|
|
466
|
-
return {
|
|
467
|
-
signal: controller.signal,
|
|
468
|
-
cleanup: () => {
|
|
469
|
-
timeoutSignal.removeEventListener("abort", abortTimeout);
|
|
470
|
-
externalSignal.removeEventListener("abort", abortExternal);
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
function getAbortReason(signal) {
|
|
475
|
-
return signal.reason ?? createAbortError();
|
|
476
|
-
}
|
|
477
457
|
function createAbortError() {
|
|
478
458
|
return new DOMException("The operation was aborted.", "AbortError");
|
|
479
459
|
}
|
|
@@ -481,20 +461,26 @@ function isCallerAbort(error, signal) {
|
|
|
481
461
|
return isAbortError(error) || error === signal?.reason;
|
|
482
462
|
}
|
|
483
463
|
function getReceiptErrors(receipt, provider) {
|
|
484
|
-
if (receipt.errors != null && receipt.errors.length > 0) return receipt.errors.map((error) => error
|
|
485
|
-
...error,
|
|
486
|
-
provider
|
|
487
|
-
} : error);
|
|
464
|
+
if (receipt.errors != null && receipt.errors.length > 0) return receipt.errors.map((error) => withReceiptErrorProvider(error, provider));
|
|
488
465
|
return receipt.errorMessages.map((message) => createReceiptError(message, { provider: receipt.provider ?? provider }));
|
|
489
466
|
}
|
|
490
467
|
function getThrownReceiptErrors(error, provider) {
|
|
491
|
-
if (isReceiptError(error)) return [error
|
|
492
|
-
...error,
|
|
493
|
-
provider
|
|
494
|
-
} : error];
|
|
468
|
+
if (isReceiptError(error)) return [withReceiptErrorProvider(error, provider)];
|
|
495
469
|
if (isFailedReceipt(error)) return getReceiptErrors(error, provider);
|
|
496
470
|
return [];
|
|
497
471
|
}
|
|
472
|
+
function withReceiptErrorProvider(error, provider) {
|
|
473
|
+
return {
|
|
474
|
+
message: error.message,
|
|
475
|
+
code: error.code,
|
|
476
|
+
category: error.category,
|
|
477
|
+
retryable: error.retryable,
|
|
478
|
+
provider: error.provider ?? provider,
|
|
479
|
+
statusCode: error.statusCode,
|
|
480
|
+
retryAfterMilliseconds: error.retryAfterMilliseconds,
|
|
481
|
+
providerDetails: error.providerDetails
|
|
482
|
+
};
|
|
483
|
+
}
|
|
498
484
|
function isReceiptError(value) {
|
|
499
485
|
return typeof value === "object" && value != null && typeof value.message === "string" && typeof value.code === "string" && typeof value.retryable === "boolean" && typeof value.category === "string";
|
|
500
486
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/pool",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.172",
|
|
4
4
|
"description": "Pool transport for Upyo email library—provides load balancing and failover for multiple email providers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
},
|
|
57
57
|
"sideEffects": false,
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@upyo/core": "0.5.0-dev.
|
|
59
|
+
"@upyo/core": "0.5.0-dev.172+1b1248e1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"tsdown": "^0.12.7",
|
|
63
63
|
"typescript": "5.8.3",
|
|
64
|
-
"@upyo/mock": "0.5.0-dev.
|
|
64
|
+
"@upyo/mock": "0.5.0-dev.172+1b1248e1"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"prepublish": "mise run --no-deps :build"
|