@upyo/retry 0.5.0-dev.197 → 0.5.0-dev.201
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 +72 -31
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +72 -31
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -113,6 +113,7 @@ var RetryTransport = class {
|
|
|
113
113
|
* @param transport The transport to wrap.
|
|
114
114
|
* @param config Retry configuration.
|
|
115
115
|
* @throws {RangeError} If retry configuration is invalid.
|
|
116
|
+
* @since 0.5.0
|
|
116
117
|
*/
|
|
117
118
|
constructor(transport, config = {}) {
|
|
118
119
|
this.wrappedTransport = transport;
|
|
@@ -126,25 +127,16 @@ var RetryTransport = class {
|
|
|
126
127
|
* @param options Optional transport options.
|
|
127
128
|
* @returns The final delivery receipt.
|
|
128
129
|
* @throws {DOMException} If the operation is aborted.
|
|
130
|
+
* @since 0.5.0
|
|
129
131
|
*/
|
|
130
132
|
async send(message, options) {
|
|
131
133
|
options?.signal?.throwIfAborted();
|
|
132
134
|
let lastThrownError;
|
|
133
135
|
for (let attempt = 1; attempt <= this.config.maxAttempts; attempt++) {
|
|
134
136
|
options?.signal?.throwIfAborted();
|
|
137
|
+
let receipt;
|
|
135
138
|
try {
|
|
136
|
-
|
|
137
|
-
if (receipt.successful) return this.withSuccessMetadata(receipt, attempt);
|
|
138
|
-
const failedReceipt = this.withFailureMetadata(receipt, attempt);
|
|
139
|
-
if (attempt >= this.config.maxAttempts || !this.shouldRetryReceipt(failedReceipt)) return failedReceipt;
|
|
140
|
-
await this.waitBeforeRetry({
|
|
141
|
-
attempt,
|
|
142
|
-
nextAttempt: attempt + 1,
|
|
143
|
-
maxAttempts: this.config.maxAttempts,
|
|
144
|
-
delayMilliseconds: this.calculateDelay(attempt, failedReceipt),
|
|
145
|
-
receipt: failedReceipt,
|
|
146
|
-
reason: "retry"
|
|
147
|
-
}, options?.signal);
|
|
139
|
+
receipt = await this.wrappedTransport.send(message, options);
|
|
148
140
|
} catch (error) {
|
|
149
141
|
options?.signal?.throwIfAborted();
|
|
150
142
|
lastThrownError = error;
|
|
@@ -157,7 +149,20 @@ var RetryTransport = class {
|
|
|
157
149
|
error,
|
|
158
150
|
reason: "retry"
|
|
159
151
|
}, options?.signal);
|
|
152
|
+
continue;
|
|
160
153
|
}
|
|
154
|
+
options?.signal?.throwIfAborted();
|
|
155
|
+
if (receipt.successful) return this.withSuccessMetadata(receipt, attempt);
|
|
156
|
+
const failedReceipt = this.withFailureMetadata(receipt, attempt);
|
|
157
|
+
if (attempt >= this.config.maxAttempts || !this.shouldRetryReceipt(failedReceipt)) return failedReceipt;
|
|
158
|
+
await this.waitBeforeRetry({
|
|
159
|
+
attempt,
|
|
160
|
+
nextAttempt: attempt + 1,
|
|
161
|
+
maxAttempts: this.config.maxAttempts,
|
|
162
|
+
delayMilliseconds: this.calculateDelay(attempt, failedReceipt),
|
|
163
|
+
receipt: failedReceipt,
|
|
164
|
+
reason: "retry"
|
|
165
|
+
}, options?.signal);
|
|
161
166
|
}
|
|
162
167
|
return this.createThrownFailure(lastThrownError, this.config.maxAttempts);
|
|
163
168
|
}
|
|
@@ -170,6 +175,7 @@ var RetryTransport = class {
|
|
|
170
175
|
* @param options Optional transport options.
|
|
171
176
|
* @returns An async iterable of receipts.
|
|
172
177
|
* @throws {DOMException} If the operation is aborted.
|
|
178
|
+
* @since 0.5.0
|
|
173
179
|
*/
|
|
174
180
|
async *sendMany(messages, options) {
|
|
175
181
|
const iterator = toAsyncIterator(messages);
|
|
@@ -181,6 +187,7 @@ var RetryTransport = class {
|
|
|
181
187
|
let launchPromise;
|
|
182
188
|
let launchError;
|
|
183
189
|
let hasLaunchError = false;
|
|
190
|
+
let hasQueuedFailure = false;
|
|
184
191
|
let pullingInput = false;
|
|
185
192
|
let closed = false;
|
|
186
193
|
const controller = new AbortController();
|
|
@@ -193,12 +200,16 @@ var RetryTransport = class {
|
|
|
193
200
|
if (inputDone) return;
|
|
194
201
|
combinedSignal.signal.throwIfAborted();
|
|
195
202
|
pullingInput = true;
|
|
196
|
-
let
|
|
203
|
+
let inputPull;
|
|
197
204
|
try {
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
205
|
+
inputPull = Promise.resolve(iterator.next());
|
|
206
|
+
} catch (error) {
|
|
207
|
+
inputPull = Promise.reject(error);
|
|
201
208
|
}
|
|
209
|
+
inputPull = inputPull.finally(() => {
|
|
210
|
+
pullingInput = false;
|
|
211
|
+
});
|
|
212
|
+
const next = await raceWithAbort(inputPull, combinedSignal.signal);
|
|
202
213
|
if (closed) return;
|
|
203
214
|
if (next.done) {
|
|
204
215
|
inputDone = true;
|
|
@@ -219,7 +230,7 @@ var RetryTransport = class {
|
|
|
219
230
|
inFlight.set(index, promise);
|
|
220
231
|
};
|
|
221
232
|
const startLaunch = () => {
|
|
222
|
-
if (launchPromise != null || inputDone || hasLaunchError || inFlight.size >= this.config.sendMany.maxConcurrent) return;
|
|
233
|
+
if (launchPromise != null || inputDone || hasLaunchError || hasQueuedFailure || inFlight.size >= this.config.sendMany.maxConcurrent) return;
|
|
223
234
|
launchPromise = launchNext().catch((error) => {
|
|
224
235
|
launchError = error;
|
|
225
236
|
hasLaunchError = true;
|
|
@@ -247,6 +258,7 @@ var RetryTransport = class {
|
|
|
247
258
|
if ("launched" in result) continue;
|
|
248
259
|
inFlight.delete(result.index);
|
|
249
260
|
completed.set(result.index, result);
|
|
261
|
+
if (!result.successful) hasQueuedFailure = true;
|
|
250
262
|
startLaunch();
|
|
251
263
|
}
|
|
252
264
|
if (hasLaunchError) throw launchError;
|
|
@@ -272,15 +284,20 @@ var RetryTransport = class {
|
|
|
272
284
|
* @since 0.5.0
|
|
273
285
|
*/
|
|
274
286
|
async [Symbol.asyncDispose]() {
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
if (typeof
|
|
278
|
-
|
|
279
|
-
|
|
287
|
+
const wrappedTransport = Object(this.wrappedTransport);
|
|
288
|
+
const asyncDisposeSymbol = Symbol.asyncDispose;
|
|
289
|
+
if (typeof asyncDisposeSymbol === "symbol") {
|
|
290
|
+
const asyncDispose = wrappedTransport[asyncDisposeSymbol];
|
|
291
|
+
if (typeof asyncDispose === "function") {
|
|
292
|
+
await asyncDispose.call(wrappedTransport);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const disposeSymbol = Symbol.dispose;
|
|
297
|
+
if (typeof disposeSymbol === "symbol") {
|
|
298
|
+
const dispose = wrappedTransport[disposeSymbol];
|
|
299
|
+
if (typeof dispose === "function") dispose.call(wrappedTransport);
|
|
280
300
|
}
|
|
281
|
-
const disposable = this.wrappedTransport;
|
|
282
|
-
const dispose = disposable[Symbol.dispose];
|
|
283
|
-
if (typeof dispose === "function") dispose.call(disposable);
|
|
284
301
|
}
|
|
285
302
|
withSuccessMetadata(receipt, attempts) {
|
|
286
303
|
return {
|
|
@@ -323,7 +340,7 @@ var RetryTransport = class {
|
|
|
323
340
|
}
|
|
324
341
|
calculateDelay(attempt, failure) {
|
|
325
342
|
const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
|
|
326
|
-
const cappedRetryAfter = retryAfterMilliseconds == null ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
|
|
343
|
+
const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds <= 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
|
|
327
344
|
if (cappedRetryAfter != null) return cappedRetryAfter;
|
|
328
345
|
const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
|
|
329
346
|
if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
|
|
@@ -387,20 +404,44 @@ function getRetryAfterMilliseconds(failure) {
|
|
|
387
404
|
return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
|
|
388
405
|
}
|
|
389
406
|
function toAsyncIterator(values) {
|
|
390
|
-
|
|
407
|
+
const asyncIterator = values[Symbol.asyncIterator];
|
|
408
|
+
if (typeof asyncIterator === "function") return asyncIterator.call(values);
|
|
391
409
|
const iterator = values[Symbol.iterator]();
|
|
392
410
|
return {
|
|
393
|
-
next() {
|
|
394
|
-
return Promise.resolve(iterator.next());
|
|
411
|
+
async next() {
|
|
412
|
+
return await Promise.resolve(iterator.next());
|
|
395
413
|
},
|
|
396
|
-
return(value) {
|
|
397
|
-
return Promise.resolve(iterator.return?.(value) ?? {
|
|
414
|
+
async return(value) {
|
|
415
|
+
return await Promise.resolve(iterator.return?.(value) ?? {
|
|
398
416
|
done: true,
|
|
399
417
|
value
|
|
400
418
|
});
|
|
401
419
|
}
|
|
402
420
|
};
|
|
403
421
|
}
|
|
422
|
+
function raceWithAbort(promise, signal) {
|
|
423
|
+
if (signal.aborted) return Promise.reject(getAbortReason(signal));
|
|
424
|
+
return new Promise((resolve, reject) => {
|
|
425
|
+
const abort = () => {
|
|
426
|
+
cleanup();
|
|
427
|
+
reject(getAbortReason(signal));
|
|
428
|
+
};
|
|
429
|
+
const cleanup = () => {
|
|
430
|
+
signal.removeEventListener("abort", abort);
|
|
431
|
+
};
|
|
432
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
433
|
+
promise.then((value) => {
|
|
434
|
+
cleanup();
|
|
435
|
+
resolve(value);
|
|
436
|
+
}, (error) => {
|
|
437
|
+
cleanup();
|
|
438
|
+
reject(error);
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function getAbortReason(signal) {
|
|
443
|
+
return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
444
|
+
}
|
|
404
445
|
function toReceiptError(value) {
|
|
405
446
|
return isReceiptError(value) ? value : void 0;
|
|
406
447
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -207,6 +207,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
207
207
|
* @param transport The transport to wrap.
|
|
208
208
|
* @param config Retry configuration.
|
|
209
209
|
* @throws {RangeError} If retry configuration is invalid.
|
|
210
|
+
* @since 0.5.0
|
|
210
211
|
*/
|
|
211
212
|
constructor(transport: Transport<TProviderId>, config?: RetryConfig<TProviderId>);
|
|
212
213
|
/**
|
|
@@ -216,6 +217,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
216
217
|
* @param options Optional transport options.
|
|
217
218
|
* @returns The final delivery receipt.
|
|
218
219
|
* @throws {DOMException} If the operation is aborted.
|
|
220
|
+
* @since 0.5.0
|
|
219
221
|
*/
|
|
220
222
|
send(message: Message, options?: TransportOptions): Promise<Receipt<TProviderId>>;
|
|
221
223
|
/**
|
|
@@ -227,6 +229,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
227
229
|
* @param options Optional transport options.
|
|
228
230
|
* @returns An async iterable of receipts.
|
|
229
231
|
* @throws {DOMException} If the operation is aborted.
|
|
232
|
+
* @since 0.5.0
|
|
230
233
|
*/
|
|
231
234
|
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<TProviderId>>;
|
|
232
235
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -207,6 +207,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
207
207
|
* @param transport The transport to wrap.
|
|
208
208
|
* @param config Retry configuration.
|
|
209
209
|
* @throws {RangeError} If retry configuration is invalid.
|
|
210
|
+
* @since 0.5.0
|
|
210
211
|
*/
|
|
211
212
|
constructor(transport: Transport<TProviderId>, config?: RetryConfig<TProviderId>);
|
|
212
213
|
/**
|
|
@@ -216,6 +217,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
216
217
|
* @param options Optional transport options.
|
|
217
218
|
* @returns The final delivery receipt.
|
|
218
219
|
* @throws {DOMException} If the operation is aborted.
|
|
220
|
+
* @since 0.5.0
|
|
219
221
|
*/
|
|
220
222
|
send(message: Message, options?: TransportOptions): Promise<Receipt<TProviderId>>;
|
|
221
223
|
/**
|
|
@@ -227,6 +229,7 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
|
|
|
227
229
|
* @param options Optional transport options.
|
|
228
230
|
* @returns An async iterable of receipts.
|
|
229
231
|
* @throws {DOMException} If the operation is aborted.
|
|
232
|
+
* @since 0.5.0
|
|
230
233
|
*/
|
|
231
234
|
sendMany(messages: Iterable<Message> | AsyncIterable<Message>, options?: TransportOptions): AsyncIterable<Receipt<TProviderId>>;
|
|
232
235
|
/**
|
package/dist/index.js
CHANGED
|
@@ -90,6 +90,7 @@ var RetryTransport = class {
|
|
|
90
90
|
* @param transport The transport to wrap.
|
|
91
91
|
* @param config Retry configuration.
|
|
92
92
|
* @throws {RangeError} If retry configuration is invalid.
|
|
93
|
+
* @since 0.5.0
|
|
93
94
|
*/
|
|
94
95
|
constructor(transport, config = {}) {
|
|
95
96
|
this.wrappedTransport = transport;
|
|
@@ -103,25 +104,16 @@ var RetryTransport = class {
|
|
|
103
104
|
* @param options Optional transport options.
|
|
104
105
|
* @returns The final delivery receipt.
|
|
105
106
|
* @throws {DOMException} If the operation is aborted.
|
|
107
|
+
* @since 0.5.0
|
|
106
108
|
*/
|
|
107
109
|
async send(message, options) {
|
|
108
110
|
options?.signal?.throwIfAborted();
|
|
109
111
|
let lastThrownError;
|
|
110
112
|
for (let attempt = 1; attempt <= this.config.maxAttempts; attempt++) {
|
|
111
113
|
options?.signal?.throwIfAborted();
|
|
114
|
+
let receipt;
|
|
112
115
|
try {
|
|
113
|
-
|
|
114
|
-
if (receipt.successful) return this.withSuccessMetadata(receipt, attempt);
|
|
115
|
-
const failedReceipt = this.withFailureMetadata(receipt, attempt);
|
|
116
|
-
if (attempt >= this.config.maxAttempts || !this.shouldRetryReceipt(failedReceipt)) return failedReceipt;
|
|
117
|
-
await this.waitBeforeRetry({
|
|
118
|
-
attempt,
|
|
119
|
-
nextAttempt: attempt + 1,
|
|
120
|
-
maxAttempts: this.config.maxAttempts,
|
|
121
|
-
delayMilliseconds: this.calculateDelay(attempt, failedReceipt),
|
|
122
|
-
receipt: failedReceipt,
|
|
123
|
-
reason: "retry"
|
|
124
|
-
}, options?.signal);
|
|
116
|
+
receipt = await this.wrappedTransport.send(message, options);
|
|
125
117
|
} catch (error) {
|
|
126
118
|
options?.signal?.throwIfAborted();
|
|
127
119
|
lastThrownError = error;
|
|
@@ -134,7 +126,20 @@ var RetryTransport = class {
|
|
|
134
126
|
error,
|
|
135
127
|
reason: "retry"
|
|
136
128
|
}, options?.signal);
|
|
129
|
+
continue;
|
|
137
130
|
}
|
|
131
|
+
options?.signal?.throwIfAborted();
|
|
132
|
+
if (receipt.successful) return this.withSuccessMetadata(receipt, attempt);
|
|
133
|
+
const failedReceipt = this.withFailureMetadata(receipt, attempt);
|
|
134
|
+
if (attempt >= this.config.maxAttempts || !this.shouldRetryReceipt(failedReceipt)) return failedReceipt;
|
|
135
|
+
await this.waitBeforeRetry({
|
|
136
|
+
attempt,
|
|
137
|
+
nextAttempt: attempt + 1,
|
|
138
|
+
maxAttempts: this.config.maxAttempts,
|
|
139
|
+
delayMilliseconds: this.calculateDelay(attempt, failedReceipt),
|
|
140
|
+
receipt: failedReceipt,
|
|
141
|
+
reason: "retry"
|
|
142
|
+
}, options?.signal);
|
|
138
143
|
}
|
|
139
144
|
return this.createThrownFailure(lastThrownError, this.config.maxAttempts);
|
|
140
145
|
}
|
|
@@ -147,6 +152,7 @@ var RetryTransport = class {
|
|
|
147
152
|
* @param options Optional transport options.
|
|
148
153
|
* @returns An async iterable of receipts.
|
|
149
154
|
* @throws {DOMException} If the operation is aborted.
|
|
155
|
+
* @since 0.5.0
|
|
150
156
|
*/
|
|
151
157
|
async *sendMany(messages, options) {
|
|
152
158
|
const iterator = toAsyncIterator(messages);
|
|
@@ -158,6 +164,7 @@ var RetryTransport = class {
|
|
|
158
164
|
let launchPromise;
|
|
159
165
|
let launchError;
|
|
160
166
|
let hasLaunchError = false;
|
|
167
|
+
let hasQueuedFailure = false;
|
|
161
168
|
let pullingInput = false;
|
|
162
169
|
let closed = false;
|
|
163
170
|
const controller = new AbortController();
|
|
@@ -170,12 +177,16 @@ var RetryTransport = class {
|
|
|
170
177
|
if (inputDone) return;
|
|
171
178
|
combinedSignal.signal.throwIfAborted();
|
|
172
179
|
pullingInput = true;
|
|
173
|
-
let
|
|
180
|
+
let inputPull;
|
|
174
181
|
try {
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
182
|
+
inputPull = Promise.resolve(iterator.next());
|
|
183
|
+
} catch (error) {
|
|
184
|
+
inputPull = Promise.reject(error);
|
|
178
185
|
}
|
|
186
|
+
inputPull = inputPull.finally(() => {
|
|
187
|
+
pullingInput = false;
|
|
188
|
+
});
|
|
189
|
+
const next = await raceWithAbort(inputPull, combinedSignal.signal);
|
|
179
190
|
if (closed) return;
|
|
180
191
|
if (next.done) {
|
|
181
192
|
inputDone = true;
|
|
@@ -196,7 +207,7 @@ var RetryTransport = class {
|
|
|
196
207
|
inFlight.set(index, promise);
|
|
197
208
|
};
|
|
198
209
|
const startLaunch = () => {
|
|
199
|
-
if (launchPromise != null || inputDone || hasLaunchError || inFlight.size >= this.config.sendMany.maxConcurrent) return;
|
|
210
|
+
if (launchPromise != null || inputDone || hasLaunchError || hasQueuedFailure || inFlight.size >= this.config.sendMany.maxConcurrent) return;
|
|
200
211
|
launchPromise = launchNext().catch((error) => {
|
|
201
212
|
launchError = error;
|
|
202
213
|
hasLaunchError = true;
|
|
@@ -224,6 +235,7 @@ var RetryTransport = class {
|
|
|
224
235
|
if ("launched" in result) continue;
|
|
225
236
|
inFlight.delete(result.index);
|
|
226
237
|
completed.set(result.index, result);
|
|
238
|
+
if (!result.successful) hasQueuedFailure = true;
|
|
227
239
|
startLaunch();
|
|
228
240
|
}
|
|
229
241
|
if (hasLaunchError) throw launchError;
|
|
@@ -249,15 +261,20 @@ var RetryTransport = class {
|
|
|
249
261
|
* @since 0.5.0
|
|
250
262
|
*/
|
|
251
263
|
async [Symbol.asyncDispose]() {
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
if (typeof
|
|
255
|
-
|
|
256
|
-
|
|
264
|
+
const wrappedTransport = Object(this.wrappedTransport);
|
|
265
|
+
const asyncDisposeSymbol = Symbol.asyncDispose;
|
|
266
|
+
if (typeof asyncDisposeSymbol === "symbol") {
|
|
267
|
+
const asyncDispose = wrappedTransport[asyncDisposeSymbol];
|
|
268
|
+
if (typeof asyncDispose === "function") {
|
|
269
|
+
await asyncDispose.call(wrappedTransport);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const disposeSymbol = Symbol.dispose;
|
|
274
|
+
if (typeof disposeSymbol === "symbol") {
|
|
275
|
+
const dispose = wrappedTransport[disposeSymbol];
|
|
276
|
+
if (typeof dispose === "function") dispose.call(wrappedTransport);
|
|
257
277
|
}
|
|
258
|
-
const disposable = this.wrappedTransport;
|
|
259
|
-
const dispose = disposable[Symbol.dispose];
|
|
260
|
-
if (typeof dispose === "function") dispose.call(disposable);
|
|
261
278
|
}
|
|
262
279
|
withSuccessMetadata(receipt, attempts) {
|
|
263
280
|
return {
|
|
@@ -300,7 +317,7 @@ var RetryTransport = class {
|
|
|
300
317
|
}
|
|
301
318
|
calculateDelay(attempt, failure) {
|
|
302
319
|
const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
|
|
303
|
-
const cappedRetryAfter = retryAfterMilliseconds == null ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
|
|
320
|
+
const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds <= 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
|
|
304
321
|
if (cappedRetryAfter != null) return cappedRetryAfter;
|
|
305
322
|
const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
|
|
306
323
|
if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
|
|
@@ -364,20 +381,44 @@ function getRetryAfterMilliseconds(failure) {
|
|
|
364
381
|
return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
|
|
365
382
|
}
|
|
366
383
|
function toAsyncIterator(values) {
|
|
367
|
-
|
|
384
|
+
const asyncIterator = values[Symbol.asyncIterator];
|
|
385
|
+
if (typeof asyncIterator === "function") return asyncIterator.call(values);
|
|
368
386
|
const iterator = values[Symbol.iterator]();
|
|
369
387
|
return {
|
|
370
|
-
next() {
|
|
371
|
-
return Promise.resolve(iterator.next());
|
|
388
|
+
async next() {
|
|
389
|
+
return await Promise.resolve(iterator.next());
|
|
372
390
|
},
|
|
373
|
-
return(value) {
|
|
374
|
-
return Promise.resolve(iterator.return?.(value) ?? {
|
|
391
|
+
async return(value) {
|
|
392
|
+
return await Promise.resolve(iterator.return?.(value) ?? {
|
|
375
393
|
done: true,
|
|
376
394
|
value
|
|
377
395
|
});
|
|
378
396
|
}
|
|
379
397
|
};
|
|
380
398
|
}
|
|
399
|
+
function raceWithAbort(promise, signal) {
|
|
400
|
+
if (signal.aborted) return Promise.reject(getAbortReason(signal));
|
|
401
|
+
return new Promise((resolve, reject) => {
|
|
402
|
+
const abort = () => {
|
|
403
|
+
cleanup();
|
|
404
|
+
reject(getAbortReason(signal));
|
|
405
|
+
};
|
|
406
|
+
const cleanup = () => {
|
|
407
|
+
signal.removeEventListener("abort", abort);
|
|
408
|
+
};
|
|
409
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
410
|
+
promise.then((value) => {
|
|
411
|
+
cleanup();
|
|
412
|
+
resolve(value);
|
|
413
|
+
}, (error) => {
|
|
414
|
+
cleanup();
|
|
415
|
+
reject(error);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function getAbortReason(signal) {
|
|
420
|
+
return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
421
|
+
}
|
|
381
422
|
function toReceiptError(value) {
|
|
382
423
|
return isReceiptError(value) ? value : void 0;
|
|
383
424
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@upyo/retry",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.201",
|
|
4
4
|
"description": "Retry and backoff decorator transport for Upyo email library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"sideEffects": false,
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@upyo/core": "0.5.0-dev.
|
|
57
|
+
"@upyo/core": "0.5.0-dev.201+ecb7233a"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"tsdown": "^0.12.7",
|