@getanyapi/sdk 0.9.8 → 0.9.10
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 +47 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +47 -82
- 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
|
}
|
|
@@ -129,10 +131,21 @@ interface ClientOptions {
|
|
|
129
131
|
fetch?: typeof fetch;
|
|
130
132
|
/** Max retry attempts for retryable failures (429 + retry-safe network). Default 2. */
|
|
131
133
|
maxRetries?: number;
|
|
132
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Per-request timeout in milliseconds. Default 300000, matching the gateway's own
|
|
136
|
+
* execution budget: the slowest lane declares a 240s per-attempt ceiling, so a
|
|
137
|
+
* smaller default can abort a run the server was still going to answer.
|
|
138
|
+
*/
|
|
133
139
|
timeoutMs?: number;
|
|
134
140
|
/** Send Idempotency-Key on billed POSTs. Default "auto"; use "off" as a kill switch. */
|
|
135
141
|
idempotency?: "auto" | "off";
|
|
142
|
+
/**
|
|
143
|
+
* Total milliseconds one run() call may block waiting out a 409 `idempotency_in_progress`
|
|
144
|
+
* (the gateway is still executing the run this key claims). Default 60000. Set 0 to
|
|
145
|
+
* surface that 409 immediately. This is a whole-call budget across every in-progress
|
|
146
|
+
* wait, separate from the 8000ms ordinary-backoff ceiling.
|
|
147
|
+
*/
|
|
148
|
+
maxInProgressWaitMs?: number;
|
|
136
149
|
}
|
|
137
150
|
/**
|
|
138
151
|
* Account profile returned by /v1/me (internal-only fields dropped). See SPEC 2.7.
|
|
@@ -168,7 +181,7 @@ interface DiscoveryPricing {
|
|
|
168
181
|
failoverMaxUsd: number;
|
|
169
182
|
}
|
|
170
183
|
interface LaneHealth {
|
|
171
|
-
window:
|
|
184
|
+
window: string;
|
|
172
185
|
uptimePct: number;
|
|
173
186
|
latencyP50Ms: number;
|
|
174
187
|
requests: number;
|
|
@@ -189,6 +202,8 @@ interface CatalogEntry {
|
|
|
189
202
|
lanes: DiscoveryLane[];
|
|
190
203
|
heavy: boolean;
|
|
191
204
|
tryEligible: boolean;
|
|
205
|
+
failover?: boolean;
|
|
206
|
+
excludesCallerDelay?: boolean;
|
|
192
207
|
inputSchema?: Record<string, unknown>;
|
|
193
208
|
outputSchema?: Record<string, unknown>;
|
|
194
209
|
}
|
|
@@ -263,6 +278,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
263
278
|
private readonly maxRetries;
|
|
264
279
|
private readonly timeoutMs;
|
|
265
280
|
private readonly idempotency;
|
|
281
|
+
private readonly maxInProgressWaitMs;
|
|
266
282
|
/**
|
|
267
283
|
* The network seam the generated per-platform namespaces target. The base client IS a
|
|
268
284
|
* ClientCore (it implements `run`), so the generated subclass hands `this._core` to each
|
|
@@ -298,6 +314,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
298
314
|
body?: string;
|
|
299
315
|
timeoutMs: number;
|
|
300
316
|
maxRetries: number;
|
|
317
|
+
maxInProgressWaitMs?: number;
|
|
301
318
|
signal?: AbortSignal;
|
|
302
319
|
idempotencyKey?: string;
|
|
303
320
|
}): 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
|
}
|
|
@@ -129,10 +131,21 @@ interface ClientOptions {
|
|
|
129
131
|
fetch?: typeof fetch;
|
|
130
132
|
/** Max retry attempts for retryable failures (429 + retry-safe network). Default 2. */
|
|
131
133
|
maxRetries?: number;
|
|
132
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Per-request timeout in milliseconds. Default 300000, matching the gateway's own
|
|
136
|
+
* execution budget: the slowest lane declares a 240s per-attempt ceiling, so a
|
|
137
|
+
* smaller default can abort a run the server was still going to answer.
|
|
138
|
+
*/
|
|
133
139
|
timeoutMs?: number;
|
|
134
140
|
/** Send Idempotency-Key on billed POSTs. Default "auto"; use "off" as a kill switch. */
|
|
135
141
|
idempotency?: "auto" | "off";
|
|
142
|
+
/**
|
|
143
|
+
* Total milliseconds one run() call may block waiting out a 409 `idempotency_in_progress`
|
|
144
|
+
* (the gateway is still executing the run this key claims). Default 60000. Set 0 to
|
|
145
|
+
* surface that 409 immediately. This is a whole-call budget across every in-progress
|
|
146
|
+
* wait, separate from the 8000ms ordinary-backoff ceiling.
|
|
147
|
+
*/
|
|
148
|
+
maxInProgressWaitMs?: number;
|
|
136
149
|
}
|
|
137
150
|
/**
|
|
138
151
|
* Account profile returned by /v1/me (internal-only fields dropped). See SPEC 2.7.
|
|
@@ -168,7 +181,7 @@ interface DiscoveryPricing {
|
|
|
168
181
|
failoverMaxUsd: number;
|
|
169
182
|
}
|
|
170
183
|
interface LaneHealth {
|
|
171
|
-
window:
|
|
184
|
+
window: string;
|
|
172
185
|
uptimePct: number;
|
|
173
186
|
latencyP50Ms: number;
|
|
174
187
|
requests: number;
|
|
@@ -189,6 +202,8 @@ interface CatalogEntry {
|
|
|
189
202
|
lanes: DiscoveryLane[];
|
|
190
203
|
heavy: boolean;
|
|
191
204
|
tryEligible: boolean;
|
|
205
|
+
failover?: boolean;
|
|
206
|
+
excludesCallerDelay?: boolean;
|
|
192
207
|
inputSchema?: Record<string, unknown>;
|
|
193
208
|
outputSchema?: Record<string, unknown>;
|
|
194
209
|
}
|
|
@@ -263,6 +278,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
263
278
|
private readonly maxRetries;
|
|
264
279
|
private readonly timeoutMs;
|
|
265
280
|
private readonly idempotency;
|
|
281
|
+
private readonly maxInProgressWaitMs;
|
|
266
282
|
/**
|
|
267
283
|
* The network seam the generated per-platform namespaces target. The base client IS a
|
|
268
284
|
* ClientCore (it implements `run`), so the generated subclass hands `this._core` to each
|
|
@@ -298,6 +314,7 @@ declare class AnyAPI$1 implements ClientCore {
|
|
|
298
314
|
body?: string;
|
|
299
315
|
timeoutMs: number;
|
|
300
316
|
maxRetries: number;
|
|
317
|
+
maxInProgressWaitMs?: number;
|
|
301
318
|
signal?: AbortSignal;
|
|
302
319
|
idempotencyKey?: string;
|
|
303
320
|
}): 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")
|
|
@@ -446,10 +394,12 @@ async function agentSignup(options = {}) {
|
|
|
446
394
|
|
|
447
395
|
// src/core/client.ts
|
|
448
396
|
var DEFAULT_BASE_URL2 = "https://api.getanyapi.com";
|
|
449
|
-
var DEFAULT_TIMEOUT_MS =
|
|
397
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
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
|
}
|