uvd-x402-sdk 2.74.0 → 2.76.0
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 +145 -1
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.d.ts +3 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/backend/index.d.mts +350 -54
- package/dist/backend/index.d.ts +350 -54
- package/dist/backend/index.js +488 -253
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +477 -254
- package/dist/backend/index.mjs.map +1 -1
- package/dist/erc8128/index.d.mts +1 -1
- package/dist/erc8128/index.d.ts +1 -1
- package/dist/{index-BkeMrSHP.d.mts → index-CiRbsqXe.d.mts} +2 -2
- package/dist/{index-BQ45e-Xa.d.ts → index-DTXTOEby.d.ts} +2 -2
- package/dist/{index-DeJMYEKC.d.mts → index-ZH10otHE.d.mts} +1 -1
- package/dist/{index-DeJMYEKC.d.ts → index-ZH10otHE.d.ts} +1 -1
- package/dist/index.d.mts +50 -10
- package/dist/index.d.ts +50 -10
- package/dist/index.js +238 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +228 -40
- package/dist/index.mjs.map +1 -1
- package/dist/{ows-Z9v4GxOZ.d.mts → ows-CYIVd4xO.d.mts} +1 -1
- package/dist/{ows-C-KmORG9.d.ts → ows-DTDixPzO.d.ts} +1 -1
- package/dist/providers/algorand/index.d.mts +1 -1
- package/dist/providers/algorand/index.d.ts +1 -1
- package/dist/providers/algorand/index.js +2 -0
- package/dist/providers/algorand/index.js.map +1 -1
- package/dist/providers/algorand/index.mjs +2 -0
- package/dist/providers/algorand/index.mjs.map +1 -1
- package/dist/providers/evm/index.d.mts +1 -1
- package/dist/providers/evm/index.d.ts +1 -1
- package/dist/providers/evm/index.js.map +1 -1
- package/dist/providers/evm/index.mjs.map +1 -1
- package/dist/providers/near/index.d.mts +1 -1
- package/dist/providers/near/index.d.ts +1 -1
- package/dist/providers/near/index.js +2 -0
- package/dist/providers/near/index.js.map +1 -1
- package/dist/providers/near/index.mjs +2 -0
- package/dist/providers/near/index.mjs.map +1 -1
- package/dist/providers/solana/index.d.mts +1 -1
- package/dist/providers/solana/index.d.ts +1 -1
- package/dist/providers/solana/index.js +2 -0
- package/dist/providers/solana/index.js.map +1 -1
- package/dist/providers/solana/index.mjs +2 -0
- package/dist/providers/solana/index.mjs.map +1 -1
- package/dist/providers/stellar/index.d.mts +1 -1
- package/dist/providers/stellar/index.d.ts +1 -1
- package/dist/providers/stellar/index.js +2 -0
- package/dist/providers/stellar/index.js.map +1 -1
- package/dist/providers/stellar/index.mjs +2 -0
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/providers/sui/index.d.mts +1 -1
- package/dist/providers/sui/index.d.ts +1 -1
- package/dist/providers/sui/index.js +2 -0
- package/dist/providers/sui/index.js.map +1 -1
- package/dist/providers/sui/index.mjs +2 -0
- package/dist/providers/sui/index.mjs.map +1 -1
- package/dist/providers/xrpl/index.d.mts +1 -1
- package/dist/providers/xrpl/index.d.ts +1 -1
- package/dist/providers/xrpl/index.js +2 -0
- package/dist/providers/xrpl/index.js.map +1 -1
- package/dist/providers/xrpl/index.mjs +2 -0
- package/dist/providers/xrpl/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs.map +1 -1
- package/dist/utils/index.d.mts +31 -260
- package/dist/utils/index.d.ts +31 -260
- package/dist/utils/index.js +17 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +16 -1
- package/dist/utils/index.mjs.map +1 -1
- package/dist/validation-De3bessL.d.mts +273 -0
- package/dist/validation-DsbfDAtV.d.ts +273 -0
- package/dist/{wallet-w7BnImDG.d.mts → wallet-0cX9Pw2F.d.mts} +1 -1
- package/dist/{wallet-w7BnImDG.d.ts → wallet-0cX9Pw2F.d.ts} +1 -1
- package/package.json +1 -1
- package/src/backend/facilitator-error.ts +355 -0
- package/src/backend/index.ts +536 -263
- package/src/dx402.ts +123 -8
- package/src/index.ts +17 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/personal-sign.ts +54 -0
package/dist/backend/index.mjs
CHANGED
|
@@ -1091,6 +1091,118 @@ function decodeX402Header(encoded) {
|
|
|
1091
1091
|
var REVIEW_WINDOW_SEC = 7 * 24 * 3600;
|
|
1092
1092
|
var REFUND_WINDOW_SEC = 7 * 24 * 3600;
|
|
1093
1093
|
|
|
1094
|
+
// src/backend/facilitator-error.ts
|
|
1095
|
+
var WRITER_LEASE_REASONS = [
|
|
1096
|
+
"holder_unknown",
|
|
1097
|
+
"forwarding_disabled",
|
|
1098
|
+
"forwarded_but_not_writer",
|
|
1099
|
+
"body_unreadable",
|
|
1100
|
+
"forward_failed"
|
|
1101
|
+
];
|
|
1102
|
+
var REPLAYABLE_LEASE_REASONS = [
|
|
1103
|
+
"holder_unknown",
|
|
1104
|
+
"forwarding_disabled",
|
|
1105
|
+
"forwarded_but_not_writer",
|
|
1106
|
+
"body_unreadable"
|
|
1107
|
+
];
|
|
1108
|
+
var AMBIGUOUS_LEASE_REASONS = ["forward_failed"];
|
|
1109
|
+
var MAX_RETRY_AFTER_SECONDS = 15;
|
|
1110
|
+
var DEFAULT_RETRY_AFTER_SECONDS = 5;
|
|
1111
|
+
var DEFAULT_FACILITATOR_RETRIES = 2;
|
|
1112
|
+
function isReplayableLeaseReason(reason) {
|
|
1113
|
+
return REPLAYABLE_LEASE_REASONS.includes(reason);
|
|
1114
|
+
}
|
|
1115
|
+
function isAmbiguousLeaseReason(reason) {
|
|
1116
|
+
return AMBIGUOUS_LEASE_REASONS.includes(reason);
|
|
1117
|
+
}
|
|
1118
|
+
function parseRetryAfterSeconds(response) {
|
|
1119
|
+
let raw;
|
|
1120
|
+
try {
|
|
1121
|
+
raw = response?.headers?.get?.("retry-after");
|
|
1122
|
+
} catch {
|
|
1123
|
+
return void 0;
|
|
1124
|
+
}
|
|
1125
|
+
if (raw === null || raw === void 0 || raw === "") return void 0;
|
|
1126
|
+
const seconds = Number(raw);
|
|
1127
|
+
if (!Number.isFinite(seconds) || seconds < 0) return void 0;
|
|
1128
|
+
return Math.min(seconds, MAX_RETRY_AFTER_SECONDS);
|
|
1129
|
+
}
|
|
1130
|
+
function reasonFrom(body) {
|
|
1131
|
+
try {
|
|
1132
|
+
const parsed = JSON.parse(body);
|
|
1133
|
+
if (parsed && typeof parsed === "object" && typeof parsed.reason === "string") {
|
|
1134
|
+
return parsed.reason;
|
|
1135
|
+
}
|
|
1136
|
+
} catch {
|
|
1137
|
+
}
|
|
1138
|
+
return void 0;
|
|
1139
|
+
}
|
|
1140
|
+
async function readFacilitatorError(response) {
|
|
1141
|
+
let body = "";
|
|
1142
|
+
try {
|
|
1143
|
+
body = await response.text();
|
|
1144
|
+
} catch {
|
|
1145
|
+
body = "";
|
|
1146
|
+
}
|
|
1147
|
+
const status = response.status;
|
|
1148
|
+
const reason = reasonFrom(body);
|
|
1149
|
+
const retryable = status === 429 || status === 502 || status === 503 || status === 504;
|
|
1150
|
+
const retryAfterSeconds = retryable ? parseRetryAfterSeconds(response) ?? DEFAULT_RETRY_AFTER_SECONDS : void 0;
|
|
1151
|
+
const safeToReplay = status === 429 || status === 503 && isReplayableLeaseReason(reason);
|
|
1152
|
+
return {
|
|
1153
|
+
error: `Facilitator error: ${status} - ${body}`,
|
|
1154
|
+
status,
|
|
1155
|
+
reason,
|
|
1156
|
+
retryAfterSeconds,
|
|
1157
|
+
retryable,
|
|
1158
|
+
safeToReplay,
|
|
1159
|
+
body
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
function failureFields(info) {
|
|
1163
|
+
return {
|
|
1164
|
+
status: info.status,
|
|
1165
|
+
retryable: info.retryable,
|
|
1166
|
+
safeToReplay: info.safeToReplay,
|
|
1167
|
+
...info.reason !== void 0 ? { reason: info.reason } : {},
|
|
1168
|
+
...info.retryAfterSeconds !== void 0 ? { retryAfterSeconds: info.retryAfterSeconds } : {}
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function carryFailureFields(source) {
|
|
1172
|
+
return {
|
|
1173
|
+
...source.status !== void 0 ? { status: source.status } : {},
|
|
1174
|
+
...source.reason !== void 0 ? { reason: source.reason } : {},
|
|
1175
|
+
...source.retryable !== void 0 ? { retryable: source.retryable } : {},
|
|
1176
|
+
...source.retryAfterSeconds !== void 0 ? { retryAfterSeconds: source.retryAfterSeconds } : {},
|
|
1177
|
+
...source.safeToReplay !== void 0 ? { safeToReplay: source.safeToReplay } : {}
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1181
|
+
async function facilitatorFetch(url, init, options) {
|
|
1182
|
+
const retries = options.retries ?? DEFAULT_FACILITATOR_RETRIES;
|
|
1183
|
+
const canReplay = options.canReplay ?? ((info) => info.safeToReplay);
|
|
1184
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
1185
|
+
const sleep = options.sleepImpl ?? defaultSleep;
|
|
1186
|
+
let attempt = 0;
|
|
1187
|
+
for (; ; ) {
|
|
1188
|
+
const controller = new AbortController();
|
|
1189
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
1190
|
+
let response;
|
|
1191
|
+
try {
|
|
1192
|
+
response = await doFetch(url, { ...init, signal: controller.signal });
|
|
1193
|
+
} finally {
|
|
1194
|
+
clearTimeout(timeoutId);
|
|
1195
|
+
}
|
|
1196
|
+
if (response.ok) return { response };
|
|
1197
|
+
const error = await readFacilitatorError(response);
|
|
1198
|
+
if (attempt >= retries || !error.retryable || !canReplay(error)) {
|
|
1199
|
+
return { response, error };
|
|
1200
|
+
}
|
|
1201
|
+
attempt += 1;
|
|
1202
|
+
await sleep((error.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS) * 1e3);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1094
1206
|
// src/backend/index.ts
|
|
1095
1207
|
function parsePaymentHeader(headerValue) {
|
|
1096
1208
|
if (!headerValue) {
|
|
@@ -1197,10 +1309,12 @@ var FacilitatorClient = class {
|
|
|
1197
1309
|
baseUrl;
|
|
1198
1310
|
timeout;
|
|
1199
1311
|
explicitTimeout;
|
|
1312
|
+
retries;
|
|
1200
1313
|
constructor(options = {}) {
|
|
1201
1314
|
this.baseUrl = options.baseUrl || "https://facilitator.ultravioletadao.xyz";
|
|
1202
1315
|
this.explicitTimeout = options.timeout !== void 0;
|
|
1203
1316
|
this.timeout = options.timeout || 3e4;
|
|
1317
|
+
this.retries = options.retries;
|
|
1204
1318
|
}
|
|
1205
1319
|
/**
|
|
1206
1320
|
* Get timeout for a specific network, using per-chain defaults when no explicit timeout was set.
|
|
@@ -1227,29 +1341,31 @@ var FacilitatorClient = class {
|
|
|
1227
1341
|
*/
|
|
1228
1342
|
async verify(paymentHeader, requirements) {
|
|
1229
1343
|
const body = buildVerifyRequest(paymentHeader, requirements);
|
|
1230
|
-
const controller = new AbortController();
|
|
1231
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
1232
1344
|
try {
|
|
1233
|
-
const response = await
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1345
|
+
const { response, error } = await facilitatorFetch(
|
|
1346
|
+
`${this.baseUrl}/verify`,
|
|
1347
|
+
{
|
|
1348
|
+
method: "POST",
|
|
1349
|
+
headers: { "Content-Type": "application/json" },
|
|
1350
|
+
body: JSON.stringify(body)
|
|
1351
|
+
},
|
|
1352
|
+
{ timeoutMs: this.timeout, retries: this.retries }
|
|
1353
|
+
);
|
|
1354
|
+
if (error) {
|
|
1242
1355
|
return {
|
|
1243
1356
|
isValid: false,
|
|
1244
|
-
invalidReason:
|
|
1357
|
+
invalidReason: error.error,
|
|
1358
|
+
...failureFields(error)
|
|
1245
1359
|
};
|
|
1246
1360
|
}
|
|
1247
1361
|
return await response.json();
|
|
1248
1362
|
} catch (error) {
|
|
1249
|
-
clearTimeout(timeoutId);
|
|
1250
1363
|
return {
|
|
1251
1364
|
isValid: false,
|
|
1252
|
-
invalidReason: error instanceof Error ? error.message : "Unknown error"
|
|
1365
|
+
invalidReason: error instanceof Error ? error.message : "Unknown error",
|
|
1366
|
+
retryable: true,
|
|
1367
|
+
safeToReplay: false,
|
|
1368
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
1253
1369
|
};
|
|
1254
1370
|
}
|
|
1255
1371
|
}
|
|
@@ -1265,21 +1381,21 @@ var FacilitatorClient = class {
|
|
|
1265
1381
|
async settle(paymentHeader, requirements) {
|
|
1266
1382
|
const body = buildSettleRequest(paymentHeader, requirements);
|
|
1267
1383
|
const settleTimeout = this.getTimeout(requirements.network);
|
|
1268
|
-
const controller = new AbortController();
|
|
1269
|
-
const timeoutId = setTimeout(() => controller.abort(), settleTimeout);
|
|
1270
1384
|
try {
|
|
1271
|
-
const response = await
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1385
|
+
const { response, error } = await facilitatorFetch(
|
|
1386
|
+
`${this.baseUrl}/settle`,
|
|
1387
|
+
{
|
|
1388
|
+
method: "POST",
|
|
1389
|
+
headers: { "Content-Type": "application/json" },
|
|
1390
|
+
body: JSON.stringify(body)
|
|
1391
|
+
},
|
|
1392
|
+
{ timeoutMs: settleTimeout, retries: this.retries }
|
|
1393
|
+
);
|
|
1394
|
+
if (error) {
|
|
1280
1395
|
return {
|
|
1281
1396
|
success: false,
|
|
1282
|
-
error:
|
|
1397
|
+
error: error.error,
|
|
1398
|
+
...failureFields(error)
|
|
1283
1399
|
};
|
|
1284
1400
|
}
|
|
1285
1401
|
const result = await response.json();
|
|
@@ -1320,10 +1436,12 @@ var FacilitatorClient = class {
|
|
|
1320
1436
|
payer: result.payer
|
|
1321
1437
|
};
|
|
1322
1438
|
} catch (error) {
|
|
1323
|
-
clearTimeout(timeoutId);
|
|
1324
1439
|
return {
|
|
1325
1440
|
success: false,
|
|
1326
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1441
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
1442
|
+
retryable: true,
|
|
1443
|
+
safeToReplay: false,
|
|
1444
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
1327
1445
|
};
|
|
1328
1446
|
}
|
|
1329
1447
|
}
|
|
@@ -1343,7 +1461,8 @@ var FacilitatorClient = class {
|
|
|
1343
1461
|
return {
|
|
1344
1462
|
verified: false,
|
|
1345
1463
|
settled: false,
|
|
1346
|
-
error: verifyResult.invalidReason
|
|
1464
|
+
error: verifyResult.invalidReason,
|
|
1465
|
+
...carryFailureFields(verifyResult)
|
|
1347
1466
|
};
|
|
1348
1467
|
}
|
|
1349
1468
|
const settleResult = await this.settle(paymentHeader, requirements);
|
|
@@ -1351,7 +1470,8 @@ var FacilitatorClient = class {
|
|
|
1351
1470
|
verified: true,
|
|
1352
1471
|
settled: settleResult.success,
|
|
1353
1472
|
transactionHash: settleResult.transactionHash,
|
|
1354
|
-
error: settleResult.error
|
|
1473
|
+
error: settleResult.error,
|
|
1474
|
+
...carryFailureFields(settleResult)
|
|
1355
1475
|
};
|
|
1356
1476
|
}
|
|
1357
1477
|
/**
|
|
@@ -1753,10 +1873,29 @@ function createVerifiedPaymentState(client, payment, requirements, verifyResult)
|
|
|
1753
1873
|
}
|
|
1754
1874
|
};
|
|
1755
1875
|
}
|
|
1876
|
+
function respondUnavailable(res, message, failure) {
|
|
1877
|
+
const seconds = Math.max(1, Math.ceil(failure.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS));
|
|
1878
|
+
const body = {
|
|
1879
|
+
error: message,
|
|
1880
|
+
reason: failure.reason ?? failure.invalidReason ?? failure.error,
|
|
1881
|
+
retryable: true,
|
|
1882
|
+
retryAfterSeconds: seconds,
|
|
1883
|
+
// False for `forward_failed` and for a bare timeout: the write may already
|
|
1884
|
+
// have landed, so the caller must reconcile before resending.
|
|
1885
|
+
safeToReplay: failure.safeToReplay === true
|
|
1886
|
+
};
|
|
1887
|
+
const staged = res.status(503);
|
|
1888
|
+
if (typeof staged.set === "function") {
|
|
1889
|
+
staged.set({ "Retry-After": String(seconds) }).json(body);
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
staged.json(body);
|
|
1893
|
+
}
|
|
1756
1894
|
function createPaymentMiddleware(getRequirements, options = {}) {
|
|
1757
1895
|
const client = new FacilitatorClient({
|
|
1758
1896
|
baseUrl: options.facilitatorUrl || options.baseUrl,
|
|
1759
|
-
timeout: options.timeout
|
|
1897
|
+
timeout: options.timeout,
|
|
1898
|
+
retries: options.retries
|
|
1760
1899
|
});
|
|
1761
1900
|
const settlementStrategy = options.settlementStrategy || "before-handler";
|
|
1762
1901
|
return async (req, res, next) => {
|
|
@@ -1771,6 +1910,10 @@ function createPaymentMiddleware(getRequirements, options = {}) {
|
|
|
1771
1910
|
const requirements = buildPaymentRequirements(reqOptions);
|
|
1772
1911
|
const verifyResult = await client.verify(payment, requirements);
|
|
1773
1912
|
if (!verifyResult.isValid) {
|
|
1913
|
+
if (verifyResult.retryable) {
|
|
1914
|
+
respondUnavailable(res, "Payment verification unavailable", verifyResult);
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1774
1917
|
res.status(402).json({
|
|
1775
1918
|
error: "Payment verification failed",
|
|
1776
1919
|
reason: verifyResult.invalidReason
|
|
@@ -1781,6 +1924,10 @@ function createPaymentMiddleware(getRequirements, options = {}) {
|
|
|
1781
1924
|
if (settlementStrategy === "before-handler") {
|
|
1782
1925
|
const settleResult = await req.x402.settle();
|
|
1783
1926
|
if (!settleResult.success) {
|
|
1927
|
+
if (settleResult.retryable) {
|
|
1928
|
+
respondUnavailable(res, "Payment settlement unavailable", settleResult);
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1784
1931
|
res.status(500).json({
|
|
1785
1932
|
error: "Payment settlement failed",
|
|
1786
1933
|
reason: settleResult.error || "Unknown settlement error"
|
|
@@ -1791,10 +1938,25 @@ function createPaymentMiddleware(getRequirements, options = {}) {
|
|
|
1791
1938
|
next();
|
|
1792
1939
|
};
|
|
1793
1940
|
}
|
|
1941
|
+
function honoUnavailable(c, message, failure) {
|
|
1942
|
+
const seconds = Math.max(1, Math.ceil(failure.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS));
|
|
1943
|
+
c.header?.("Retry-After", String(seconds));
|
|
1944
|
+
return c.json(
|
|
1945
|
+
{
|
|
1946
|
+
error: message,
|
|
1947
|
+
reason: failure.reason ?? failure.invalidReason ?? failure.error,
|
|
1948
|
+
retryable: true,
|
|
1949
|
+
retryAfterSeconds: seconds,
|
|
1950
|
+
safeToReplay: failure.safeToReplay === true
|
|
1951
|
+
},
|
|
1952
|
+
503
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1794
1955
|
function createHonoMiddleware(options) {
|
|
1795
1956
|
const client = new FacilitatorClient({
|
|
1796
1957
|
baseUrl: options.facilitatorUrl || options.baseUrl,
|
|
1797
|
-
timeout: options.timeout
|
|
1958
|
+
timeout: options.timeout,
|
|
1959
|
+
retries: options.retries
|
|
1798
1960
|
});
|
|
1799
1961
|
const settlementStrategy = options.settlementStrategy || "before-handler";
|
|
1800
1962
|
if (!options.accepts[0]) {
|
|
@@ -1834,6 +1996,9 @@ function createHonoMiddleware(options) {
|
|
|
1834
1996
|
}
|
|
1835
1997
|
const verifyResult = await client.verify(parsed, requirement);
|
|
1836
1998
|
if (!verifyResult.isValid) {
|
|
1999
|
+
if (verifyResult.retryable) {
|
|
2000
|
+
return honoUnavailable(c, "Payment verification unavailable", verifyResult);
|
|
2001
|
+
}
|
|
1837
2002
|
return c.json({
|
|
1838
2003
|
error: "Payment verification failed",
|
|
1839
2004
|
reason: verifyResult.invalidReason
|
|
@@ -1844,6 +2009,9 @@ function createHonoMiddleware(options) {
|
|
|
1844
2009
|
if (settlementStrategy === "before-handler") {
|
|
1845
2010
|
const settleResult = await verifiedPayment.settle();
|
|
1846
2011
|
if (!settleResult.success) {
|
|
2012
|
+
if (settleResult.retryable) {
|
|
2013
|
+
return honoUnavailable(c, "Payment settlement unavailable", settleResult);
|
|
2014
|
+
}
|
|
1847
2015
|
return c.json({
|
|
1848
2016
|
error: "Payment settlement failed",
|
|
1849
2017
|
reason: settleResult.error || "Unknown error"
|
|
@@ -2625,19 +2793,65 @@ var Erc8004LookupError = class extends Error {
|
|
|
2625
2793
|
status;
|
|
2626
2794
|
/** Raw response body, for debugging */
|
|
2627
2795
|
body;
|
|
2628
|
-
|
|
2796
|
+
/**
|
|
2797
|
+
* `Retry-After`, already clamped, when the facilitator sent one.
|
|
2798
|
+
*
|
|
2799
|
+
* Optional so every existing three-argument construction keeps compiling; it
|
|
2800
|
+
* falls back to the default wait rather than to zero, because a caller that
|
|
2801
|
+
* retries instantly on a 503 is the load that caused it.
|
|
2802
|
+
*/
|
|
2803
|
+
retryAfterHint;
|
|
2804
|
+
constructor(message, status, body, retryAfterSeconds) {
|
|
2629
2805
|
super(message);
|
|
2630
2806
|
this.name = "Erc8004LookupError";
|
|
2631
2807
|
this.status = status;
|
|
2632
2808
|
this.body = body;
|
|
2809
|
+
this.retryAfterHint = retryAfterSeconds;
|
|
2633
2810
|
}
|
|
2634
2811
|
/** The address genuinely owns no agent on this network. */
|
|
2635
2812
|
get notFound() {
|
|
2636
2813
|
return this.status === 404;
|
|
2637
2814
|
}
|
|
2638
|
-
/**
|
|
2815
|
+
/**
|
|
2816
|
+
* The lookup reached no verdict. Retry; never read as "owns nothing".
|
|
2817
|
+
*
|
|
2818
|
+
* `502` and `504` join `503` and `429` here: a gateway that answered on the
|
|
2819
|
+
* facilitator's behalf is exactly as silent about the agent's existence, and
|
|
2820
|
+
* reading either as absence has the same consequence -- a duplicate mint.
|
|
2821
|
+
*/
|
|
2639
2822
|
get retryable() {
|
|
2640
|
-
return this.status === 503;
|
|
2823
|
+
return this.status === 429 || this.status === 502 || this.status === 503 || this.status === 504;
|
|
2824
|
+
}
|
|
2825
|
+
/**
|
|
2826
|
+
* The facilitator's own `reason`, when the body carried one.
|
|
2827
|
+
*
|
|
2828
|
+
* On a WRITE route this is the writer-lease reason and it decides whether the
|
|
2829
|
+
* request may be re-sent; see {@link isReplayableLeaseReason}.
|
|
2830
|
+
*/
|
|
2831
|
+
get reason() {
|
|
2832
|
+
try {
|
|
2833
|
+
const parsed = JSON.parse(this.body);
|
|
2834
|
+
if (parsed && typeof parsed === "object" && typeof parsed.reason === "string") {
|
|
2835
|
+
return parsed.reason;
|
|
2836
|
+
}
|
|
2837
|
+
} catch {
|
|
2838
|
+
}
|
|
2839
|
+
return void 0;
|
|
2840
|
+
}
|
|
2841
|
+
/**
|
|
2842
|
+
* The facilitator NAMED a reason proving it executed nothing.
|
|
2843
|
+
*
|
|
2844
|
+
* False for `forward_failed` and for every unattributed 5xx: "something
|
|
2845
|
+
* answered" is not evidence that nothing ran. On `/register`, replaying when
|
|
2846
|
+
* this is false is the sequence that minted five duplicate agents.
|
|
2847
|
+
*/
|
|
2848
|
+
get safeToReplay() {
|
|
2849
|
+
return this.status === 429 || this.status === 503 && isReplayableLeaseReason(this.reason);
|
|
2850
|
+
}
|
|
2851
|
+
/** Seconds to wait before retrying, clamped. Absent when not retryable. */
|
|
2852
|
+
get retryAfterSeconds() {
|
|
2853
|
+
if (!this.retryable) return void 0;
|
|
2854
|
+
return this.retryAfterHint ?? DEFAULT_RETRY_AFTER_SECONDS;
|
|
2641
2855
|
}
|
|
2642
2856
|
};
|
|
2643
2857
|
function isRegisterJobTerminal(job) {
|
|
@@ -2674,9 +2888,38 @@ function jobToRegisterResponse(job, network) {
|
|
|
2674
2888
|
var Erc8004Client = class {
|
|
2675
2889
|
baseUrl;
|
|
2676
2890
|
timeout;
|
|
2891
|
+
retries;
|
|
2677
2892
|
constructor(options = {}) {
|
|
2678
2893
|
this.baseUrl = options.baseUrl || "https://facilitator.ultravioletadao.xyz";
|
|
2679
2894
|
this.timeout = options.timeout || 3e4;
|
|
2895
|
+
this.retries = options.retries;
|
|
2896
|
+
}
|
|
2897
|
+
/**
|
|
2898
|
+
* POST a write route, keeping a refusal readable.
|
|
2899
|
+
*
|
|
2900
|
+
* Every ERC-8004 write goes through the facilitator's EVM writer lease, so
|
|
2901
|
+
* every one of them can answer `503` + `reason`. Flattened to a string, those
|
|
2902
|
+
* are indistinguishable from "the registry rejected your feedback" — and on
|
|
2903
|
+
* `/register` the wrong reading re-POSTs a mint that may already have landed,
|
|
2904
|
+
* which is precisely how five duplicate agents were once created.
|
|
2905
|
+
*
|
|
2906
|
+
* A refusal the facilitator proved it did not execute is replayed
|
|
2907
|
+
* automatically (`safeToReplay`); `forward_failed` never is.
|
|
2908
|
+
*/
|
|
2909
|
+
async writeJson(url, body, extraHeaders = {}) {
|
|
2910
|
+
return facilitatorFetch(
|
|
2911
|
+
url,
|
|
2912
|
+
{
|
|
2913
|
+
method: "POST",
|
|
2914
|
+
headers: {
|
|
2915
|
+
"Content-Type": "application/json",
|
|
2916
|
+
Accept: "application/json",
|
|
2917
|
+
...extraHeaders
|
|
2918
|
+
},
|
|
2919
|
+
body: JSON.stringify(body)
|
|
2920
|
+
},
|
|
2921
|
+
{ timeoutMs: this.timeout, retries: this.retries }
|
|
2922
|
+
);
|
|
2680
2923
|
}
|
|
2681
2924
|
/**
|
|
2682
2925
|
* Get agent identity from the Identity Registry
|
|
@@ -2725,26 +2968,21 @@ var Erc8004Client = class {
|
|
|
2725
2968
|
const url = `${this.baseUrl}/identity/${wireNetwork(network)}/owner/${address}`;
|
|
2726
2969
|
const controller = new AbortController();
|
|
2727
2970
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
);
|
|
2742
|
-
}
|
|
2743
|
-
return await response.json();
|
|
2744
|
-
} catch (error) {
|
|
2745
|
-
clearTimeout(timeoutId);
|
|
2746
|
-
throw error;
|
|
2971
|
+
const response = await fetch(url, {
|
|
2972
|
+
method: "GET",
|
|
2973
|
+
headers: { Accept: "application/json" },
|
|
2974
|
+
signal: controller.signal
|
|
2975
|
+
}).finally(() => clearTimeout(timeoutId));
|
|
2976
|
+
if (!response.ok) {
|
|
2977
|
+
const info = await readFacilitatorError(response);
|
|
2978
|
+
throw new Erc8004LookupError(
|
|
2979
|
+
`ERC-8004 API error: ${info.status} - ${info.body}`,
|
|
2980
|
+
info.status,
|
|
2981
|
+
info.body,
|
|
2982
|
+
info.retryAfterSeconds
|
|
2983
|
+
);
|
|
2747
2984
|
}
|
|
2985
|
+
return await response.json();
|
|
2748
2986
|
}
|
|
2749
2987
|
/**
|
|
2750
2988
|
* Resolve agent registration file from agentURI
|
|
@@ -2853,34 +3091,28 @@ var Erc8004Client = class {
|
|
|
2853
3091
|
*/
|
|
2854
3092
|
async submitFeedback(request) {
|
|
2855
3093
|
const url = `${this.baseUrl}/feedback`;
|
|
2856
|
-
const controller = new AbortController();
|
|
2857
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2858
3094
|
try {
|
|
2859
|
-
const response = await
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
"Content-Type": "application/json",
|
|
2863
|
-
"Accept": "application/json"
|
|
2864
|
-
},
|
|
2865
|
-
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
2866
|
-
signal: controller.signal
|
|
3095
|
+
const { response, error } = await this.writeJson(url, {
|
|
3096
|
+
...request,
|
|
3097
|
+
network: wireNetwork(request.network)
|
|
2867
3098
|
});
|
|
2868
|
-
|
|
2869
|
-
if (!response.ok) {
|
|
2870
|
-
const errorText = await response.text();
|
|
3099
|
+
if (error) {
|
|
2871
3100
|
return {
|
|
2872
3101
|
success: false,
|
|
2873
|
-
error:
|
|
2874
|
-
network: request.network
|
|
3102
|
+
error: error.error,
|
|
3103
|
+
network: request.network,
|
|
3104
|
+
...failureFields(error)
|
|
2875
3105
|
};
|
|
2876
3106
|
}
|
|
2877
3107
|
return await response.json();
|
|
2878
3108
|
} catch (error) {
|
|
2879
|
-
clearTimeout(timeoutId);
|
|
2880
3109
|
return {
|
|
2881
3110
|
success: false,
|
|
2882
3111
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
2883
|
-
network: request.network
|
|
3112
|
+
network: request.network,
|
|
3113
|
+
retryable: true,
|
|
3114
|
+
safeToReplay: false,
|
|
3115
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
2884
3116
|
};
|
|
2885
3117
|
}
|
|
2886
3118
|
}
|
|
@@ -2989,34 +3221,28 @@ var Erc8004Client = class {
|
|
|
2989
3221
|
*/
|
|
2990
3222
|
async submitRelayedFeedback(request) {
|
|
2991
3223
|
const url = `${this.baseUrl}/feedback/evm/submit`;
|
|
2992
|
-
const controller = new AbortController();
|
|
2993
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2994
3224
|
try {
|
|
2995
|
-
const response = await
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
"Content-Type": "application/json",
|
|
2999
|
-
"Accept": "application/json"
|
|
3000
|
-
},
|
|
3001
|
-
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
3002
|
-
signal: controller.signal
|
|
3225
|
+
const { response, error } = await this.writeJson(url, {
|
|
3226
|
+
...request,
|
|
3227
|
+
network: wireNetwork(request.network)
|
|
3003
3228
|
});
|
|
3004
|
-
|
|
3005
|
-
if (!response.ok) {
|
|
3006
|
-
const errorText = await response.text();
|
|
3229
|
+
if (error) {
|
|
3007
3230
|
return {
|
|
3008
3231
|
success: false,
|
|
3009
|
-
error:
|
|
3010
|
-
network: request.network
|
|
3232
|
+
error: error.error,
|
|
3233
|
+
network: request.network,
|
|
3234
|
+
...failureFields(error)
|
|
3011
3235
|
};
|
|
3012
3236
|
}
|
|
3013
3237
|
return await response.json();
|
|
3014
3238
|
} catch (error) {
|
|
3015
|
-
clearTimeout(timeoutId);
|
|
3016
3239
|
return {
|
|
3017
3240
|
success: false,
|
|
3018
3241
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
3019
|
-
network: request.network
|
|
3242
|
+
network: request.network,
|
|
3243
|
+
retryable: true,
|
|
3244
|
+
safeToReplay: false,
|
|
3245
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
3020
3246
|
};
|
|
3021
3247
|
}
|
|
3022
3248
|
}
|
|
@@ -3032,8 +3258,6 @@ var Erc8004Client = class {
|
|
|
3032
3258
|
*/
|
|
3033
3259
|
async revokeFeedback(network, agentId, feedbackIndex, options) {
|
|
3034
3260
|
const url = `${this.baseUrl}/feedback/revoke`;
|
|
3035
|
-
const controller = new AbortController();
|
|
3036
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3037
3261
|
const payload = {
|
|
3038
3262
|
x402Version: 1,
|
|
3039
3263
|
network: wireNetwork(network),
|
|
@@ -3046,31 +3270,24 @@ var Erc8004Client = class {
|
|
|
3046
3270
|
payload.originalFeedback = options.originalFeedback;
|
|
3047
3271
|
}
|
|
3048
3272
|
try {
|
|
3049
|
-
const response = await
|
|
3050
|
-
|
|
3051
|
-
headers: {
|
|
3052
|
-
"Content-Type": "application/json",
|
|
3053
|
-
"Accept": "application/json"
|
|
3054
|
-
},
|
|
3055
|
-
body: JSON.stringify(payload),
|
|
3056
|
-
signal: controller.signal
|
|
3057
|
-
});
|
|
3058
|
-
clearTimeout(timeoutId);
|
|
3059
|
-
if (!response.ok) {
|
|
3060
|
-
const errorText = await response.text();
|
|
3273
|
+
const { response, error } = await this.writeJson(url, payload);
|
|
3274
|
+
if (error) {
|
|
3061
3275
|
return {
|
|
3062
3276
|
success: false,
|
|
3063
|
-
error:
|
|
3064
|
-
network
|
|
3277
|
+
error: error.error,
|
|
3278
|
+
network,
|
|
3279
|
+
...failureFields(error)
|
|
3065
3280
|
};
|
|
3066
3281
|
}
|
|
3067
3282
|
return await response.json();
|
|
3068
3283
|
} catch (error) {
|
|
3069
|
-
clearTimeout(timeoutId);
|
|
3070
3284
|
return {
|
|
3071
3285
|
success: false,
|
|
3072
3286
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
3073
|
-
network
|
|
3287
|
+
network,
|
|
3288
|
+
retryable: true,
|
|
3289
|
+
safeToReplay: false,
|
|
3290
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
3074
3291
|
};
|
|
3075
3292
|
}
|
|
3076
3293
|
}
|
|
@@ -3160,24 +3377,23 @@ var Erc8004Client = class {
|
|
|
3160
3377
|
}
|
|
3161
3378
|
/** Shared POST for the relay routes: a refusal is data, never a throw. */
|
|
3162
3379
|
async postRelay(path, request, onError) {
|
|
3163
|
-
const controller = new AbortController();
|
|
3164
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3165
3380
|
try {
|
|
3166
|
-
const response = await
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
3170
|
-
signal: controller.signal
|
|
3381
|
+
const { response, error } = await this.writeJson(`${this.baseUrl}${path}`, {
|
|
3382
|
+
...request,
|
|
3383
|
+
network: wireNetwork(request.network)
|
|
3171
3384
|
});
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
const errorText = await response.text();
|
|
3175
|
-
return { ...onError, error: `Facilitator error: ${response.status} - ${errorText}` };
|
|
3385
|
+
if (error) {
|
|
3386
|
+
return { ...onError, error: error.error, ...failureFields(error) };
|
|
3176
3387
|
}
|
|
3177
3388
|
return await response.json();
|
|
3178
3389
|
} catch (error) {
|
|
3179
|
-
|
|
3180
|
-
|
|
3390
|
+
return {
|
|
3391
|
+
...onError,
|
|
3392
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
3393
|
+
retryable: true,
|
|
3394
|
+
safeToReplay: false,
|
|
3395
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
3396
|
+
};
|
|
3181
3397
|
}
|
|
3182
3398
|
}
|
|
3183
3399
|
/**
|
|
@@ -3214,8 +3430,6 @@ var Erc8004Client = class {
|
|
|
3214
3430
|
*/
|
|
3215
3431
|
async appendResponse(network, agentId, feedbackIndex, response, options) {
|
|
3216
3432
|
const url = `${this.baseUrl}/feedback/response`;
|
|
3217
|
-
const controller = new AbortController();
|
|
3218
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3219
3433
|
const payload = {
|
|
3220
3434
|
x402Version: 1,
|
|
3221
3435
|
network: wireNetwork(network),
|
|
@@ -3230,31 +3444,24 @@ var Erc8004Client = class {
|
|
|
3230
3444
|
payload.sealHash = options.sealHash;
|
|
3231
3445
|
}
|
|
3232
3446
|
try {
|
|
3233
|
-
const fetchResponse = await
|
|
3234
|
-
|
|
3235
|
-
headers: {
|
|
3236
|
-
"Content-Type": "application/json",
|
|
3237
|
-
"Accept": "application/json"
|
|
3238
|
-
},
|
|
3239
|
-
body: JSON.stringify(payload),
|
|
3240
|
-
signal: controller.signal
|
|
3241
|
-
});
|
|
3242
|
-
clearTimeout(timeoutId);
|
|
3243
|
-
if (!fetchResponse.ok) {
|
|
3244
|
-
const errorText = await fetchResponse.text();
|
|
3447
|
+
const { response: fetchResponse, error } = await this.writeJson(url, payload);
|
|
3448
|
+
if (error) {
|
|
3245
3449
|
return {
|
|
3246
3450
|
success: false,
|
|
3247
|
-
error:
|
|
3248
|
-
network
|
|
3451
|
+
error: error.error,
|
|
3452
|
+
network,
|
|
3453
|
+
...failureFields(error)
|
|
3249
3454
|
};
|
|
3250
3455
|
}
|
|
3251
3456
|
return await fetchResponse.json();
|
|
3252
3457
|
} catch (error) {
|
|
3253
|
-
clearTimeout(timeoutId);
|
|
3254
3458
|
return {
|
|
3255
3459
|
success: false,
|
|
3256
3460
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
3257
|
-
network
|
|
3461
|
+
network,
|
|
3462
|
+
retryable: true,
|
|
3463
|
+
safeToReplay: false,
|
|
3464
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
3258
3465
|
};
|
|
3259
3466
|
}
|
|
3260
3467
|
}
|
|
@@ -3298,47 +3505,42 @@ var Erc8004Client = class {
|
|
|
3298
3505
|
return jobToRegisterResponse(terminal, request.network);
|
|
3299
3506
|
}
|
|
3300
3507
|
const url = `${this.baseUrl}/register`;
|
|
3301
|
-
const controller = new AbortController();
|
|
3302
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3303
3508
|
try {
|
|
3304
|
-
const response = await
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
"Content-Type": "application/json",
|
|
3308
|
-
"Accept": "application/json"
|
|
3309
|
-
},
|
|
3310
|
-
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
3311
|
-
signal: controller.signal
|
|
3509
|
+
const { response, error } = await this.writeJson(url, {
|
|
3510
|
+
...request,
|
|
3511
|
+
network: wireNetwork(request.network)
|
|
3312
3512
|
});
|
|
3313
|
-
|
|
3314
|
-
if (!response.ok) {
|
|
3315
|
-
const errorText = await response.text();
|
|
3513
|
+
if (error) {
|
|
3316
3514
|
try {
|
|
3317
|
-
const parsed = JSON.parse(
|
|
3515
|
+
const parsed = JSON.parse(error.body);
|
|
3318
3516
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3319
3517
|
return {
|
|
3320
3518
|
...parsed,
|
|
3321
|
-
// Never let a
|
|
3519
|
+
// Never let a non-2xx body claim success, whatever it says.
|
|
3322
3520
|
success: false,
|
|
3323
|
-
error: parsed.error ?? `Facilitator error: ${
|
|
3324
|
-
network: parsed.network ?? request.network
|
|
3521
|
+
error: parsed.error ?? `Facilitator error: ${error.status}`,
|
|
3522
|
+
network: parsed.network ?? request.network,
|
|
3523
|
+
...failureFields(error)
|
|
3325
3524
|
};
|
|
3326
3525
|
}
|
|
3327
3526
|
} catch {
|
|
3328
3527
|
}
|
|
3329
3528
|
return {
|
|
3330
3529
|
success: false,
|
|
3331
|
-
error:
|
|
3332
|
-
network: request.network
|
|
3530
|
+
error: error.error,
|
|
3531
|
+
network: request.network,
|
|
3532
|
+
...failureFields(error)
|
|
3333
3533
|
};
|
|
3334
3534
|
}
|
|
3335
3535
|
return await response.json();
|
|
3336
3536
|
} catch (error) {
|
|
3337
|
-
clearTimeout(timeoutId);
|
|
3338
3537
|
return {
|
|
3339
3538
|
success: false,
|
|
3340
3539
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
3341
|
-
network: request.network
|
|
3540
|
+
network: request.network,
|
|
3541
|
+
retryable: true,
|
|
3542
|
+
safeToReplay: false,
|
|
3543
|
+
retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
|
|
3342
3544
|
};
|
|
3343
3545
|
}
|
|
3344
3546
|
}
|
|
@@ -3356,33 +3558,20 @@ var Erc8004Client = class {
|
|
|
3356
3558
|
*/
|
|
3357
3559
|
async registerAgentAsync(request) {
|
|
3358
3560
|
const url = `${this.baseUrl}/register`;
|
|
3359
|
-
const
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
});
|
|
3372
|
-
clearTimeout(timeoutId);
|
|
3373
|
-
if (!response.ok) {
|
|
3374
|
-
const errorText = await response.text();
|
|
3375
|
-
throw new Erc8004LookupError(
|
|
3376
|
-
`ERC-8004 API error: ${response.status} - ${errorText}`,
|
|
3377
|
-
response.status,
|
|
3378
|
-
errorText
|
|
3379
|
-
);
|
|
3380
|
-
}
|
|
3381
|
-
return await response.json();
|
|
3382
|
-
} catch (error) {
|
|
3383
|
-
clearTimeout(timeoutId);
|
|
3384
|
-
throw error;
|
|
3561
|
+
const { response, error } = await this.writeJson(
|
|
3562
|
+
url,
|
|
3563
|
+
{ ...request, network: wireNetwork(request.network) },
|
|
3564
|
+
{ Prefer: "respond-async" }
|
|
3565
|
+
);
|
|
3566
|
+
if (error) {
|
|
3567
|
+
throw new Erc8004LookupError(
|
|
3568
|
+
`ERC-8004 API error: ${error.status} - ${error.body}`,
|
|
3569
|
+
error.status,
|
|
3570
|
+
error.body,
|
|
3571
|
+
error.retryAfterSeconds
|
|
3572
|
+
);
|
|
3385
3573
|
}
|
|
3574
|
+
return await response.json();
|
|
3386
3575
|
}
|
|
3387
3576
|
/**
|
|
3388
3577
|
* Read the current state of an asynchronous registration.
|
|
@@ -3394,26 +3583,21 @@ var Erc8004Client = class {
|
|
|
3394
3583
|
const url = `${this.baseUrl}/register/status/${encodeURIComponent(jobId)}`;
|
|
3395
3584
|
const controller = new AbortController();
|
|
3396
3585
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
);
|
|
3411
|
-
}
|
|
3412
|
-
return await response.json();
|
|
3413
|
-
} catch (error) {
|
|
3414
|
-
clearTimeout(timeoutId);
|
|
3415
|
-
throw error;
|
|
3586
|
+
const response = await fetch(url, {
|
|
3587
|
+
method: "GET",
|
|
3588
|
+
headers: { Accept: "application/json" },
|
|
3589
|
+
signal: controller.signal
|
|
3590
|
+
}).finally(() => clearTimeout(timeoutId));
|
|
3591
|
+
if (!response.ok) {
|
|
3592
|
+
const info = await readFacilitatorError(response);
|
|
3593
|
+
throw new Erc8004LookupError(
|
|
3594
|
+
`ERC-8004 API error: ${info.status} - ${info.body}`,
|
|
3595
|
+
info.status,
|
|
3596
|
+
info.body,
|
|
3597
|
+
info.retryAfterSeconds
|
|
3598
|
+
);
|
|
3416
3599
|
}
|
|
3600
|
+
return await response.json();
|
|
3417
3601
|
}
|
|
3418
3602
|
/**
|
|
3419
3603
|
* Poll an asynchronous registration until it finishes.
|
|
@@ -3714,6 +3898,7 @@ var AdvancedEscrowClient = class {
|
|
|
3714
3898
|
chainId;
|
|
3715
3899
|
gasLimit;
|
|
3716
3900
|
timeout;
|
|
3901
|
+
retries;
|
|
3717
3902
|
contracts;
|
|
3718
3903
|
signer;
|
|
3719
3904
|
// ethers.Signer (legacy mode)
|
|
@@ -3750,6 +3935,7 @@ var AdvancedEscrowClient = class {
|
|
|
3750
3935
|
this.chainId = options.chainId || 8453;
|
|
3751
3936
|
this.gasLimit = options.gasLimit || 3e5;
|
|
3752
3937
|
this.timeout = options.timeout || ESCROW_TIMEOUT_MS[this.chainId] || DEFAULT_ESCROW_TIMEOUT_MS;
|
|
3938
|
+
this.retries = options.retries;
|
|
3753
3939
|
if (this.walletAdapter && !this.rpcUrl) {
|
|
3754
3940
|
throw new Error(
|
|
3755
3941
|
"AdvancedEscrowClient: rpcUrl is required when using a SigningWalletAdapter. The adapter signs transactions offline; an RPC provider is needed to build and broadcast them."
|
|
@@ -3824,8 +4010,8 @@ var AdvancedEscrowClient = class {
|
|
|
3824
4010
|
* Matches the on-chain AuthCaptureEscrow nonce derivation.
|
|
3825
4011
|
*/
|
|
3826
4012
|
async computeNonce(paymentInfo) {
|
|
3827
|
-
const { ethers:
|
|
3828
|
-
const piTuple =
|
|
4013
|
+
const { ethers: ethers3 } = await import('ethers');
|
|
4014
|
+
const piTuple = ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
3829
4015
|
["bytes32", "tuple(address,address,address,address,uint120,uint48,uint48,uint48,uint16,uint16,address,uint256)"],
|
|
3830
4016
|
[
|
|
3831
4017
|
PAYMENT_INFO_TYPEHASH,
|
|
@@ -3846,12 +4032,12 @@ var AdvancedEscrowClient = class {
|
|
|
3846
4032
|
]
|
|
3847
4033
|
]
|
|
3848
4034
|
);
|
|
3849
|
-
const piHash =
|
|
3850
|
-
const finalEncoded =
|
|
4035
|
+
const piHash = ethers3.keccak256(piTuple);
|
|
4036
|
+
const finalEncoded = ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
3851
4037
|
["uint256", "address", "bytes32"],
|
|
3852
4038
|
[this.chainId, this.contracts.escrow, piHash]
|
|
3853
4039
|
);
|
|
3854
|
-
return
|
|
4040
|
+
return ethers3.keccak256(finalEncoded);
|
|
3855
4041
|
}
|
|
3856
4042
|
/**
|
|
3857
4043
|
* Sign ReceiveWithAuthorization for ERC-3009.
|
|
@@ -4008,17 +4194,17 @@ var AdvancedEscrowClient = class {
|
|
|
4008
4194
|
async release(paymentInfo, amount) {
|
|
4009
4195
|
if (!this.payerAddress) await this.init();
|
|
4010
4196
|
try {
|
|
4011
|
-
const { ethers:
|
|
4197
|
+
const { ethers: ethers3 } = await import('ethers');
|
|
4012
4198
|
const isCreate3 = CREATE3_CHAIN_IDS.has(this.chainId);
|
|
4013
4199
|
const abi = isCreate3 ? OPERATOR_ABI_CREATE3 : OPERATOR_ABI;
|
|
4014
4200
|
const amt = amount || paymentInfo.maxAmount;
|
|
4015
4201
|
const tuple = this.buildTuple(paymentInfo);
|
|
4016
4202
|
if (this.walletAdapter) {
|
|
4017
|
-
return this.sendViaAdapter(
|
|
4203
|
+
return this.sendViaAdapter(ethers3, abi, (iface) => {
|
|
4018
4204
|
return isCreate3 ? iface.encodeFunctionData("release", [tuple, amt, "0x"]) : iface.encodeFunctionData("release", [tuple, amt]);
|
|
4019
4205
|
});
|
|
4020
4206
|
}
|
|
4021
|
-
const contract = new
|
|
4207
|
+
const contract = new ethers3.Contract(this.contracts.operator, abi, this.signer);
|
|
4022
4208
|
const tx = isCreate3 ? await contract.release(tuple, amt, "0x", { gasLimit: this.gasLimit }) : await contract.release(tuple, amt, { gasLimit: this.gasLimit });
|
|
4023
4209
|
const receipt = await tx.wait();
|
|
4024
4210
|
return {
|
|
@@ -4042,17 +4228,17 @@ var AdvancedEscrowClient = class {
|
|
|
4042
4228
|
async refundInEscrow(paymentInfo, amount) {
|
|
4043
4229
|
if (!this.payerAddress) await this.init();
|
|
4044
4230
|
try {
|
|
4045
|
-
const { ethers:
|
|
4231
|
+
const { ethers: ethers3 } = await import('ethers');
|
|
4046
4232
|
const isCreate3 = CREATE3_CHAIN_IDS.has(this.chainId);
|
|
4047
4233
|
const abi = isCreate3 ? OPERATOR_ABI_CREATE3 : OPERATOR_ABI;
|
|
4048
4234
|
const amt = amount || paymentInfo.maxAmount;
|
|
4049
4235
|
const tuple = this.buildTuple(paymentInfo);
|
|
4050
4236
|
if (this.walletAdapter) {
|
|
4051
|
-
return this.sendViaAdapter(
|
|
4237
|
+
return this.sendViaAdapter(ethers3, abi, (iface) => {
|
|
4052
4238
|
return isCreate3 ? iface.encodeFunctionData("refundInEscrow", [tuple, amt, "0x"]) : iface.encodeFunctionData("refundInEscrow", [tuple, amt]);
|
|
4053
4239
|
});
|
|
4054
4240
|
}
|
|
4055
|
-
const contract = new
|
|
4241
|
+
const contract = new ethers3.Contract(this.contracts.operator, abi, this.signer);
|
|
4056
4242
|
const tx = isCreate3 ? await contract.refundInEscrow(tuple, amt, "0x", { gasLimit: this.gasLimit }) : await contract.refundInEscrow(tuple, amt, { gasLimit: this.gasLimit });
|
|
4057
4243
|
const receipt = await tx.wait();
|
|
4058
4244
|
return {
|
|
@@ -4122,16 +4308,19 @@ var AdvancedEscrowClient = class {
|
|
|
4122
4308
|
}
|
|
4123
4309
|
}
|
|
4124
4310
|
};
|
|
4125
|
-
const controller = new AbortController();
|
|
4126
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
4127
4311
|
try {
|
|
4128
|
-
const response = await
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4312
|
+
const { response, error } = await facilitatorFetch(
|
|
4313
|
+
`${this.facilitatorUrl}/settle`,
|
|
4314
|
+
{
|
|
4315
|
+
method: "POST",
|
|
4316
|
+
headers: { "Content-Type": "application/json" },
|
|
4317
|
+
body: JSON.stringify(payload)
|
|
4318
|
+
},
|
|
4319
|
+
{ timeoutMs: this.timeout, retries: this.retries }
|
|
4320
|
+
);
|
|
4321
|
+
if (error) {
|
|
4322
|
+
return { success: false, error: error.error, ...failureFields(error) };
|
|
4323
|
+
}
|
|
4135
4324
|
const result = await response.json();
|
|
4136
4325
|
if (result.success) {
|
|
4137
4326
|
return {
|
|
@@ -4144,7 +4333,6 @@ var AdvancedEscrowClient = class {
|
|
|
4144
4333
|
error: result.errorReason || result.error || `Release refused with no reason (HTTP ${response.status}, body keys: ${Object.keys(result ?? {}).sort().join(", ") || "none"})`
|
|
4145
4334
|
};
|
|
4146
4335
|
} catch (fetchErr) {
|
|
4147
|
-
clearTimeout(timeoutId);
|
|
4148
4336
|
if (fetchErr.name === "AbortError") {
|
|
4149
4337
|
try {
|
|
4150
4338
|
const state = await this.queryEscrowState(paymentInfo);
|
|
@@ -4162,23 +4350,53 @@ var AdvancedEscrowClient = class {
|
|
|
4162
4350
|
}
|
|
4163
4351
|
}
|
|
4164
4352
|
/**
|
|
4165
|
-
* GASLESS REFUND:
|
|
4353
|
+
* GASLESS REFUND: return escrowed funds to the payer via the facilitator.
|
|
4166
4354
|
*
|
|
4167
|
-
*
|
|
4168
|
-
*
|
|
4169
|
-
*
|
|
4355
|
+
* Sends `action: "refundInEscrow"` to `POST /settle`; the facilitator's
|
|
4356
|
+
* PaymentOperator calls `AuthCaptureEscrow.partialVoid`.
|
|
4357
|
+
*
|
|
4358
|
+
* # This is how an EXPIRED escrow is recovered
|
|
4359
|
+
*
|
|
4360
|
+
* A widely repeated claim — including in this SDK's own comments until now —
|
|
4361
|
+
* says that once `authorizationExpiry` passes, only the payer's `reclaim()`
|
|
4362
|
+
* can move the funds. **That is false, and believing it has left real money
|
|
4363
|
+
* stranded.**
|
|
4364
|
+
*
|
|
4365
|
+
* Read the contract (`AuthCaptureEscrow.sol`):
|
|
4366
|
+
*
|
|
4367
|
+
* - `partialVoid` is `onlySender(paymentInfo.operator)` — the operator is the
|
|
4368
|
+
* FACILITATOR, not the payer — it sends the tokens **to the payer**, and it
|
|
4369
|
+
* **does not check `authorizationExpiry` at all**. It works before expiry
|
|
4370
|
+
* and after it, and the payer never has to appear.
|
|
4371
|
+
* - `reclaim` is `onlySender(paymentInfo.payer)` and only after expiry. It is
|
|
4372
|
+
* a payer's self-service escape hatch, which is why this facilitator does
|
|
4373
|
+
* not expose it — **not** the only way out.
|
|
4374
|
+
*
|
|
4375
|
+
* So a release that reverted with `AfterAuthorizationExpiry` is recoverable
|
|
4376
|
+
* from here, with no gas and no cooperation from the payer. Get the amount
|
|
4377
|
+
* from {@link queryEscrowState}'s `capturableAmount`.
|
|
4378
|
+
*
|
|
4379
|
+
* # A refusal that is not a refusal
|
|
4380
|
+
*
|
|
4381
|
+
* Check `retryable` before writing an escrow off. A `503` means the
|
|
4382
|
+
* facilitator never reached the chain — the escrow is untouched and the same
|
|
4383
|
+
* request should be sent again.
|
|
4170
4384
|
*
|
|
4171
4385
|
* @param paymentInfo - PaymentInfo from the authorize step
|
|
4172
|
-
* @param amount - Amount to refund in atomic units (defaults to maxAmount)
|
|
4386
|
+
* @param amount - Amount to refund in atomic units (defaults to maxAmount).
|
|
4387
|
+
* For a stuck escrow pass `capturableAmount` from {@link queryEscrowState}.
|
|
4173
4388
|
* @returns Transaction result from the facilitator
|
|
4174
4389
|
*
|
|
4175
|
-
* @example
|
|
4390
|
+
* @example Recovering an escrow whose release window already closed
|
|
4176
4391
|
* ```typescript
|
|
4177
|
-
* const
|
|
4178
|
-
*
|
|
4179
|
-
*
|
|
4180
|
-
*
|
|
4181
|
-
*
|
|
4392
|
+
* const state = await client.queryEscrowState(pi);
|
|
4393
|
+
* if (state.capturableAmount !== '0') {
|
|
4394
|
+
* // No payer needed, no gas, and expiry is irrelevant to partialVoid.
|
|
4395
|
+
* const result = await client.refundViaFacilitator(pi, state.capturableAmount);
|
|
4396
|
+
* if (!result.success && result.retryable) {
|
|
4397
|
+
* // No verdict was reached. The funds are still there; send it again.
|
|
4398
|
+
* }
|
|
4399
|
+
* }
|
|
4182
4400
|
* ```
|
|
4183
4401
|
*/
|
|
4184
4402
|
async refundViaFacilitator(paymentInfo, amount) {
|
|
@@ -4215,16 +4433,19 @@ var AdvancedEscrowClient = class {
|
|
|
4215
4433
|
}
|
|
4216
4434
|
}
|
|
4217
4435
|
};
|
|
4218
|
-
const controller = new AbortController();
|
|
4219
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
4220
4436
|
try {
|
|
4221
|
-
const response = await
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4437
|
+
const { response, error } = await facilitatorFetch(
|
|
4438
|
+
`${this.facilitatorUrl}/settle`,
|
|
4439
|
+
{
|
|
4440
|
+
method: "POST",
|
|
4441
|
+
headers: { "Content-Type": "application/json" },
|
|
4442
|
+
body: JSON.stringify(payload)
|
|
4443
|
+
},
|
|
4444
|
+
{ timeoutMs: this.timeout, retries: this.retries }
|
|
4445
|
+
);
|
|
4446
|
+
if (error) {
|
|
4447
|
+
return { success: false, error: error.error, ...failureFields(error) };
|
|
4448
|
+
}
|
|
4228
4449
|
const result = await response.json();
|
|
4229
4450
|
if (result.success) {
|
|
4230
4451
|
return {
|
|
@@ -4232,9 +4453,11 @@ var AdvancedEscrowClient = class {
|
|
|
4232
4453
|
transactionHash: result.transaction || result.transactionHash || result.transaction_hash
|
|
4233
4454
|
};
|
|
4234
4455
|
}
|
|
4235
|
-
return {
|
|
4456
|
+
return {
|
|
4457
|
+
success: false,
|
|
4458
|
+
error: result.errorReason || result.error || `Refund refused with no reason (HTTP ${response.status}, body keys: ${Object.keys(result ?? {}).sort().join(", ") || "none"})`
|
|
4459
|
+
};
|
|
4236
4460
|
} catch (fetchErr) {
|
|
4237
|
-
clearTimeout(timeoutId);
|
|
4238
4461
|
if (fetchErr.name === "AbortError") {
|
|
4239
4462
|
try {
|
|
4240
4463
|
const state = await this.queryEscrowState(paymentInfo);
|
|
@@ -4318,7 +4541,7 @@ var AdvancedEscrowClient = class {
|
|
|
4318
4541
|
async charge(paymentInfo, amount) {
|
|
4319
4542
|
if (!this.payerAddress) await this.init();
|
|
4320
4543
|
try {
|
|
4321
|
-
const { ethers:
|
|
4544
|
+
const { ethers: ethers3 } = await import('ethers');
|
|
4322
4545
|
const nonce = await this.computeNonce(paymentInfo);
|
|
4323
4546
|
const amt = amount || paymentInfo.maxAmount;
|
|
4324
4547
|
const auth = {
|
|
@@ -4330,10 +4553,10 @@ var AdvancedEscrowClient = class {
|
|
|
4330
4553
|
nonce
|
|
4331
4554
|
};
|
|
4332
4555
|
const signature = await this.signErc3009(auth);
|
|
4333
|
-
const collectorData =
|
|
4556
|
+
const collectorData = ethers3.getBytes(signature);
|
|
4334
4557
|
const tuple = this.buildTuple(paymentInfo);
|
|
4335
4558
|
if (this.walletAdapter) {
|
|
4336
|
-
return this.sendViaAdapter(
|
|
4559
|
+
return this.sendViaAdapter(ethers3, OPERATOR_ABI, (iface) => {
|
|
4337
4560
|
return iface.encodeFunctionData("charge", [
|
|
4338
4561
|
tuple,
|
|
4339
4562
|
amt,
|
|
@@ -4342,7 +4565,7 @@ var AdvancedEscrowClient = class {
|
|
|
4342
4565
|
]);
|
|
4343
4566
|
});
|
|
4344
4567
|
}
|
|
4345
|
-
const contract = new
|
|
4568
|
+
const contract = new ethers3.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
|
|
4346
4569
|
const tx = await contract.charge(
|
|
4347
4570
|
tuple,
|
|
4348
4571
|
amt,
|
|
@@ -4384,11 +4607,11 @@ var AdvancedEscrowClient = class {
|
|
|
4384
4607
|
async refundPostEscrow(paymentInfo, amount, tokenCollector, collectorData) {
|
|
4385
4608
|
if (!this.payerAddress) await this.init();
|
|
4386
4609
|
try {
|
|
4387
|
-
const { ethers:
|
|
4610
|
+
const { ethers: ethers3 } = await import('ethers');
|
|
4388
4611
|
const amt = amount || paymentInfo.maxAmount;
|
|
4389
4612
|
const tuple = this.buildTuple(paymentInfo);
|
|
4390
4613
|
if (this.walletAdapter) {
|
|
4391
|
-
return this.sendViaAdapter(
|
|
4614
|
+
return this.sendViaAdapter(ethers3, OPERATOR_ABI, (iface) => {
|
|
4392
4615
|
return iface.encodeFunctionData("refundPostEscrow", [
|
|
4393
4616
|
tuple,
|
|
4394
4617
|
amt,
|
|
@@ -4397,7 +4620,7 @@ var AdvancedEscrowClient = class {
|
|
|
4397
4620
|
]);
|
|
4398
4621
|
});
|
|
4399
4622
|
}
|
|
4400
|
-
const contract = new
|
|
4623
|
+
const contract = new ethers3.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
|
|
4401
4624
|
const tx = await contract.refundPostEscrow(
|
|
4402
4625
|
tuple,
|
|
4403
4626
|
amt,
|
|
@@ -4460,6 +4683,6 @@ var AdvancedEscrowClient = class {
|
|
|
4460
4683
|
}
|
|
4461
4684
|
};
|
|
4462
4685
|
|
|
4463
|
-
export { AdvancedEscrowClient, BASE_MAINNET_CONTRACTS, BazaarClient, DEPOSIT_LIMIT_USDC, ERC8004_CONTRACTS, ERC8004_EXTENSION_ID, ESCROW_CONTRACTS, ESCROW_TIMEOUT_MS, Erc8004Client, Erc8004LookupError, EscrowClient, FacilitatorClient, HEALTH_FILTERS, MAX_SEARCH_LEN, OPERATOR_ABI, OPERATOR_ABI_CREATE3, PAYMENT_INFO_TYPEHASH, RELAYED_FEEDBACK_NETWORKS, RegistrationPendingError, TIER_FILTERS, TIER_TIMINGS, USDC_DOMAIN_NAME, X402_CORS_HEADERS, X402_HEADER_NAMES, ZERO_ADDRESS, buildErc8004PaymentRequirements, buildPaymentRequirements, buildSettleRequest, buildSettleRequestV2, buildVerifyRequest, buildVerifyRequestV2, canRefundEscrow, canReleaseEscrow, create402Response, createHonoMiddleware, createPaymentMiddleware, epochToDate, escrowTimeRemaining, extractPaymentFromHeaders, getCorsHeaders, getEscrowContractsByChainId, getEscrowSupportedChainIds, isAlive, isEscrowExpired, isEscrowSupportedOnChain, isRegisterJobTerminal, parsePaymentHeader, supportsRelayedFeedback, wireNetwork };
|
|
4686
|
+
export { AMBIGUOUS_LEASE_REASONS, AdvancedEscrowClient, BASE_MAINNET_CONTRACTS, BazaarClient, DEFAULT_FACILITATOR_RETRIES, DEFAULT_RETRY_AFTER_SECONDS, DEPOSIT_LIMIT_USDC, ERC8004_CONTRACTS, ERC8004_EXTENSION_ID, ESCROW_CONTRACTS, ESCROW_TIMEOUT_MS, Erc8004Client, Erc8004LookupError, EscrowClient, FacilitatorClient, HEALTH_FILTERS, MAX_RETRY_AFTER_SECONDS, MAX_SEARCH_LEN, OPERATOR_ABI, OPERATOR_ABI_CREATE3, PAYMENT_INFO_TYPEHASH, RELAYED_FEEDBACK_NETWORKS, REPLAYABLE_LEASE_REASONS, RegistrationPendingError, TIER_FILTERS, TIER_TIMINGS, USDC_DOMAIN_NAME, WRITER_LEASE_REASONS, X402_CORS_HEADERS, X402_HEADER_NAMES, ZERO_ADDRESS, buildErc8004PaymentRequirements, buildPaymentRequirements, buildSettleRequest, buildSettleRequestV2, buildVerifyRequest, buildVerifyRequestV2, canRefundEscrow, canReleaseEscrow, carryFailureFields, create402Response, createHonoMiddleware, createPaymentMiddleware, epochToDate, escrowTimeRemaining, extractPaymentFromHeaders, facilitatorFetch, getCorsHeaders, getEscrowContractsByChainId, getEscrowSupportedChainIds, isAlive, isAmbiguousLeaseReason, isEscrowExpired, isEscrowSupportedOnChain, isRegisterJobTerminal, isReplayableLeaseReason, parsePaymentHeader, parseRetryAfterSeconds, readFacilitatorError, supportsRelayedFeedback, wireNetwork };
|
|
4464
4687
|
//# sourceMappingURL=index.mjs.map
|
|
4465
4688
|
//# sourceMappingURL=index.mjs.map
|