@doist/comms-sdk 3.0.0 → 3.0.1
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.
|
@@ -4,7 +4,8 @@ import { transformTimestamps } from '../utils/timestamp-conversion.js';
|
|
|
4
4
|
import { getDefaultTransport } from './http-dispatcher.js';
|
|
5
5
|
export async function fetchWithRetry(url, options, maxRetries = 3, customFetch) {
|
|
6
6
|
let lastError;
|
|
7
|
-
|
|
7
|
+
let attempt = 0;
|
|
8
|
+
for (; attempt <= maxRetries; attempt++) {
|
|
8
9
|
let clearTimeoutFn;
|
|
9
10
|
try {
|
|
10
11
|
let requestSignal = options.signal || undefined;
|
|
@@ -56,7 +57,48 @@ export async function fetchWithRetry(url, options, maxRetries = 3, customFetch)
|
|
|
56
57
|
if (lastError instanceof CommsRequestError) {
|
|
57
58
|
throw lastError;
|
|
58
59
|
}
|
|
59
|
-
throw new CommsRequestError(lastError
|
|
60
|
+
throw new CommsRequestError(describeTransportFailure(lastError, attempt + 1), undefined, undefined, {
|
|
61
|
+
cause: lastError,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Causes reported before the rest of the chain is dropped. */
|
|
65
|
+
const CAUSE_CHAIN_LIMIT = 3;
|
|
66
|
+
/**
|
|
67
|
+
* Builds the message for a request that never produced a response.
|
|
68
|
+
*
|
|
69
|
+
* `fetch` reports every transport problem as the same `fetch failed`, and puts
|
|
70
|
+
* the reason a caller actually needs — `ENOTFOUND`, `ECONNRESET`, a TLS failure
|
|
71
|
+
* — in `cause`. Dropping that leaves an unattributable error in the logs, so
|
|
72
|
+
* unwrap the chain into the message and keep the original as `cause`.
|
|
73
|
+
*/
|
|
74
|
+
function describeTransportFailure(error, attempts) {
|
|
75
|
+
const base = error?.message ?? 'Request failed';
|
|
76
|
+
const cause = describeCauseChain(error);
|
|
77
|
+
const tries = attempts > 1 ? ` after ${attempts} attempts` : '';
|
|
78
|
+
return cause ? `${base} (${cause})${tries}` : `${base}${tries}`;
|
|
79
|
+
}
|
|
80
|
+
function describeCauseChain(error) {
|
|
81
|
+
const descriptions = [];
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
let current = error?.cause;
|
|
84
|
+
while (current instanceof Error &&
|
|
85
|
+
!seen.has(current) &&
|
|
86
|
+
descriptions.length < CAUSE_CHAIN_LIMIT) {
|
|
87
|
+
seen.add(current);
|
|
88
|
+
const description = describeCause(current);
|
|
89
|
+
if (description) {
|
|
90
|
+
descriptions.push(description);
|
|
91
|
+
}
|
|
92
|
+
// A failed connect can carry one error per address it tried; the first
|
|
93
|
+
// one is representative and the rest are the same failure repeated.
|
|
94
|
+
const aggregated = current instanceof AggregateError ? current.errors[0] : undefined;
|
|
95
|
+
current = aggregated ?? current.cause;
|
|
96
|
+
}
|
|
97
|
+
return descriptions.length > 0 ? descriptions.join(' <- ') : undefined;
|
|
98
|
+
}
|
|
99
|
+
function describeCause(error) {
|
|
100
|
+
const code = error.code;
|
|
101
|
+
return typeof code === 'string' && code.length > 0 ? `${code}: ${error.message}` : error.message;
|
|
60
102
|
}
|
|
61
103
|
async function fetchWithDefaultTransport(url, options, signal) {
|
|
62
104
|
// Read the dispatcher and its paired `fetch` as one value so they can never
|
package/dist/esm/types/errors.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CustomError } from 'ts-custom-error';
|
|
2
2
|
export class CommsRequestError extends CustomError {
|
|
3
|
-
constructor(message, httpStatusCode, responseData) {
|
|
4
|
-
super(message);
|
|
3
|
+
constructor(message, httpStatusCode, responseData, options) {
|
|
4
|
+
super(message, options);
|
|
5
5
|
this.httpStatusCode = httpStatusCode;
|
|
6
6
|
this.responseData = responseData;
|
|
7
7
|
}
|
|
@@ -2,5 +2,5 @@ import { CustomError } from 'ts-custom-error';
|
|
|
2
2
|
export declare class CommsRequestError extends CustomError {
|
|
3
3
|
httpStatusCode?: number;
|
|
4
4
|
responseData?: unknown;
|
|
5
|
-
constructor(message: string, httpStatusCode?: number, responseData?: unknown);
|
|
5
|
+
constructor(message: string, httpStatusCode?: number, responseData?: unknown, options?: ErrorOptions);
|
|
6
6
|
}
|