@upyo/retry 0.5.0-dev.0 → 0.5.0-dev.193

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
@@ -74,7 +74,7 @@ async function defaultWait(context, signal) {
74
74
  const abort = () => {
75
75
  clearTimeout(timeout);
76
76
  cleanup();
77
- reject(createAbortError());
77
+ reject(signal?.reason ?? createAbortError());
78
78
  };
79
79
  if (signal?.aborted) {
80
80
  abort();
@@ -153,7 +153,7 @@ var RetryTransport = class {
153
153
  attempt,
154
154
  nextAttempt: attempt + 1,
155
155
  maxAttempts: this.config.maxAttempts,
156
- delayMilliseconds: this.calculateDelay(attempt),
156
+ delayMilliseconds: this.calculateDelay(attempt, toReceiptError(error)),
157
157
  error,
158
158
  reason: "retry"
159
159
  }, options?.signal);
@@ -178,17 +178,36 @@ var RetryTransport = class {
178
178
  let inputDone = false;
179
179
  let nextLaunchIndex = 0;
180
180
  let nextYieldIndex = 0;
181
+ let launchPromise;
182
+ let launchError;
183
+ let hasLaunchError = false;
184
+ let pullingInput = false;
185
+ let closed = false;
186
+ const controller = new AbortController();
187
+ const combinedSignal = (0, __upyo_core.combineSignals)(controller.signal, options?.signal);
188
+ const sendOptions = {
189
+ ...options,
190
+ signal: combinedSignal.signal
191
+ };
181
192
  const launchNext = async () => {
182
193
  if (inputDone) return;
183
- options?.signal?.throwIfAborted();
184
- const next = await iterator.next();
194
+ combinedSignal.signal.throwIfAborted();
195
+ pullingInput = true;
196
+ let next;
197
+ try {
198
+ next = await iterator.next();
199
+ } finally {
200
+ pullingInput = false;
201
+ }
202
+ if (closed) return;
185
203
  if (next.done) {
186
204
  inputDone = true;
187
205
  return;
188
206
  }
189
207
  const index = nextLaunchIndex++;
190
- if (index > 0) await this.waitBetweenSendMany(options?.signal);
191
- const promise = this.send(next.value, options).then((receipt) => ({
208
+ if (index > 0) await this.waitBetweenSendMany(combinedSignal.signal);
209
+ if (closed) return;
210
+ const promise = this.send(next.value, sendOptions).then((receipt) => ({
192
211
  index,
193
212
  successful: true,
194
213
  receipt
@@ -199,12 +218,19 @@ var RetryTransport = class {
199
218
  }));
200
219
  inFlight.set(index, promise);
201
220
  };
202
- const launchAvailable = async () => {
203
- while (!inputDone && inFlight.size < this.config.sendMany.maxConcurrent) await launchNext();
221
+ const startLaunch = () => {
222
+ if (launchPromise != null || inputDone || inFlight.size >= this.config.sendMany.maxConcurrent) return;
223
+ launchPromise = launchNext().catch((error) => {
224
+ launchError = error;
225
+ hasLaunchError = true;
226
+ }).finally(() => {
227
+ launchPromise = void 0;
228
+ });
204
229
  };
205
230
  try {
206
- await launchAvailable();
207
- while (inFlight.size > 0 || completed.has(nextYieldIndex)) {
231
+ startLaunch();
232
+ while (inFlight.size > 0 || completed.has(nextYieldIndex) || launchPromise != null || !inputDone) {
233
+ if (hasLaunchError) throw launchError;
208
234
  while (completed.has(nextYieldIndex)) {
209
235
  const result$1 = completed.get(nextYieldIndex);
210
236
  completed.delete(nextYieldIndex);
@@ -212,16 +238,33 @@ var RetryTransport = class {
212
238
  if (!result$1.successful) throw result$1.error;
213
239
  yield result$1.receipt;
214
240
  nextYieldIndex++;
215
- await launchAvailable();
241
+ startLaunch();
216
242
  }
217
- if (inFlight.size <= 0) break;
218
- const result = await Promise.race(inFlight.values());
243
+ startLaunch();
244
+ if (inFlight.size <= 0 && launchPromise == null) break;
245
+ const launch = launchPromise?.then(() => ({ launched: true }));
246
+ const result = await Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]);
247
+ if ("launched" in result) continue;
219
248
  inFlight.delete(result.index);
220
249
  completed.set(result.index, result);
221
- if (result.index !== nextYieldIndex) await launchAvailable();
250
+ startLaunch();
222
251
  }
252
+ if (hasLaunchError) throw launchError;
223
253
  } finally {
224
- if (!inputDone) await iterator.return?.();
254
+ closed = true;
255
+ controller.abort(new DOMException("The operation was aborted.", "AbortError"));
256
+ launchPromise?.catch(() => {});
257
+ try {
258
+ const closeIterator = async () => {
259
+ if (!inputDone) await iterator.return?.();
260
+ };
261
+ if (pullingInput) launchPromise?.finally(() => {
262
+ closeIterator().catch(() => {});
263
+ });
264
+ else await closeIterator();
265
+ } finally {
266
+ combinedSignal.cleanup();
267
+ }
225
268
  }
226
269
  }
227
270
  /**
@@ -256,32 +299,47 @@ var RetryTransport = class {
256
299
  };
257
300
  }
258
301
  shouldRetryReceipt(receipt) {
259
- if (this.config.shouldRetry != null) return this.config.shouldRetry(receipt);
302
+ const shouldRetry = this.config.shouldRetry;
303
+ if (shouldRetry != null) return shouldRetry({
304
+ kind: "receipt",
305
+ receipt
306
+ });
260
307
  if (receipt.retryable != null) return receipt.retryable;
261
308
  return this.hasRetryableError(receipt.errors);
262
309
  }
263
310
  shouldRetryError(error) {
264
- if (this.config.shouldRetry != null) return this.config.shouldRetry(error);
311
+ const receiptError = toReceiptError(error);
312
+ const shouldRetry = this.config.shouldRetry;
313
+ if (shouldRetry != null) return shouldRetry({
314
+ kind: "error",
315
+ error,
316
+ receiptError
317
+ });
318
+ if (receiptError != null) return receiptError.retryable;
319
+ if (error instanceof Error && error.name === "AbortError") return true;
265
320
  return (0, __upyo_core.classifyReceiptError)(error).retryable;
266
321
  }
267
322
  hasRetryableError(errors) {
268
323
  return errors?.some((error) => error.retryable) ?? false;
269
324
  }
270
- calculateDelay(attempt, receipt) {
271
- const retryAfterMilliseconds = getRetryAfterMilliseconds(receipt);
325
+ calculateDelay(attempt, failure) {
326
+ const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
272
327
  const cappedRetryAfter = retryAfterMilliseconds == null ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
273
328
  if (cappedRetryAfter != null) return cappedRetryAfter;
274
329
  const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
275
330
  if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
276
- return Math.floor(this.config.random() * computedDelay);
331
+ const random = this.config.random;
332
+ return Math.floor(random() * computedDelay);
277
333
  }
278
334
  waitBeforeRetry(context, signal) {
279
- return this.config.wait(context, signal);
335
+ const wait = this.config.wait;
336
+ return wait(context, signal);
280
337
  }
281
338
  waitBetweenSendMany(signal) {
282
339
  const delayMilliseconds = this.config.sendMany.intervalMilliseconds;
283
340
  if (delayMilliseconds <= 0) return Promise.resolve();
284
- return this.config.wait({
341
+ const wait = this.config.wait;
342
+ return wait({
285
343
  attempt: 0,
286
344
  nextAttempt: 0,
287
345
  maxAttempts: this.config.maxAttempts,
@@ -290,6 +348,11 @@ var RetryTransport = class {
290
348
  }, signal);
291
349
  }
292
350
  createThrownFailure(error, attempts) {
351
+ const receiptError = toReceiptError(error);
352
+ if (receiptError != null) return (0, __upyo_core.createFailedReceipt)(receiptError, {
353
+ provider: receiptError.provider ?? this.id,
354
+ attempts
355
+ });
293
356
  const message = error instanceof Error ? error.message : String(error);
294
357
  const classification = (0, __upyo_core.classifyReceiptError)(error);
295
358
  return (0, __upyo_core.createFailedReceipt)((0, __upyo_core.createReceiptError)(message, {
@@ -315,13 +378,20 @@ var RetryTransport = class {
315
378
  function createRetryTransport(baseTransport, config = {}) {
316
379
  return new RetryTransport(baseTransport, config);
317
380
  }
318
- function getRetryAfterMilliseconds(receipt) {
319
- const receiptDelay = receipt?.errors?.map((error) => error.retryAfterMilliseconds).find((delay) => delay != null);
320
- return receiptDelay;
381
+ function getRetryAfterMilliseconds(failure) {
382
+ if (failure == null) return void 0;
383
+ if (isReceiptError(failure)) return failure.retryAfterMilliseconds;
384
+ return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
321
385
  }
322
386
  async function* toAsyncIterator(values) {
323
387
  for await (const value of values) yield value;
324
388
  }
389
+ function toReceiptError(value) {
390
+ return isReceiptError(value) ? value : void 0;
391
+ }
392
+ function isReceiptError(value) {
393
+ return typeof value === "object" && value != null && typeof value.message === "string" && typeof value.code === "string" && typeof value.category === "string" && typeof value.retryable === "boolean";
394
+ }
325
395
 
326
396
  //#endregion
327
397
  exports.RetryTransport = RetryTransport;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Message, Receipt, Transport, TransportOptions } from "@upyo/core";
1
+ import { Message, Receipt, ReceiptError, Transport, TransportOptions } from "@upyo/core";
2
2
 
3
3
  //#region src/config.d.ts
4
4
 
@@ -80,16 +80,29 @@ interface DelayContext<TProviderId extends string = string> {
80
80
  * @since 0.5.0
81
81
  */
82
82
  type WaitFunction<TProviderId extends string = string> = (context: DelayContext<TProviderId>, signal?: AbortSignal) => Promise<void>;
83
+ /**
84
+ * Failure passed to a custom retry classifier.
85
+ *
86
+ * @since 0.5.0
87
+ */
88
+ type RetryFailure<TProviderId extends string = string> = {
89
+ readonly kind: "receipt";
90
+ readonly receipt: Receipt<TProviderId> & {
91
+ readonly successful: false;
92
+ };
93
+ } | {
94
+ readonly kind: "error";
95
+ readonly error: unknown;
96
+ readonly receiptError?: ReceiptError<TProviderId>;
97
+ };
83
98
  /**
84
99
  * Function that decides whether a failure should be retried.
85
100
  *
86
- * @param failure Failed receipt or thrown error.
101
+ * @param failure Failed receipt or thrown error metadata.
87
102
  * @returns Whether another attempt should be made.
88
103
  * @since 0.5.0
89
104
  */
90
- type RetryClassifier<TProviderId extends string = string> = (failure: (Receipt<TProviderId> & {
91
- readonly successful: false;
92
- }) | unknown) => boolean;
105
+ type RetryClassifier<TProviderId extends string = string> = (failure: RetryFailure<TProviderId>) => boolean;
93
106
  /**
94
107
  * Retry behavior for `sendMany()`.
95
108
  *
@@ -243,4 +256,4 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
243
256
  */
244
257
  declare function createRetryTransport<TProviderId extends string = string>(baseTransport: Transport<TProviderId>, config?: RetryConfig<TProviderId>): RetryTransport<TProviderId>;
245
258
  //#endregion
246
- export { BackoffConfig, DelayContext, JitterConfig, RetryClassifier, RetryConfig, RetryTransport, SendManyRetryConfig, WaitFunction, createRetryTransport };
259
+ export { BackoffConfig, DelayContext, JitterConfig, RetryClassifier, RetryConfig, RetryFailure, RetryTransport, SendManyRetryConfig, WaitFunction, createRetryTransport };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Message, Receipt, Transport, TransportOptions } from "@upyo/core";
1
+ import { Message, Receipt, ReceiptError, Transport, TransportOptions } from "@upyo/core";
2
2
 
3
3
  //#region src/config.d.ts
4
4
 
@@ -80,16 +80,29 @@ interface DelayContext<TProviderId extends string = string> {
80
80
  * @since 0.5.0
81
81
  */
82
82
  type WaitFunction<TProviderId extends string = string> = (context: DelayContext<TProviderId>, signal?: AbortSignal) => Promise<void>;
83
+ /**
84
+ * Failure passed to a custom retry classifier.
85
+ *
86
+ * @since 0.5.0
87
+ */
88
+ type RetryFailure<TProviderId extends string = string> = {
89
+ readonly kind: "receipt";
90
+ readonly receipt: Receipt<TProviderId> & {
91
+ readonly successful: false;
92
+ };
93
+ } | {
94
+ readonly kind: "error";
95
+ readonly error: unknown;
96
+ readonly receiptError?: ReceiptError<TProviderId>;
97
+ };
83
98
  /**
84
99
  * Function that decides whether a failure should be retried.
85
100
  *
86
- * @param failure Failed receipt or thrown error.
101
+ * @param failure Failed receipt or thrown error metadata.
87
102
  * @returns Whether another attempt should be made.
88
103
  * @since 0.5.0
89
104
  */
90
- type RetryClassifier<TProviderId extends string = string> = (failure: (Receipt<TProviderId> & {
91
- readonly successful: false;
92
- }) | unknown) => boolean;
105
+ type RetryClassifier<TProviderId extends string = string> = (failure: RetryFailure<TProviderId>) => boolean;
93
106
  /**
94
107
  * Retry behavior for `sendMany()`.
95
108
  *
@@ -243,4 +256,4 @@ declare class RetryTransport<TProviderId extends string = string> implements Tra
243
256
  */
244
257
  declare function createRetryTransport<TProviderId extends string = string>(baseTransport: Transport<TProviderId>, config?: RetryConfig<TProviderId>): RetryTransport<TProviderId>;
245
258
  //#endregion
246
- export { BackoffConfig, DelayContext, JitterConfig, RetryClassifier, RetryConfig, RetryTransport, SendManyRetryConfig, WaitFunction, createRetryTransport };
259
+ export { BackoffConfig, DelayContext, JitterConfig, RetryClassifier, RetryConfig, RetryFailure, RetryTransport, SendManyRetryConfig, WaitFunction, createRetryTransport };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { classifyReceiptError, createFailedReceipt, createReceiptError } from "@upyo/core";
1
+ import { classifyReceiptError, combineSignals, createFailedReceipt, createReceiptError } from "@upyo/core";
2
2
 
3
3
  //#region src/config.ts
4
4
  /**
@@ -51,7 +51,7 @@ async function defaultWait(context, signal) {
51
51
  const abort = () => {
52
52
  clearTimeout(timeout);
53
53
  cleanup();
54
- reject(createAbortError());
54
+ reject(signal?.reason ?? createAbortError());
55
55
  };
56
56
  if (signal?.aborted) {
57
57
  abort();
@@ -130,7 +130,7 @@ var RetryTransport = class {
130
130
  attempt,
131
131
  nextAttempt: attempt + 1,
132
132
  maxAttempts: this.config.maxAttempts,
133
- delayMilliseconds: this.calculateDelay(attempt),
133
+ delayMilliseconds: this.calculateDelay(attempt, toReceiptError(error)),
134
134
  error,
135
135
  reason: "retry"
136
136
  }, options?.signal);
@@ -155,17 +155,36 @@ var RetryTransport = class {
155
155
  let inputDone = false;
156
156
  let nextLaunchIndex = 0;
157
157
  let nextYieldIndex = 0;
158
+ let launchPromise;
159
+ let launchError;
160
+ let hasLaunchError = false;
161
+ let pullingInput = false;
162
+ let closed = false;
163
+ const controller = new AbortController();
164
+ const combinedSignal = combineSignals(controller.signal, options?.signal);
165
+ const sendOptions = {
166
+ ...options,
167
+ signal: combinedSignal.signal
168
+ };
158
169
  const launchNext = async () => {
159
170
  if (inputDone) return;
160
- options?.signal?.throwIfAborted();
161
- const next = await iterator.next();
171
+ combinedSignal.signal.throwIfAborted();
172
+ pullingInput = true;
173
+ let next;
174
+ try {
175
+ next = await iterator.next();
176
+ } finally {
177
+ pullingInput = false;
178
+ }
179
+ if (closed) return;
162
180
  if (next.done) {
163
181
  inputDone = true;
164
182
  return;
165
183
  }
166
184
  const index = nextLaunchIndex++;
167
- if (index > 0) await this.waitBetweenSendMany(options?.signal);
168
- const promise = this.send(next.value, options).then((receipt) => ({
185
+ if (index > 0) await this.waitBetweenSendMany(combinedSignal.signal);
186
+ if (closed) return;
187
+ const promise = this.send(next.value, sendOptions).then((receipt) => ({
169
188
  index,
170
189
  successful: true,
171
190
  receipt
@@ -176,12 +195,19 @@ var RetryTransport = class {
176
195
  }));
177
196
  inFlight.set(index, promise);
178
197
  };
179
- const launchAvailable = async () => {
180
- while (!inputDone && inFlight.size < this.config.sendMany.maxConcurrent) await launchNext();
198
+ const startLaunch = () => {
199
+ if (launchPromise != null || inputDone || inFlight.size >= this.config.sendMany.maxConcurrent) return;
200
+ launchPromise = launchNext().catch((error) => {
201
+ launchError = error;
202
+ hasLaunchError = true;
203
+ }).finally(() => {
204
+ launchPromise = void 0;
205
+ });
181
206
  };
182
207
  try {
183
- await launchAvailable();
184
- while (inFlight.size > 0 || completed.has(nextYieldIndex)) {
208
+ startLaunch();
209
+ while (inFlight.size > 0 || completed.has(nextYieldIndex) || launchPromise != null || !inputDone) {
210
+ if (hasLaunchError) throw launchError;
185
211
  while (completed.has(nextYieldIndex)) {
186
212
  const result$1 = completed.get(nextYieldIndex);
187
213
  completed.delete(nextYieldIndex);
@@ -189,16 +215,33 @@ var RetryTransport = class {
189
215
  if (!result$1.successful) throw result$1.error;
190
216
  yield result$1.receipt;
191
217
  nextYieldIndex++;
192
- await launchAvailable();
218
+ startLaunch();
193
219
  }
194
- if (inFlight.size <= 0) break;
195
- const result = await Promise.race(inFlight.values());
220
+ startLaunch();
221
+ if (inFlight.size <= 0 && launchPromise == null) break;
222
+ const launch = launchPromise?.then(() => ({ launched: true }));
223
+ const result = await Promise.race([...inFlight.values(), ...launch == null ? [] : [launch]]);
224
+ if ("launched" in result) continue;
196
225
  inFlight.delete(result.index);
197
226
  completed.set(result.index, result);
198
- if (result.index !== nextYieldIndex) await launchAvailable();
227
+ startLaunch();
199
228
  }
229
+ if (hasLaunchError) throw launchError;
200
230
  } finally {
201
- if (!inputDone) await iterator.return?.();
231
+ closed = true;
232
+ controller.abort(new DOMException("The operation was aborted.", "AbortError"));
233
+ launchPromise?.catch(() => {});
234
+ try {
235
+ const closeIterator = async () => {
236
+ if (!inputDone) await iterator.return?.();
237
+ };
238
+ if (pullingInput) launchPromise?.finally(() => {
239
+ closeIterator().catch(() => {});
240
+ });
241
+ else await closeIterator();
242
+ } finally {
243
+ combinedSignal.cleanup();
244
+ }
202
245
  }
203
246
  }
204
247
  /**
@@ -233,32 +276,47 @@ var RetryTransport = class {
233
276
  };
234
277
  }
235
278
  shouldRetryReceipt(receipt) {
236
- if (this.config.shouldRetry != null) return this.config.shouldRetry(receipt);
279
+ const shouldRetry = this.config.shouldRetry;
280
+ if (shouldRetry != null) return shouldRetry({
281
+ kind: "receipt",
282
+ receipt
283
+ });
237
284
  if (receipt.retryable != null) return receipt.retryable;
238
285
  return this.hasRetryableError(receipt.errors);
239
286
  }
240
287
  shouldRetryError(error) {
241
- if (this.config.shouldRetry != null) return this.config.shouldRetry(error);
288
+ const receiptError = toReceiptError(error);
289
+ const shouldRetry = this.config.shouldRetry;
290
+ if (shouldRetry != null) return shouldRetry({
291
+ kind: "error",
292
+ error,
293
+ receiptError
294
+ });
295
+ if (receiptError != null) return receiptError.retryable;
296
+ if (error instanceof Error && error.name === "AbortError") return true;
242
297
  return classifyReceiptError(error).retryable;
243
298
  }
244
299
  hasRetryableError(errors) {
245
300
  return errors?.some((error) => error.retryable) ?? false;
246
301
  }
247
- calculateDelay(attempt, receipt) {
248
- const retryAfterMilliseconds = getRetryAfterMilliseconds(receipt);
302
+ calculateDelay(attempt, failure) {
303
+ const retryAfterMilliseconds = getRetryAfterMilliseconds(failure);
249
304
  const cappedRetryAfter = retryAfterMilliseconds == null ? void 0 : Math.min(retryAfterMilliseconds, this.config.backoff.maxDelayMilliseconds);
250
305
  if (cappedRetryAfter != null) return cappedRetryAfter;
251
306
  const computedDelay = Math.min(this.config.backoff.baseDelayMilliseconds * Math.pow(this.config.backoff.factor, attempt - 1), this.config.backoff.maxDelayMilliseconds);
252
307
  if (this.config.jitter === false || this.config.jitter === "none") return computedDelay;
253
- return Math.floor(this.config.random() * computedDelay);
308
+ const random = this.config.random;
309
+ return Math.floor(random() * computedDelay);
254
310
  }
255
311
  waitBeforeRetry(context, signal) {
256
- return this.config.wait(context, signal);
312
+ const wait = this.config.wait;
313
+ return wait(context, signal);
257
314
  }
258
315
  waitBetweenSendMany(signal) {
259
316
  const delayMilliseconds = this.config.sendMany.intervalMilliseconds;
260
317
  if (delayMilliseconds <= 0) return Promise.resolve();
261
- return this.config.wait({
318
+ const wait = this.config.wait;
319
+ return wait({
262
320
  attempt: 0,
263
321
  nextAttempt: 0,
264
322
  maxAttempts: this.config.maxAttempts,
@@ -267,6 +325,11 @@ var RetryTransport = class {
267
325
  }, signal);
268
326
  }
269
327
  createThrownFailure(error, attempts) {
328
+ const receiptError = toReceiptError(error);
329
+ if (receiptError != null) return createFailedReceipt(receiptError, {
330
+ provider: receiptError.provider ?? this.id,
331
+ attempts
332
+ });
270
333
  const message = error instanceof Error ? error.message : String(error);
271
334
  const classification = classifyReceiptError(error);
272
335
  return createFailedReceipt(createReceiptError(message, {
@@ -292,13 +355,20 @@ var RetryTransport = class {
292
355
  function createRetryTransport(baseTransport, config = {}) {
293
356
  return new RetryTransport(baseTransport, config);
294
357
  }
295
- function getRetryAfterMilliseconds(receipt) {
296
- const receiptDelay = receipt?.errors?.map((error) => error.retryAfterMilliseconds).find((delay) => delay != null);
297
- return receiptDelay;
358
+ function getRetryAfterMilliseconds(failure) {
359
+ if (failure == null) return void 0;
360
+ if (isReceiptError(failure)) return failure.retryAfterMilliseconds;
361
+ return failure.errors?.find((error) => error.retryAfterMilliseconds != null)?.retryAfterMilliseconds;
298
362
  }
299
363
  async function* toAsyncIterator(values) {
300
364
  for await (const value of values) yield value;
301
365
  }
366
+ function toReceiptError(value) {
367
+ return isReceiptError(value) ? value : void 0;
368
+ }
369
+ function isReceiptError(value) {
370
+ return typeof value === "object" && value != null && typeof value.message === "string" && typeof value.code === "string" && typeof value.category === "string" && typeof value.retryable === "boolean";
371
+ }
302
372
 
303
373
  //#endregion
304
374
  export { RetryTransport, createRetryTransport };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upyo/retry",
3
- "version": "0.5.0-dev.0",
3
+ "version": "0.5.0-dev.193",
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"
57
+ "@upyo/core": "0.5.0-dev.193+eb1e84b9"
58
58
  },
59
59
  "devDependencies": {
60
60
  "tsdown": "^0.12.7",