@getanyapi/sdk 0.9.8 → 0.9.9
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/README.md +31 -8
- package/dist/index.cjs +46 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +46 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -114,6 +114,8 @@ interface RequestOptions {
|
|
|
114
114
|
signal?: AbortSignal;
|
|
115
115
|
/** Override the client maxRetries for this call. */
|
|
116
116
|
maxRetries?: number;
|
|
117
|
+
/** Override the client maxInProgressWaitMs for this call. */
|
|
118
|
+
maxInProgressWaitMs?: number;
|
|
117
119
|
/** Override the generated Idempotency-Key for this billed POST. */
|
|
118
120
|
idempotencyKey?: string;
|
|
119
121
|
}
|
|
@@ -133,6 +135,13 @@ interface ClientOptions {
|
|
|
133
135
|
timeoutMs?: number;
|
|
134
136
|
/** Send Idempotency-Key on billed POSTs. Default "auto"; use "off" as a kill switch. */
|
|
135
137
|
idempotency?: "auto" | "off";
|
|
138
|
+
/**
|
|
139
|
+
* Total milliseconds one run() call may block waiting out a 409 `idempotency_in_progress`
|
|
140
|
+
* (the gateway is still executing the run this key claims). Default 60000. Set 0 to
|
|
141
|
+
* surface that 409 immediately. This is a whole-call budget across every in-progress
|
|
142
|
+
* wait, separate from the 8000ms ordinary-backoff ceiling.
|
|
143
|
+
*/
|
|
144
|
+
maxInProgressWaitMs?: number;
|
|
136
145
|
}
|
|
137
146
|
/**
|
|
138
147
|
* Account profile returned by /v1/me (internal-only fields dropped). See SPEC 2.7.
|
|
@@ -168,7 +177,7 @@ interface DiscoveryPricing {
|
|
|
168
177
|
failoverMaxUsd: number;
|
|
169
178
|
}
|
|
170
179
|
interface LaneHealth {
|
|
171
|
-
window:
|
|
180
|
+
window: string;
|
|
172
181
|
uptimePct: number;
|
|
173
182
|
latencyP50Ms: number;
|
|
174
183
|
requests: number;
|
|
@@ -189,6 +198,8 @@ interface CatalogEntry {
|
|
|
189
198
|
lanes: DiscoveryLane[];
|
|
190
199
|
heavy: boolean;
|
|
191
200
|
tryEligible: boolean;
|
|
201
|
+
failover?: boolean;
|
|
202
|
+
excludesCallerDelay?: boolean;
|
|
192
203
|
inputSchema?: Record<string, unknown>;
|
|
193
204
|
outputSchema?: Record<string, unknown>;
|
|
194
205
|
}
|
|
@@ -263,6 +274,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
263
274
|
private readonly maxRetries;
|
|
264
275
|
private readonly timeoutMs;
|
|
265
276
|
private readonly idempotency;
|
|
277
|
+
private readonly maxInProgressWaitMs;
|
|
266
278
|
/**
|
|
267
279
|
* The network seam the generated per-platform namespaces target. The base client IS a
|
|
268
280
|
* ClientCore (it implements `run`), so the generated subclass hands `this._core` to each
|
|
@@ -298,6 +310,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
298
310
|
body?: string;
|
|
299
311
|
timeoutMs: number;
|
|
300
312
|
maxRetries: number;
|
|
313
|
+
maxInProgressWaitMs?: number;
|
|
301
314
|
signal?: AbortSignal;
|
|
302
315
|
idempotencyKey?: string;
|
|
303
316
|
}): Promise<T>;
|
package/dist/index.d.ts
CHANGED
|
@@ -114,6 +114,8 @@ interface RequestOptions {
|
|
|
114
114
|
signal?: AbortSignal;
|
|
115
115
|
/** Override the client maxRetries for this call. */
|
|
116
116
|
maxRetries?: number;
|
|
117
|
+
/** Override the client maxInProgressWaitMs for this call. */
|
|
118
|
+
maxInProgressWaitMs?: number;
|
|
117
119
|
/** Override the generated Idempotency-Key for this billed POST. */
|
|
118
120
|
idempotencyKey?: string;
|
|
119
121
|
}
|
|
@@ -133,6 +135,13 @@ interface ClientOptions {
|
|
|
133
135
|
timeoutMs?: number;
|
|
134
136
|
/** Send Idempotency-Key on billed POSTs. Default "auto"; use "off" as a kill switch. */
|
|
135
137
|
idempotency?: "auto" | "off";
|
|
138
|
+
/**
|
|
139
|
+
* Total milliseconds one run() call may block waiting out a 409 `idempotency_in_progress`
|
|
140
|
+
* (the gateway is still executing the run this key claims). Default 60000. Set 0 to
|
|
141
|
+
* surface that 409 immediately. This is a whole-call budget across every in-progress
|
|
142
|
+
* wait, separate from the 8000ms ordinary-backoff ceiling.
|
|
143
|
+
*/
|
|
144
|
+
maxInProgressWaitMs?: number;
|
|
136
145
|
}
|
|
137
146
|
/**
|
|
138
147
|
* Account profile returned by /v1/me (internal-only fields dropped). See SPEC 2.7.
|
|
@@ -168,7 +177,7 @@ interface DiscoveryPricing {
|
|
|
168
177
|
failoverMaxUsd: number;
|
|
169
178
|
}
|
|
170
179
|
interface LaneHealth {
|
|
171
|
-
window:
|
|
180
|
+
window: string;
|
|
172
181
|
uptimePct: number;
|
|
173
182
|
latencyP50Ms: number;
|
|
174
183
|
requests: number;
|
|
@@ -189,6 +198,8 @@ interface CatalogEntry {
|
|
|
189
198
|
lanes: DiscoveryLane[];
|
|
190
199
|
heavy: boolean;
|
|
191
200
|
tryEligible: boolean;
|
|
201
|
+
failover?: boolean;
|
|
202
|
+
excludesCallerDelay?: boolean;
|
|
192
203
|
inputSchema?: Record<string, unknown>;
|
|
193
204
|
outputSchema?: Record<string, unknown>;
|
|
194
205
|
}
|
|
@@ -263,6 +274,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
263
274
|
private readonly maxRetries;
|
|
264
275
|
private readonly timeoutMs;
|
|
265
276
|
private readonly idempotency;
|
|
277
|
+
private readonly maxInProgressWaitMs;
|
|
266
278
|
/**
|
|
267
279
|
* The network seam the generated per-platform namespaces target. The base client IS a
|
|
268
280
|
* ClientCore (it implements `run`), so the generated subclass hands `this._core` to each
|
|
@@ -298,6 +310,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
298
310
|
body?: string;
|
|
299
311
|
timeoutMs: number;
|
|
300
312
|
maxRetries: number;
|
|
313
|
+
maxInProgressWaitMs?: number;
|
|
301
314
|
signal?: AbortSignal;
|
|
302
315
|
idempotencyKey?: string;
|
|
303
316
|
}): Promise<T>;
|
package/dist/index.js
CHANGED
|
@@ -119,17 +119,20 @@ var DEFAULT_BASE_URL = "https://api.getanyapi.com";
|
|
|
119
119
|
function malformed(path) {
|
|
120
120
|
throw new AnyAPIError(`malformed discovery response: ${path}`, 0);
|
|
121
121
|
}
|
|
122
|
-
function
|
|
122
|
+
function rejectUnsafeDiscoveryFields(value, path) {
|
|
123
123
|
if (Array.isArray(value)) {
|
|
124
124
|
value.forEach(
|
|
125
|
-
(item, index) =>
|
|
125
|
+
(item, index) => rejectUnsafeDiscoveryFields(item, `${path}[${index}]`)
|
|
126
126
|
);
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
129
|
if (typeof value !== "object" || value === null) return;
|
|
130
130
|
for (const [key, item] of Object.entries(value)) {
|
|
131
131
|
if (key.toLowerCase().includes("credit")) malformed(`${path}.${key}`);
|
|
132
|
-
|
|
132
|
+
if (key === "provider" && item !== "AnyAPI") {
|
|
133
|
+
malformed(`${path}.${key}`);
|
|
134
|
+
}
|
|
135
|
+
rejectUnsafeDiscoveryFields(item, `${path}.${key}`);
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
138
|
function record(value, path) {
|
|
@@ -138,12 +141,6 @@ function record(value, path) {
|
|
|
138
141
|
}
|
|
139
142
|
return value;
|
|
140
143
|
}
|
|
141
|
-
function exactKeys(raw, allowed, path) {
|
|
142
|
-
const keys = new Set(allowed);
|
|
143
|
-
for (const key of Object.keys(raw)) {
|
|
144
|
-
if (!keys.has(key)) malformed(`${path}.${key}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
144
|
function stringField(raw, key, path) {
|
|
148
145
|
const value = raw[key];
|
|
149
146
|
if (typeof value !== "string") return malformed(`${path}.${key}`);
|
|
@@ -174,14 +171,12 @@ function parseOffer(value, path) {
|
|
|
174
171
|
const unit = stringField(raw, "unit", path);
|
|
175
172
|
const maxUsd = numberField(raw, "maxUsd", path);
|
|
176
173
|
if (model === "flat") {
|
|
177
|
-
|
|
178
|
-
if (unit !== "request" || "baseUsd" in raw || "perUnitUsd" in raw) {
|
|
174
|
+
if (unit !== "request") {
|
|
179
175
|
return malformed(path);
|
|
180
176
|
}
|
|
181
177
|
return { model, unit, maxUsd };
|
|
182
178
|
}
|
|
183
179
|
if (model === "linear") {
|
|
184
|
-
exactKeys(raw, ["model", "unit", "baseUsd", "perUnitUsd", "maxUsd"], path);
|
|
185
180
|
if (unit.length === 0) return malformed(`${path}.unit`);
|
|
186
181
|
return {
|
|
187
182
|
model,
|
|
@@ -195,7 +190,6 @@ function parseOffer(value, path) {
|
|
|
195
190
|
}
|
|
196
191
|
function parsePricing(value, path) {
|
|
197
192
|
const raw = record(value, path);
|
|
198
|
-
exactKeys(raw, ["from", "failoverMaxUsd"], path);
|
|
199
193
|
return {
|
|
200
194
|
from: parseOffer(raw["from"], `${path}.from`),
|
|
201
195
|
failoverMaxUsd: numberField(raw, "failoverMaxUsd", path)
|
|
@@ -203,10 +197,8 @@ function parsePricing(value, path) {
|
|
|
203
197
|
}
|
|
204
198
|
function parseHealth(value, path) {
|
|
205
199
|
const raw = record(value, path);
|
|
206
|
-
exactKeys(raw, ["window", "uptimePct", "latencyP50Ms", "requests"], path);
|
|
207
|
-
if (raw["window"] !== "30d") return malformed(`${path}.window`);
|
|
208
200
|
return {
|
|
209
|
-
window: "
|
|
201
|
+
window: stringField(raw, "window", path),
|
|
210
202
|
uptimePct: boundedNumberField(raw, "uptimePct", path, void 0, 100),
|
|
211
203
|
latencyP50Ms: integerField(raw, "latencyP50Ms", path),
|
|
212
204
|
requests: integerField(raw, "requests", path)
|
|
@@ -214,7 +206,6 @@ function parseHealth(value, path) {
|
|
|
214
206
|
}
|
|
215
207
|
function parseLane(value, path) {
|
|
216
208
|
const raw = record(value, path);
|
|
217
|
-
exactKeys(raw, ["pricing", "health"], path);
|
|
218
209
|
const lane = {
|
|
219
210
|
pricing: parseOffer(raw["pricing"], `${path}.pricing`)
|
|
220
211
|
};
|
|
@@ -232,7 +223,6 @@ function parseSchema(value, path) {
|
|
|
232
223
|
}
|
|
233
224
|
function parseHighlight(value, path) {
|
|
234
225
|
const raw = record(value, path);
|
|
235
|
-
exactKeys(raw, ["path", "type", "why"], path);
|
|
236
226
|
const field = {
|
|
237
227
|
path: stringField(raw, "path", path),
|
|
238
228
|
type: stringField(raw, "type", path)
|
|
@@ -253,28 +243,10 @@ function mapProfile(raw) {
|
|
|
253
243
|
return profile;
|
|
254
244
|
}
|
|
255
245
|
function mapCatalogEntry(raw) {
|
|
256
|
-
|
|
246
|
+
rejectUnsafeDiscoveryFields(raw, "api");
|
|
257
247
|
const value = record(raw, "api");
|
|
258
|
-
exactKeys(
|
|
259
|
-
value,
|
|
260
|
-
[
|
|
261
|
-
"id",
|
|
262
|
-
"slug",
|
|
263
|
-
"category",
|
|
264
|
-
"name",
|
|
265
|
-
"description",
|
|
266
|
-
"provider",
|
|
267
|
-
"pricing",
|
|
268
|
-
"lanes",
|
|
269
|
-
"heavy",
|
|
270
|
-
"tryEligible",
|
|
271
|
-
"inputSchema",
|
|
272
|
-
"outputSchema"
|
|
273
|
-
],
|
|
274
|
-
"api"
|
|
275
|
-
);
|
|
276
248
|
const lanesRaw = value["lanes"];
|
|
277
|
-
if (!Array.isArray(lanesRaw)
|
|
249
|
+
if (!Array.isArray(lanesRaw)) {
|
|
278
250
|
return malformed("api.lanes");
|
|
279
251
|
}
|
|
280
252
|
const entry = {
|
|
@@ -296,32 +268,24 @@ function mapCatalogEntry(raw) {
|
|
|
296
268
|
}
|
|
297
269
|
if (typeof value["tryEligible"] !== "boolean")
|
|
298
270
|
return malformed("api.tryEligible");
|
|
271
|
+
if (value["failover"] !== void 0) {
|
|
272
|
+
if (typeof value["failover"] !== "boolean")
|
|
273
|
+
return malformed("api.failover");
|
|
274
|
+
entry.failover = value["failover"];
|
|
275
|
+
}
|
|
276
|
+
if (value["excludesCallerDelay"] !== void 0) {
|
|
277
|
+
if (typeof value["excludesCallerDelay"] !== "boolean")
|
|
278
|
+
return malformed("api.excludesCallerDelay");
|
|
279
|
+
entry.excludesCallerDelay = value["excludesCallerDelay"];
|
|
280
|
+
}
|
|
299
281
|
if (value["inputSchema"] !== void 0) {
|
|
300
282
|
entry.inputSchema = parseSchema(value["inputSchema"], "api.inputSchema");
|
|
301
283
|
}
|
|
302
284
|
if (value["outputSchema"] !== void 0) {
|
|
303
285
|
entry.outputSchema = parseSchema(value["outputSchema"], "api.outputSchema");
|
|
304
286
|
}
|
|
305
|
-
if (!offersEqual(entry.pricing.from, entry.lanes[0].pricing)) {
|
|
306
|
-
return malformed("api.pricing.from");
|
|
307
|
-
}
|
|
308
|
-
const failoverMaxUsd = Math.max(
|
|
309
|
-
...entry.lanes.map((lane) => lane.pricing.maxUsd)
|
|
310
|
-
);
|
|
311
|
-
if (entry.pricing.failoverMaxUsd !== failoverMaxUsd) {
|
|
312
|
-
return malformed("api.pricing.failoverMaxUsd");
|
|
313
|
-
}
|
|
314
287
|
return entry;
|
|
315
288
|
}
|
|
316
|
-
function offersEqual(left, right) {
|
|
317
|
-
if (left.model !== right.model || left.unit !== right.unit || left.maxUsd !== right.maxUsd) {
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
if (left.model === "flat" || right.model === "flat") {
|
|
321
|
-
return left.model === right.model;
|
|
322
|
-
}
|
|
323
|
-
return left.baseUsd === right.baseUsd && left.perUnitUsd === right.perUnitUsd;
|
|
324
|
-
}
|
|
325
289
|
function mapCatalogDetail(raw) {
|
|
326
290
|
const entry = mapCatalogEntry(raw);
|
|
327
291
|
if (entry.inputSchema === void 0) return malformed("api.inputSchema");
|
|
@@ -329,28 +293,13 @@ function mapCatalogDetail(raw) {
|
|
|
329
293
|
return entry;
|
|
330
294
|
}
|
|
331
295
|
function mapCatalogList(raw) {
|
|
296
|
+
rejectUnsafeDiscoveryFields(raw, "catalog");
|
|
332
297
|
const envelope = record(raw, "catalog");
|
|
333
|
-
exactKeys(envelope, ["apis"], "catalog");
|
|
334
298
|
if (!Array.isArray(envelope["apis"])) return malformed("catalog.apis");
|
|
335
299
|
return envelope["apis"].map(mapCatalogEntry);
|
|
336
300
|
}
|
|
337
301
|
function mapSearchResult(value, path) {
|
|
338
302
|
const raw = record(value, path);
|
|
339
|
-
exactKeys(
|
|
340
|
-
raw,
|
|
341
|
-
[
|
|
342
|
-
"slug",
|
|
343
|
-
"platformId",
|
|
344
|
-
"name",
|
|
345
|
-
"description",
|
|
346
|
-
"category",
|
|
347
|
-
"provider",
|
|
348
|
-
"pricing",
|
|
349
|
-
"relevance",
|
|
350
|
-
"highlightFields"
|
|
351
|
-
],
|
|
352
|
-
path
|
|
353
|
-
);
|
|
354
303
|
const result = {
|
|
355
304
|
slug: stringField(raw, "slug", path),
|
|
356
305
|
platformId: stringField(raw, "platformId", path),
|
|
@@ -371,9 +320,8 @@ function mapSearchResult(value, path) {
|
|
|
371
320
|
return result;
|
|
372
321
|
}
|
|
373
322
|
function mapCatalogSearch(raw) {
|
|
374
|
-
|
|
323
|
+
rejectUnsafeDiscoveryFields(raw, "search");
|
|
375
324
|
const envelope = record(raw, "search");
|
|
376
|
-
exactKeys(envelope, ["results", "total", "ranking"], "search");
|
|
377
325
|
if (!Array.isArray(envelope["results"])) return malformed("search.results");
|
|
378
326
|
const ranking = envelope["ranking"];
|
|
379
327
|
if (ranking !== "semantic" && ranking !== "keyword")
|
|
@@ -450,6 +398,8 @@ var DEFAULT_TIMEOUT_MS = 6e4;
|
|
|
450
398
|
var DEFAULT_MAX_RETRIES = 2;
|
|
451
399
|
var RETRY_BASE_DELAY_MS = 500;
|
|
452
400
|
var RETRY_MAX_DELAY_MS = 8e3;
|
|
401
|
+
var DEFAULT_MAX_IN_PROGRESS_WAIT_MS = 6e4;
|
|
402
|
+
var IDEMPOTENCY_IN_PROGRESS_CODE = "idempotency_in_progress";
|
|
453
403
|
var PRE_SEND_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
454
404
|
"EADDRNOTAVAIL",
|
|
455
405
|
"EAI_AGAIN",
|
|
@@ -493,7 +443,7 @@ function backoffDelay(attempt) {
|
|
|
493
443
|
const factor = 0.5 + Math.random();
|
|
494
444
|
return base * factor;
|
|
495
445
|
}
|
|
496
|
-
function
|
|
446
|
+
function parseRetryAfterMs(header) {
|
|
497
447
|
if (header === null) {
|
|
498
448
|
return void 0;
|
|
499
449
|
}
|
|
@@ -503,13 +453,11 @@ function parseRetryAfter(header) {
|
|
|
503
453
|
}
|
|
504
454
|
const seconds = Number(trimmed);
|
|
505
455
|
if (Number.isFinite(seconds)) {
|
|
506
|
-
|
|
507
|
-
return Math.min(Math.max(ms, 0), RETRY_MAX_DELAY_MS);
|
|
456
|
+
return Math.max(seconds * 1e3, 0);
|
|
508
457
|
}
|
|
509
458
|
const dateMs = Date.parse(trimmed);
|
|
510
459
|
if (Number.isFinite(dateMs)) {
|
|
511
|
-
|
|
512
|
-
return Math.min(Math.max(delta, 0), RETRY_MAX_DELAY_MS);
|
|
460
|
+
return Math.max(dateMs - Date.now(), 0);
|
|
513
461
|
}
|
|
514
462
|
return void 0;
|
|
515
463
|
}
|
|
@@ -614,6 +562,7 @@ var AnyAPI = class {
|
|
|
614
562
|
maxRetries;
|
|
615
563
|
timeoutMs;
|
|
616
564
|
idempotency;
|
|
565
|
+
maxInProgressWaitMs;
|
|
617
566
|
/**
|
|
618
567
|
* The network seam the generated per-platform namespaces target. The base client IS a
|
|
619
568
|
* ClientCore (it implements `run`), so the generated subclass hands `this._core` to each
|
|
@@ -636,6 +585,7 @@ var AnyAPI = class {
|
|
|
636
585
|
this.fetchImpl = resolvedFetch;
|
|
637
586
|
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
638
587
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
588
|
+
this.maxInProgressWaitMs = options.maxInProgressWaitMs ?? DEFAULT_MAX_IN_PROGRESS_WAIT_MS;
|
|
639
589
|
const idempotency = options.idempotency ?? "auto";
|
|
640
590
|
if (idempotency !== "auto" && idempotency !== "off") {
|
|
641
591
|
throw new TypeError('idempotency must be "auto" or "off"');
|
|
@@ -656,6 +606,7 @@ var AnyAPI = class {
|
|
|
656
606
|
body,
|
|
657
607
|
timeoutMs: options?.timeoutMs ?? this.timeoutMs,
|
|
658
608
|
maxRetries: options?.maxRetries ?? this.maxRetries,
|
|
609
|
+
maxInProgressWaitMs: options?.maxInProgressWaitMs ?? this.maxInProgressWaitMs,
|
|
659
610
|
...options?.idempotencyKey !== void 0 ? { idempotencyKey: options.idempotencyKey } : {},
|
|
660
611
|
...options?.signal ? { signal: options.signal } : {}
|
|
661
612
|
}
|
|
@@ -728,6 +679,11 @@ var AnyAPI = class {
|
|
|
728
679
|
headers["Idempotency-Key"] = key;
|
|
729
680
|
}
|
|
730
681
|
let attempt = 0;
|
|
682
|
+
let inProgressWaitedMs = 0;
|
|
683
|
+
const inProgressBudgetMs = Math.max(
|
|
684
|
+
opts.maxInProgressWaitMs ?? DEFAULT_MAX_IN_PROGRESS_WAIT_MS,
|
|
685
|
+
0
|
|
686
|
+
);
|
|
731
687
|
for (; ; ) {
|
|
732
688
|
const { signal, timeoutSignal } = composeSignal(
|
|
733
689
|
opts.timeoutMs,
|
|
@@ -776,13 +732,22 @@ var AnyAPI = class {
|
|
|
776
732
|
}
|
|
777
733
|
const body = await response.text().catch(() => "");
|
|
778
734
|
const { message, code } = messageFromBody(body, response.status);
|
|
735
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
779
736
|
if (response.status === 429 && attempt < opts.maxRetries) {
|
|
780
|
-
const
|
|
781
|
-
const delay = retryAfter ?? backoffDelay(attempt);
|
|
737
|
+
const delay = retryAfterMs !== void 0 ? Math.min(retryAfterMs, RETRY_MAX_DELAY_MS) : backoffDelay(attempt);
|
|
782
738
|
await sleep(delay, opts.signal);
|
|
783
739
|
attempt += 1;
|
|
784
740
|
continue;
|
|
785
741
|
}
|
|
742
|
+
if (billedPost && response.status === 409 && code === IDEMPOTENCY_IN_PROGRESS_CODE && attempt < opts.maxRetries) {
|
|
743
|
+
const delay = retryAfterMs ?? backoffDelay(attempt);
|
|
744
|
+
if (inProgressWaitedMs + delay <= inProgressBudgetMs) {
|
|
745
|
+
await sleep(delay, opts.signal);
|
|
746
|
+
inProgressWaitedMs += delay;
|
|
747
|
+
attempt += 1;
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
786
751
|
throw errorFromStatus(response.status, message, requestId, code);
|
|
787
752
|
}
|
|
788
753
|
}
|