@upyo/retry 0.5.0-dev.199 → 0.5.0-dev.205

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 CHANGED
@@ -187,6 +187,7 @@ var RetryTransport = class {
187
187
  let launchPromise;
188
188
  let launchError;
189
189
  let hasLaunchError = false;
190
+ let hasQueuedFailure = false;
190
191
  let pullingInput = false;
191
192
  let closed = false;
192
193
  const controller = new AbortController();
@@ -229,7 +230,7 @@ var RetryTransport = class {
229
230
  inFlight.set(index, promise);
230
231
  };
231
232
  const startLaunch = () => {
232
- 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;
233
234
  launchPromise = launchNext().catch((error) => {
234
235
  launchError = error;
235
236
  hasLaunchError = true;
@@ -240,6 +241,7 @@ var RetryTransport = class {
240
241
  try {
241
242
  startLaunch();
242
243
  while (inFlight.size > 0 || completed.has(nextYieldIndex) || launchPromise != null || !inputDone) {
244
+ combinedSignal.signal.throwIfAborted();
243
245
  while (completed.has(nextYieldIndex)) {
244
246
  const result$1 = completed.get(nextYieldIndex);
245
247
  completed.delete(nextYieldIndex);
@@ -253,10 +255,11 @@ var RetryTransport = class {
253
255
  startLaunch();
254
256
  if (inFlight.size <= 0 && launchPromise == null) break;
255
257
  const launch = launchPromise?.then(() => ({ launched: true }));
256
- const result = await Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]);
258
+ const result = await raceWithAbort(Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]), combinedSignal.signal);
257
259
  if ("launched" in result) continue;
258
260
  inFlight.delete(result.index);
259
261
  completed.set(result.index, result);
262
+ if (!result.successful) hasQueuedFailure = true;
260
263
  startLaunch();
261
264
  }
262
265
  if (hasLaunchError) throw launchError;
@@ -282,15 +285,20 @@ var RetryTransport = class {
282
285
  * @since 0.5.0
283
286
  */
284
287
  async [Symbol.asyncDispose]() {
285
- const asyncDisposable = this.wrappedTransport;
286
- const asyncDispose = asyncDisposable[Symbol.asyncDispose];
287
- if (typeof asyncDispose === "function") {
288
- await asyncDispose.call(asyncDisposable);
289
- return;
288
+ const wrappedTransport = Object(this.wrappedTransport);
289
+ const asyncDisposeSymbol = Symbol.asyncDispose;
290
+ if (typeof asyncDisposeSymbol === "symbol") {
291
+ const asyncDispose = wrappedTransport[asyncDisposeSymbol];
292
+ if (typeof asyncDispose === "function") {
293
+ await asyncDispose.call(wrappedTransport);
294
+ return;
295
+ }
296
+ }
297
+ const disposeSymbol = Symbol.dispose;
298
+ if (typeof disposeSymbol === "symbol") {
299
+ const dispose = wrappedTransport[disposeSymbol];
300
+ if (typeof dispose === "function") dispose.call(wrappedTransport);
290
301
  }
291
- const disposable = this.wrappedTransport;
292
- const dispose = disposable[Symbol.dispose];
293
- if (typeof dispose === "function") dispose.call(disposable);
294
302
  }
295
303
  withSuccessMetadata(receipt, attempts) {
296
304
  return {
@@ -333,7 +341,7 @@ var RetryTransport = class {
333
341
  }
334
342
  calculateDelay(attempt, failure) {
335
343
  const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
336
- const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds <= 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
344
+ const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds < 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
337
345
  if (cappedRetryAfter != null) return cappedRetryAfter;
338
346
  const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
339
347
  if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
@@ -397,7 +405,8 @@ function getRetryAfterMilliseconds(failure) {
397
405
  return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
398
406
  }
399
407
  function toAsyncIterator(values) {
400
- if (Symbol.asyncIterator in values) return values[Symbol.asyncIterator]();
408
+ const asyncIterator = values[Symbol.asyncIterator];
409
+ if (typeof asyncIterator === "function") return asyncIterator.call(values);
401
410
  const iterator = values[Symbol.iterator]();
402
411
  return {
403
412
  async next() {
@@ -412,11 +421,11 @@ function toAsyncIterator(values) {
412
421
  };
413
422
  }
414
423
  function raceWithAbort(promise, signal) {
415
- if (signal.aborted) return Promise.reject(signal.reason);
424
+ if (signal.aborted) return Promise.reject(getAbortReason(signal));
416
425
  return new Promise((resolve, reject) => {
417
426
  const abort = () => {
418
427
  cleanup();
419
- reject(signal.reason);
428
+ reject(getAbortReason(signal));
420
429
  };
421
430
  const cleanup = () => {
422
431
  signal.removeEventListener("abort", abort);
@@ -431,6 +440,9 @@ function raceWithAbort(promise, signal) {
431
440
  });
432
441
  });
433
442
  }
443
+ function getAbortReason(signal) {
444
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
445
+ }
434
446
  function toReceiptError(value) {
435
447
  return isReceiptError(value) ? value : void 0;
436
448
  }
package/dist/index.js CHANGED
@@ -164,6 +164,7 @@ var RetryTransport = class {
164
164
  let launchPromise;
165
165
  let launchError;
166
166
  let hasLaunchError = false;
167
+ let hasQueuedFailure = false;
167
168
  let pullingInput = false;
168
169
  let closed = false;
169
170
  const controller = new AbortController();
@@ -206,7 +207,7 @@ var RetryTransport = class {
206
207
  inFlight.set(index, promise);
207
208
  };
208
209
  const startLaunch = () => {
209
- 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;
210
211
  launchPromise = launchNext().catch((error) => {
211
212
  launchError = error;
212
213
  hasLaunchError = true;
@@ -217,6 +218,7 @@ var RetryTransport = class {
217
218
  try {
218
219
  startLaunch();
219
220
  while (inFlight.size > 0 || completed.has(nextYieldIndex) || launchPromise != null || !inputDone) {
221
+ combinedSignal.signal.throwIfAborted();
220
222
  while (completed.has(nextYieldIndex)) {
221
223
  const result$1 = completed.get(nextYieldIndex);
222
224
  completed.delete(nextYieldIndex);
@@ -230,10 +232,11 @@ var RetryTransport = class {
230
232
  startLaunch();
231
233
  if (inFlight.size <= 0 && launchPromise == null) break;
232
234
  const launch = launchPromise?.then(() => ({ launched: true }));
233
- const result = await Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]);
235
+ const result = await raceWithAbort(Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]), combinedSignal.signal);
234
236
  if ("launched" in result) continue;
235
237
  inFlight.delete(result.index);
236
238
  completed.set(result.index, result);
239
+ if (!result.successful) hasQueuedFailure = true;
237
240
  startLaunch();
238
241
  }
239
242
  if (hasLaunchError) throw launchError;
@@ -259,15 +262,20 @@ var RetryTransport = class {
259
262
  * @since 0.5.0
260
263
  */
261
264
  async [Symbol.asyncDispose]() {
262
- const asyncDisposable = this.wrappedTransport;
263
- const asyncDispose = asyncDisposable[Symbol.asyncDispose];
264
- if (typeof asyncDispose === "function") {
265
- await asyncDispose.call(asyncDisposable);
266
- return;
265
+ const wrappedTransport = Object(this.wrappedTransport);
266
+ const asyncDisposeSymbol = Symbol.asyncDispose;
267
+ if (typeof asyncDisposeSymbol === "symbol") {
268
+ const asyncDispose = wrappedTransport[asyncDisposeSymbol];
269
+ if (typeof asyncDispose === "function") {
270
+ await asyncDispose.call(wrappedTransport);
271
+ return;
272
+ }
273
+ }
274
+ const disposeSymbol = Symbol.dispose;
275
+ if (typeof disposeSymbol === "symbol") {
276
+ const dispose = wrappedTransport[disposeSymbol];
277
+ if (typeof dispose === "function") dispose.call(wrappedTransport);
267
278
  }
268
- const disposable = this.wrappedTransport;
269
- const dispose = disposable[Symbol.dispose];
270
- if (typeof dispose === "function") dispose.call(disposable);
271
279
  }
272
280
  withSuccessMetadata(receipt, attempts) {
273
281
  return {
@@ -310,7 +318,7 @@ var RetryTransport = class {
310
318
  }
311
319
  calculateDelay(attempt, failure) {
312
320
  const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
313
- const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds <= 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
321
+ const cappedRetryAfter = retryAfterMilliseconds == null || !Number.isFinite(retryAfterMilliseconds) || retryAfterMilliseconds < 0 ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
314
322
  if (cappedRetryAfter != null) return cappedRetryAfter;
315
323
  const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
316
324
  if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
@@ -374,7 +382,8 @@ function getRetryAfterMilliseconds(failure) {
374
382
  return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
375
383
  }
376
384
  function toAsyncIterator(values) {
377
- if (Symbol.asyncIterator in values) return values[Symbol.asyncIterator]();
385
+ const asyncIterator = values[Symbol.asyncIterator];
386
+ if (typeof asyncIterator === "function") return asyncIterator.call(values);
378
387
  const iterator = values[Symbol.iterator]();
379
388
  return {
380
389
  async next() {
@@ -389,11 +398,11 @@ function toAsyncIterator(values) {
389
398
  };
390
399
  }
391
400
  function raceWithAbort(promise, signal) {
392
- if (signal.aborted) return Promise.reject(signal.reason);
401
+ if (signal.aborted) return Promise.reject(getAbortReason(signal));
393
402
  return new Promise((resolve, reject) => {
394
403
  const abort = () => {
395
404
  cleanup();
396
- reject(signal.reason);
405
+ reject(getAbortReason(signal));
397
406
  };
398
407
  const cleanup = () => {
399
408
  signal.removeEventListener("abort", abort);
@@ -408,6 +417,9 @@ function raceWithAbort(promise, signal) {
408
417
  });
409
418
  });
410
419
  }
420
+ function getAbortReason(signal) {
421
+ return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
422
+ }
411
423
  function toReceiptError(value) {
412
424
  return isReceiptError(value) ? value : void 0;
413
425
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upyo/retry",
3
- "version": "0.5.0-dev.199",
3
+ "version": "0.5.0-dev.205",
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.199+f10145fc"
57
+ "@upyo/core": "0.5.0-dev.205+0a836319"
58
58
  },
59
59
  "devDependencies": {
60
60
  "tsdown": "^0.12.7",