@agent-cards/checkout 0.15.0 → 0.15.1
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/client.d.ts +8 -1
- package/dist/client.js +51 -18
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -527,8 +527,15 @@ export declare class VaultClient {
|
|
|
527
527
|
* exchange rather than each minting their own token.
|
|
528
528
|
*/
|
|
529
529
|
private accessToken;
|
|
530
|
-
/**
|
|
530
|
+
/**
|
|
531
|
+
* A preparation status read may retry two known connection failures, after
|
|
532
|
+
* 250ms and 500ms, while keeping its original approval deadline and signal.
|
|
533
|
+
* Only fetch and a successful response's body read belong to that retry:
|
|
534
|
+
* OAuth, HTTP errors, invalid JSON and every mutation remain outside it.
|
|
535
|
+
* The existing one-time 401 refresh carries the remaining read budget.
|
|
536
|
+
*/
|
|
531
537
|
private call;
|
|
532
538
|
private post;
|
|
533
539
|
private get;
|
|
540
|
+
private readPreparation;
|
|
534
541
|
}
|
package/dist/client.js
CHANGED
|
@@ -354,6 +354,17 @@ export function redactUrl(raw) {
|
|
|
354
354
|
}
|
|
355
355
|
/** Default backoff for a 502 amount_unverifiable at create: two retries, then give up. */
|
|
356
356
|
const UNVERIFIABLE_RETRY_DELAYS_MS = [500, 1500];
|
|
357
|
+
const PREPARATION_READ_RETRY_DELAYS_MS = [250, 500];
|
|
358
|
+
const TRANSIENT_READ_NETWORK_CODES = new Set([
|
|
359
|
+
'ECONNRESET', 'ECONNREFUSED', 'EPIPE', 'ETIMEDOUT', 'EAI_AGAIN',
|
|
360
|
+
'UND_ERR_SOCKET', 'UND_ERR_CONNECT_TIMEOUT', 'UND_ERR_HEADERS_TIMEOUT', 'UND_ERR_BODY_TIMEOUT',
|
|
361
|
+
]);
|
|
362
|
+
function transientReadNetworkError(error) {
|
|
363
|
+
if (!(error instanceof Error) || error.name === 'AbortError' || error.name === 'TimeoutError' || error instanceof SyntaxError)
|
|
364
|
+
return false;
|
|
365
|
+
const code = error.cause?.code ?? error.code;
|
|
366
|
+
return typeof code === 'string' && TRANSIENT_READ_NETWORK_CODES.has(code);
|
|
367
|
+
}
|
|
357
368
|
export class VaultClient {
|
|
358
369
|
opts;
|
|
359
370
|
baseUrl;
|
|
@@ -460,7 +471,7 @@ export class VaultClient {
|
|
|
460
471
|
}
|
|
461
472
|
catch { /* observer only */ }
|
|
462
473
|
while (!signal.aborted) {
|
|
463
|
-
const state = await this.
|
|
474
|
+
const state = await this.readPreparation(id, signal);
|
|
464
475
|
if (signal.aborted)
|
|
465
476
|
throw fail('cancelled', id);
|
|
466
477
|
if (state?.id !== id)
|
|
@@ -1023,30 +1034,49 @@ export class VaultClient {
|
|
|
1023
1034
|
})().finally(() => { this.inflight = null; });
|
|
1024
1035
|
return this.inflight;
|
|
1025
1036
|
}
|
|
1026
|
-
/**
|
|
1027
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* A preparation status read may retry two known connection failures, after
|
|
1039
|
+
* 250ms and 500ms, while keeping its original approval deadline and signal.
|
|
1040
|
+
* Only fetch and a successful response's body read belong to that retry:
|
|
1041
|
+
* OAuth, HTTP errors, invalid JSON and every mutation remain outside it.
|
|
1042
|
+
* The existing one-time 401 refresh carries the remaining read budget.
|
|
1043
|
+
*/
|
|
1044
|
+
async call(path, init = {}, retried = false, stopNewRequests, preparationReadAttempt) {
|
|
1028
1045
|
const signal = init.signal ?? AbortSignal.timeout(30_000);
|
|
1029
1046
|
const token = await withSignal(this.accessToken(), signal);
|
|
1030
1047
|
// Auth can outlive the merchant request. Stop a create that has not left
|
|
1031
1048
|
// yet, while preserving the response of one already sent for cleanup.
|
|
1032
1049
|
if (stopNewRequests?.aborted)
|
|
1033
1050
|
throw new PaymentOutcomeUnknownError(null, 'merchant_request_aborted');
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1051
|
+
for (;;) {
|
|
1052
|
+
signal.throwIfAborted();
|
|
1053
|
+
let r;
|
|
1054
|
+
try {
|
|
1055
|
+
r = await withSignal(this.fetch(`${this.baseUrl}${path}`, {
|
|
1056
|
+
...init,
|
|
1057
|
+
signal,
|
|
1058
|
+
headers: { ...(init.headers ?? {}), authorization: `Bearer ${token}`, 'content-type': 'application/json' },
|
|
1059
|
+
}), signal);
|
|
1060
|
+
if (r.ok)
|
|
1061
|
+
return await withSignal(r.json(), signal);
|
|
1062
|
+
}
|
|
1063
|
+
catch (error) {
|
|
1064
|
+
const delay = preparationReadAttempt === undefined ? undefined : PREPARATION_READ_RETRY_DELAYS_MS[preparationReadAttempt];
|
|
1065
|
+
if (signal.aborted || preparationReadAttempt === undefined || delay === undefined || !transientReadNetworkError(error))
|
|
1066
|
+
throw error;
|
|
1067
|
+
preparationReadAttempt++;
|
|
1068
|
+
await interruptibleSleep(delay, signal);
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
// A token can be revoked or expire early; one forced refresh, then give up.
|
|
1072
|
+
if (r.status === 401 && !retried) {
|
|
1073
|
+
if (stopNewRequests?.aborted)
|
|
1074
|
+
throw new PaymentOutcomeUnknownError(null, 'merchant_request_aborted');
|
|
1075
|
+
await withSignal(this.accessToken(true), signal);
|
|
1076
|
+
return this.call(path, { ...init, signal }, true, stopNewRequests, preparationReadAttempt);
|
|
1077
|
+
}
|
|
1048
1078
|
throw new CheckoutApiError(r.status, path, await withSignal(r.text(), signal));
|
|
1049
|
-
|
|
1079
|
+
}
|
|
1050
1080
|
}
|
|
1051
1081
|
post(path, body, signal, stopNewRequests) {
|
|
1052
1082
|
return this.call(path, { method: 'POST', body: JSON.stringify(body), signal }, false, stopNewRequests);
|
|
@@ -1054,6 +1084,9 @@ export class VaultClient {
|
|
|
1054
1084
|
get(path, signal) {
|
|
1055
1085
|
return this.call(path, { signal });
|
|
1056
1086
|
}
|
|
1087
|
+
readPreparation(id, signal) {
|
|
1088
|
+
return this.call(`/v2/checkout/preparations/${id}`, { signal }, false, undefined, 0);
|
|
1089
|
+
}
|
|
1057
1090
|
}
|
|
1058
1091
|
function executionMetadata(state, authorizationId, previous = {}) {
|
|
1059
1092
|
if (state.execution_mode === undefined)
|
package/package.json
CHANGED