@zeroxyz/sdk 0.6.0 → 0.7.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/CHANGELOG.md +8 -0
- package/README.md +6 -3
- package/dist/{chunk-3YKWO4B2.js → chunk-26IHUYNK.js} +1560 -1552
- package/dist/chunk-26IHUYNK.js.map +1 -0
- package/dist/{chunk-UIK7QKNQ.cjs → chunk-2HZJHVDN.cjs} +1560 -1551
- package/dist/chunk-2HZJHVDN.cjs.map +1 -0
- package/dist/{client-CDk1PVU-.d.cts → client-7zp9ZyYd.d.cts} +20 -1
- package/dist/{client-CDk1PVU-.d.ts → client-7zp9ZyYd.d.ts} +20 -1
- package/dist/index.cjs +39 -35
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/testing.cjs +2 -2
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3YKWO4B2.js.map +0 -1
- package/dist/chunk-UIK7QKNQ.cjs.map +0 -1
|
@@ -11,8 +11,8 @@ var fetch = require('@x402/fetch');
|
|
|
11
11
|
var mppx = require('mppx');
|
|
12
12
|
var client$2 = require('mppx/client');
|
|
13
13
|
var chains = require('viem/chains');
|
|
14
|
-
var zod = require('zod');
|
|
15
14
|
var crypto$1 = require('crypto');
|
|
15
|
+
var zod = require('zod');
|
|
16
16
|
|
|
17
17
|
// src/auth/managed-account.ts
|
|
18
18
|
var createManagedAccount = (client, address) => accounts.toAccount({
|
|
@@ -1215,1683 +1215,1688 @@ var Payments = class {
|
|
|
1215
1215
|
};
|
|
1216
1216
|
};
|
|
1217
1217
|
};
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
var
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
var signResponseSchema = zod.z.object({
|
|
1260
|
-
signature: zod.z.string().regex(/^0x[0-9a-fA-F]+$/, "must be 0x-prefixed hex"),
|
|
1261
|
-
walletAddress: zod.z.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be 0x-prefixed 40-char hex address")
|
|
1262
|
-
});
|
|
1263
|
-
|
|
1264
|
-
// src/schemas/device.ts
|
|
1265
|
-
var deviceStartResponseSchema = zod.z.object({
|
|
1266
|
-
deviceCode: zod.z.string(),
|
|
1267
|
-
userCode: zod.z.string(),
|
|
1268
|
-
verificationUri: zod.z.string(),
|
|
1269
|
-
pollInterval: zod.z.number(),
|
|
1270
|
-
expiresAt: zod.z.number()
|
|
1271
|
-
});
|
|
1272
|
-
var devicePollResponseSchema = zod.z.union([
|
|
1273
|
-
// userCode + verificationUri are optional: older API deployments don't
|
|
1274
|
-
// echo them on pending.
|
|
1275
|
-
zod.z.object({
|
|
1276
|
-
error: zod.z.literal("authorization_pending"),
|
|
1277
|
-
userCode: zod.z.string().optional(),
|
|
1278
|
-
verificationUri: zod.z.string().optional()
|
|
1279
|
-
}),
|
|
1280
|
-
zod.z.object({ error: zod.z.literal("expired_token") }),
|
|
1281
|
-
zod.z.object({
|
|
1282
|
-
accessToken: zod.z.string(),
|
|
1283
|
-
refreshToken: zod.z.string(),
|
|
1284
|
-
expiresIn: zod.z.number(),
|
|
1285
|
-
user: internalUserDtoSchema
|
|
1286
|
-
})
|
|
1287
|
-
]);
|
|
1288
|
-
var sessionExchangeResponseSchema = zod.z.object({
|
|
1289
|
-
token: zod.z.string(),
|
|
1290
|
-
expiresAt: zod.z.number()
|
|
1291
|
-
});
|
|
1292
|
-
var refreshResponseSchema = zod.z.object({
|
|
1293
|
-
accessToken: zod.z.string(),
|
|
1294
|
-
refreshToken: zod.z.string()
|
|
1295
|
-
});
|
|
1296
|
-
var tryRefreshSession = async (client, callerSignal) => {
|
|
1297
|
-
const credentials = client.getCredentials();
|
|
1298
|
-
if (credentials.kind !== "session") return false;
|
|
1299
|
-
if (!credentials.refreshToken) return false;
|
|
1300
|
-
const url = `${client.baseUrl.replace(/\/$/, "")}/v1/auth/refresh`;
|
|
1301
|
-
const timeoutSignal = AbortSignal.timeout(client.timeout);
|
|
1302
|
-
const signal = callerSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : timeoutSignal;
|
|
1303
|
-
let response;
|
|
1304
|
-
try {
|
|
1305
|
-
response = await client.fetchImpl(url, {
|
|
1306
|
-
method: "POST",
|
|
1307
|
-
headers: { "content-type": "application/json" },
|
|
1308
|
-
body: JSON.stringify({ refreshToken: credentials.refreshToken }),
|
|
1309
|
-
signal
|
|
1310
|
-
});
|
|
1311
|
-
} catch {
|
|
1312
|
-
return false;
|
|
1218
|
+
var isShortToken = (id) => id.startsWith("z_") && id.indexOf(".", 2) !== -1;
|
|
1219
|
+
var MAX_402_PROBE_BYTES = 1024 * 1024;
|
|
1220
|
+
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
1221
|
+
var TEXT_CONTENT_TYPES = [
|
|
1222
|
+
"application/json",
|
|
1223
|
+
"application/xml",
|
|
1224
|
+
"application/javascript",
|
|
1225
|
+
"application/ecmascript",
|
|
1226
|
+
"application/x-www-form-urlencoded",
|
|
1227
|
+
"text/",
|
|
1228
|
+
"+json",
|
|
1229
|
+
"+xml"
|
|
1230
|
+
];
|
|
1231
|
+
var MPP_SCHEME_TOKENS = /* @__PURE__ */ new Set(["payment", "mpp"]);
|
|
1232
|
+
var splitWwwAuthenticateChallenges = (header) => {
|
|
1233
|
+
const chunks = [];
|
|
1234
|
+
let buf = "";
|
|
1235
|
+
let inQuotes = false;
|
|
1236
|
+
for (let i = 0; i < header.length; i++) {
|
|
1237
|
+
const ch = header[i];
|
|
1238
|
+
if (inQuotes) {
|
|
1239
|
+
if (ch === "\\" && i + 1 < header.length) {
|
|
1240
|
+
buf += ch + header[i + 1];
|
|
1241
|
+
i++;
|
|
1242
|
+
continue;
|
|
1243
|
+
}
|
|
1244
|
+
if (ch === '"') inQuotes = false;
|
|
1245
|
+
buf += ch;
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
if (ch === '"') {
|
|
1249
|
+
inQuotes = true;
|
|
1250
|
+
buf += ch;
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
if (ch === ",") {
|
|
1254
|
+
chunks.push(buf);
|
|
1255
|
+
buf = "";
|
|
1256
|
+
continue;
|
|
1257
|
+
}
|
|
1258
|
+
buf += ch;
|
|
1313
1259
|
}
|
|
1314
|
-
if (
|
|
1315
|
-
|
|
1260
|
+
if (buf.length > 0) chunks.push(buf);
|
|
1261
|
+
return chunks;
|
|
1262
|
+
};
|
|
1263
|
+
var isTextContentType = (contentType) => {
|
|
1264
|
+
if (!contentType) return true;
|
|
1265
|
+
const lower = contentType.toLowerCase();
|
|
1266
|
+
return TEXT_CONTENT_TYPES.some((marker) => lower.includes(marker));
|
|
1267
|
+
};
|
|
1268
|
+
var redactUrl = (url) => {
|
|
1316
1269
|
try {
|
|
1317
|
-
|
|
1270
|
+
const u = new URL(url);
|
|
1271
|
+
return `${u.origin}${u.pathname}`;
|
|
1318
1272
|
} catch {
|
|
1319
|
-
return
|
|
1273
|
+
return "<invalid url>";
|
|
1320
1274
|
}
|
|
1321
|
-
const parsed = refreshResponseSchema.safeParse(body);
|
|
1322
|
-
if (!parsed.success) return false;
|
|
1323
|
-
await client.applyRefreshedTokens({
|
|
1324
|
-
accessToken: parsed.data.accessToken,
|
|
1325
|
-
refreshToken: parsed.data.refreshToken
|
|
1326
|
-
});
|
|
1327
|
-
return true;
|
|
1328
|
-
};
|
|
1329
|
-
var buildSessionAuthHeaders = (accessToken) => ({
|
|
1330
|
-
authorization: `Bearer ${accessToken}`
|
|
1331
|
-
});
|
|
1332
|
-
var buildCanonicalMessage = (method, pathWithQuery, body, timestamp, nonce) => {
|
|
1333
|
-
const bodyHash = crypto$1.createHash("sha256").update(body ?? "").digest("hex");
|
|
1334
|
-
return `${method}:${pathWithQuery}:${bodyHash}:${timestamp}:${nonce}`;
|
|
1335
1275
|
};
|
|
1336
|
-
var
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
body,
|
|
1343
|
-
timestamp,
|
|
1344
|
-
nonce
|
|
1276
|
+
var ECHO_DETECT_MIN_LEN = 16;
|
|
1277
|
+
var ECHO_DETECT_MAX_SCAN = 64 * 1024;
|
|
1278
|
+
var requestBodyEchoed = (candidate, requestBody) => {
|
|
1279
|
+
if (requestBody === void 0) return false;
|
|
1280
|
+
const asString = typeof requestBody === "string" ? requestBody : new TextDecoder("utf-8", { fatal: false }).decode(
|
|
1281
|
+
requestBody.byteLength > ECHO_DETECT_MAX_SCAN ? requestBody.subarray(0, ECHO_DETECT_MAX_SCAN) : requestBody
|
|
1345
1282
|
);
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
};
|
|
1353
|
-
};
|
|
1354
|
-
|
|
1355
|
-
// src/transport/http.ts
|
|
1356
|
-
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 502, 503, 504]);
|
|
1357
|
-
var sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
1358
|
-
if (signal?.aborted) {
|
|
1359
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
1360
|
-
return;
|
|
1361
|
-
}
|
|
1362
|
-
const timer = setTimeout(() => {
|
|
1363
|
-
signal?.removeEventListener("abort", onAbort);
|
|
1364
|
-
resolve();
|
|
1365
|
-
}, ms);
|
|
1366
|
-
const onAbort = () => {
|
|
1367
|
-
clearTimeout(timer);
|
|
1368
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
1369
|
-
};
|
|
1370
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1371
|
-
});
|
|
1372
|
-
var buildPathWithQuery = (path, query) => {
|
|
1373
|
-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1374
|
-
if (!query) return normalizedPath;
|
|
1375
|
-
const params = new URLSearchParams();
|
|
1376
|
-
for (const [key, value] of Object.entries(query)) {
|
|
1377
|
-
if (value !== void 0) params.set(key, String(value));
|
|
1378
|
-
}
|
|
1379
|
-
const qs = params.toString();
|
|
1380
|
-
return qs ? `${normalizedPath}?${qs}` : normalizedPath;
|
|
1381
|
-
};
|
|
1382
|
-
var joinUrl = (baseUrl, pathWithQuery) => {
|
|
1383
|
-
const base3 = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
1384
|
-
return `${base3}${pathWithQuery}`;
|
|
1385
|
-
};
|
|
1386
|
-
var buildHeaders = async (client, method, pathWithQuery, hasBody, bodyStr) => {
|
|
1387
|
-
const headers = { ...client.defaultHeaders };
|
|
1388
|
-
if (hasBody) headers["content-type"] = "application/json";
|
|
1389
|
-
headers["x-zero-sdk-version"] = SDK_VERSION;
|
|
1390
|
-
if (client.apiVersion) headers["x-zero-api-version"] = client.apiVersion;
|
|
1391
|
-
const credentials = client.getCredentials();
|
|
1392
|
-
if (credentials.kind === "session") {
|
|
1393
|
-
Object.assign(headers, buildSessionAuthHeaders(credentials.accessToken));
|
|
1394
|
-
} else if (credentials.kind === "account") {
|
|
1395
|
-
const signed = await buildAccountAuthHeaders(
|
|
1396
|
-
credentials.account,
|
|
1397
|
-
method,
|
|
1398
|
-
pathWithQuery,
|
|
1399
|
-
bodyStr
|
|
1400
|
-
);
|
|
1401
|
-
Object.assign(headers, signed);
|
|
1283
|
+
if (asString.length < ECHO_DETECT_MIN_LEN) return false;
|
|
1284
|
+
const scanLen = Math.min(asString.length, ECHO_DETECT_MAX_SCAN);
|
|
1285
|
+
for (let i = 0; i + ECHO_DETECT_MIN_LEN <= scanLen; i++) {
|
|
1286
|
+
if (candidate.includes(asString.slice(i, i + ECHO_DETECT_MIN_LEN))) {
|
|
1287
|
+
return true;
|
|
1288
|
+
}
|
|
1402
1289
|
}
|
|
1403
|
-
return
|
|
1290
|
+
return false;
|
|
1404
1291
|
};
|
|
1405
|
-
var
|
|
1292
|
+
var cancelBody2 = (response) => {
|
|
1406
1293
|
try {
|
|
1407
|
-
|
|
1294
|
+
response.body?.cancel().catch(() => {
|
|
1295
|
+
});
|
|
1408
1296
|
} catch {
|
|
1409
|
-
try {
|
|
1410
|
-
return await response.text();
|
|
1411
|
-
} catch {
|
|
1412
|
-
return void 0;
|
|
1413
|
-
}
|
|
1414
1297
|
}
|
|
1415
1298
|
};
|
|
1416
|
-
var
|
|
1417
|
-
if (
|
|
1418
|
-
|
|
1299
|
+
var detectPaymentRequirement = async (response) => {
|
|
1300
|
+
if (response.status !== 402) return null;
|
|
1301
|
+
const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
|
|
1302
|
+
if (x402Header) {
|
|
1303
|
+
cancelBody2(response);
|
|
1304
|
+
try {
|
|
1305
|
+
const decoded = JSON.parse(
|
|
1306
|
+
Buffer.from(x402Header, "base64").toString("utf8")
|
|
1307
|
+
);
|
|
1308
|
+
return { protocol: "x402", raw: decoded };
|
|
1309
|
+
} catch {
|
|
1310
|
+
return { protocol: "x402", raw: { encoded: x402Header } };
|
|
1311
|
+
}
|
|
1419
1312
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
const
|
|
1425
|
-
|
|
1426
|
-
const bodyStr = hasBody ? JSON.stringify(
|
|
1427
|
-
opts.body,
|
|
1428
|
-
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
1429
|
-
) : void 0;
|
|
1430
|
-
const configuredFetch = buildConfiguredFetch(client);
|
|
1431
|
-
const performOnce = async () => configuredFetch(url, {
|
|
1432
|
-
method: opts.method,
|
|
1433
|
-
headers: await buildHeaders(
|
|
1434
|
-
client,
|
|
1435
|
-
opts.method,
|
|
1436
|
-
pathWithQuery,
|
|
1437
|
-
hasBody,
|
|
1438
|
-
bodyStr
|
|
1439
|
-
),
|
|
1440
|
-
body: bodyStr,
|
|
1441
|
-
signal: opts.signal
|
|
1442
|
-
});
|
|
1443
|
-
let refreshAttempted = false;
|
|
1444
|
-
const executeWithRefresh = async () => {
|
|
1445
|
-
const response = await performOnce();
|
|
1446
|
-
if (response.status !== 401 || refreshAttempted) return response;
|
|
1447
|
-
const credentials = client.getCredentials();
|
|
1448
|
-
if (credentials.kind !== "session") return response;
|
|
1449
|
-
refreshAttempted = true;
|
|
1450
|
-
const refreshed = await client.refreshSessionOnce(opts.signal);
|
|
1451
|
-
if (!refreshed) return response;
|
|
1452
|
-
return await performOnce();
|
|
1453
|
-
};
|
|
1454
|
-
let lastNetworkError;
|
|
1455
|
-
for (let attempt = 0; attempt <= client.maxRetries; attempt++) {
|
|
1456
|
-
let response;
|
|
1313
|
+
const declaredLen = Number.parseInt(
|
|
1314
|
+
response.headers.get("content-length") ?? "",
|
|
1315
|
+
10
|
|
1316
|
+
);
|
|
1317
|
+
const bodyFits = !Number.isFinite(declaredLen) || declaredLen <= MAX_402_PROBE_BYTES;
|
|
1318
|
+
if (bodyFits) {
|
|
1457
1319
|
try {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
try {
|
|
1464
|
-
await sleep(2 ** attempt * 200, opts.signal);
|
|
1465
|
-
} catch (sleepErr) {
|
|
1466
|
-
throw new ZeroApiError("Request aborted by caller", {
|
|
1467
|
-
status: 0,
|
|
1468
|
-
cause: sleepErr
|
|
1469
|
-
});
|
|
1320
|
+
const text = await readClippedText(response, MAX_402_PROBE_BYTES);
|
|
1321
|
+
if (text) {
|
|
1322
|
+
const parsed = JSON.parse(text);
|
|
1323
|
+
if (looksLikeX402Body(parsed)) {
|
|
1324
|
+
return { protocol: "x402", raw: parsed };
|
|
1470
1325
|
}
|
|
1471
|
-
continue;
|
|
1472
|
-
}
|
|
1473
|
-
throw new ZeroApiError("Network request failed", {
|
|
1474
|
-
status: 0,
|
|
1475
|
-
cause: e
|
|
1476
|
-
});
|
|
1477
|
-
}
|
|
1478
|
-
if (response.ok) {
|
|
1479
|
-
let text;
|
|
1480
|
-
try {
|
|
1481
|
-
text = await response.text();
|
|
1482
|
-
} catch (e) {
|
|
1483
|
-
throw new ZeroApiError("Response body read failed", {
|
|
1484
|
-
status: response.status,
|
|
1485
|
-
cause: e
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
let json;
|
|
1489
|
-
try {
|
|
1490
|
-
json = JSON.parse(text);
|
|
1491
|
-
} catch {
|
|
1492
1326
|
}
|
|
1493
|
-
|
|
1494
|
-
if (!parsed.success) {
|
|
1495
|
-
throw new ZeroValidationError(
|
|
1496
|
-
`Response did not match expected schema for ${opts.method} ${opts.path}`,
|
|
1497
|
-
{ cause: parsed.error, body: text }
|
|
1498
|
-
);
|
|
1499
|
-
}
|
|
1500
|
-
return parsed.data;
|
|
1327
|
+
} catch {
|
|
1501
1328
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
}
|
|
1511
|
-
continue;
|
|
1329
|
+
}
|
|
1330
|
+
const wwwAuth = response.headers.get("www-authenticate");
|
|
1331
|
+
if (wwwAuth) {
|
|
1332
|
+
const schemes = splitWwwAuthenticateChallenges(wwwAuth).map(
|
|
1333
|
+
(challenge) => challenge.trim().split(/\s+/)[0]?.toLowerCase() ?? ""
|
|
1334
|
+
);
|
|
1335
|
+
if (schemes.some((scheme) => MPP_SCHEME_TOKENS.has(scheme))) {
|
|
1336
|
+
cancelBody2(response);
|
|
1337
|
+
return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
|
|
1512
1338
|
}
|
|
1513
|
-
const errorBody = await parseErrorBody(response);
|
|
1514
|
-
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1515
|
-
throw new ZeroApiError(errorMessageFromBody(errorBody, response.status), {
|
|
1516
|
-
status: response.status,
|
|
1517
|
-
requestId,
|
|
1518
|
-
body: errorBody
|
|
1519
|
-
});
|
|
1520
1339
|
}
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
cause: lastNetworkError
|
|
1524
|
-
});
|
|
1340
|
+
cancelBody2(response);
|
|
1341
|
+
return { protocol: "unknown", raw: {} };
|
|
1525
1342
|
};
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
},
|
|
1539
|
-
deviceStartResponseSchema
|
|
1540
|
-
);
|
|
1541
|
-
poll = async (deviceCode, opts = {}) => {
|
|
1542
|
-
const parsed = await request(
|
|
1543
|
-
this.client,
|
|
1544
|
-
{
|
|
1545
|
-
method: "POST",
|
|
1546
|
-
path: "/v1/auth/device/poll",
|
|
1547
|
-
body: { deviceCode },
|
|
1548
|
-
signal: opts.signal
|
|
1549
|
-
},
|
|
1550
|
-
devicePollResponseSchema
|
|
1551
|
-
);
|
|
1552
|
-
if ("error" in parsed) {
|
|
1553
|
-
return parsed.error === "authorization_pending" ? {
|
|
1554
|
-
status: "pending",
|
|
1555
|
-
userCode: parsed.userCode,
|
|
1556
|
-
verificationUri: parsed.verificationUri
|
|
1557
|
-
} : { status: "expired" };
|
|
1343
|
+
var readClippedBytes = async (response, max) => {
|
|
1344
|
+
if (response.body === null) return new Uint8Array(0);
|
|
1345
|
+
const reader = response.body.getReader();
|
|
1346
|
+
const chunks = [];
|
|
1347
|
+
let total = 0;
|
|
1348
|
+
try {
|
|
1349
|
+
while (total < max) {
|
|
1350
|
+
const { done, value } = await reader.read();
|
|
1351
|
+
if (done) break;
|
|
1352
|
+
if (!value) continue;
|
|
1353
|
+
chunks.push(value);
|
|
1354
|
+
total += value.byteLength;
|
|
1558
1355
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1356
|
+
} finally {
|
|
1357
|
+
try {
|
|
1358
|
+
await reader.cancel();
|
|
1359
|
+
} catch {
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
const merged = new Uint8Array(Math.min(total, max));
|
|
1363
|
+
let offset = 0;
|
|
1364
|
+
for (const c of chunks) {
|
|
1365
|
+
const take = Math.min(c.byteLength, max - offset);
|
|
1366
|
+
merged.set(c.subarray(0, take), offset);
|
|
1367
|
+
offset += take;
|
|
1368
|
+
if (offset >= max) break;
|
|
1369
|
+
}
|
|
1370
|
+
return merged;
|
|
1567
1371
|
};
|
|
1568
|
-
var
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
if (typeof message.raw === "string") return message.raw;
|
|
1572
|
-
return viem.bytesToHex(message.raw);
|
|
1372
|
+
var readClippedText = async (response, max) => {
|
|
1373
|
+
const bytes = await readClippedBytes(response, max);
|
|
1374
|
+
return new TextDecoder().decode(bytes);
|
|
1573
1375
|
};
|
|
1574
|
-
var
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
);
|
|
1376
|
+
var parseResponseBody = async (response, max) => {
|
|
1377
|
+
const contentType = response.headers.get("content-type");
|
|
1378
|
+
const bytes = await readClippedBytes(response, max + 1);
|
|
1379
|
+
const truncated = bytes.byteLength > max;
|
|
1380
|
+
const view = truncated ? bytes.subarray(0, max) : bytes;
|
|
1381
|
+
const buf = Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
|
1382
|
+
if (!isTextContentType(contentType)) {
|
|
1383
|
+
const base64 = buf.toString("base64");
|
|
1384
|
+
return {
|
|
1385
|
+
body: base64,
|
|
1386
|
+
bodyRaw: base64,
|
|
1387
|
+
bodyEncoding: "base64",
|
|
1388
|
+
truncated
|
|
1389
|
+
};
|
|
1582
1390
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1391
|
+
const text = buf.toString("utf8");
|
|
1392
|
+
if (contentType?.toLowerCase().includes("json")) {
|
|
1393
|
+
try {
|
|
1394
|
+
return { body: JSON.parse(text), bodyRaw: text, truncated };
|
|
1395
|
+
} catch {
|
|
1396
|
+
}
|
|
1589
1397
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1398
|
+
return { body: text, bodyRaw: text, truncated };
|
|
1399
|
+
};
|
|
1400
|
+
var UPSTREAM_ERROR_FIELDS = [
|
|
1401
|
+
"error",
|
|
1402
|
+
"message",
|
|
1403
|
+
"detail",
|
|
1404
|
+
"reason",
|
|
1405
|
+
"error_description"
|
|
1406
|
+
];
|
|
1407
|
+
var UPSTREAM_ERROR_MAX_LEN = 200;
|
|
1408
|
+
var ERROR_SNIPPET_BYTES = 500;
|
|
1409
|
+
var clampUpstreamMessage = (value) => {
|
|
1410
|
+
const trimmed = value.trim();
|
|
1411
|
+
if (!trimmed) return void 0;
|
|
1412
|
+
return trimmed.length > UPSTREAM_ERROR_MAX_LEN ? `${trimmed.slice(0, UPSTREAM_ERROR_MAX_LEN)}\u2026` : trimmed;
|
|
1413
|
+
};
|
|
1414
|
+
var tryParseJson = (text) => {
|
|
1415
|
+
try {
|
|
1416
|
+
return JSON.parse(text);
|
|
1417
|
+
} catch {
|
|
1418
|
+
return null;
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
var extractUpstreamErrorMessage = (body) => {
|
|
1422
|
+
const parsed = tryParseJson(body);
|
|
1423
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
1424
|
+
return clampUpstreamMessage(body);
|
|
1425
|
+
}
|
|
1426
|
+
const record = parsed;
|
|
1427
|
+
for (const field of UPSTREAM_ERROR_FIELDS) {
|
|
1428
|
+
const value = record[field];
|
|
1429
|
+
if (typeof value === "string" && value.length > 0) {
|
|
1430
|
+
return clampUpstreamMessage(value);
|
|
1431
|
+
}
|
|
1432
|
+
if (value && typeof value === "object") {
|
|
1433
|
+
const nested = value.message;
|
|
1434
|
+
if (typeof nested === "string" && nested.length > 0) {
|
|
1435
|
+
return clampUpstreamMessage(nested);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
return void 0;
|
|
1440
|
+
};
|
|
1441
|
+
var buildUpstreamError = (status, bodyRaw, bodyEncoding) => {
|
|
1442
|
+
if (status >= 200 && status < 300) return void 0;
|
|
1443
|
+
if (bodyRaw === null || bodyRaw.length === 0) return void 0;
|
|
1444
|
+
if (bodyEncoding === "base64") return void 0;
|
|
1445
|
+
const snippet = bodyRaw.slice(0, ERROR_SNIPPET_BYTES);
|
|
1446
|
+
return {
|
|
1447
|
+
status,
|
|
1448
|
+
message: extractUpstreamErrorMessage(bodyRaw),
|
|
1449
|
+
snippetHash: crypto$1.createHash("sha256").update(snippet).digest("hex"),
|
|
1450
|
+
snippetLength: snippet.length
|
|
1451
|
+
};
|
|
1452
|
+
};
|
|
1453
|
+
var computeOutcome = (status, payment, warnings) => {
|
|
1454
|
+
if (warnings.includes(FETCH_WARNINGS.mppSessionCloseFailed))
|
|
1455
|
+
return "payment_close_failed";
|
|
1456
|
+
if (status === 402 && payment !== null) return "payment_rejected";
|
|
1457
|
+
if (status === 402) return "payment_failed";
|
|
1458
|
+
if (status >= 400) return "server_error";
|
|
1459
|
+
return "success";
|
|
1460
|
+
};
|
|
1461
|
+
var errorFetchResult = (startedAt, error, skipReason, capabilityIdRequested, outcome, status = null) => {
|
|
1462
|
+
const result = {
|
|
1463
|
+
runId: null,
|
|
1464
|
+
ok: false,
|
|
1465
|
+
status,
|
|
1466
|
+
latencyMs: Date.now() - startedAt,
|
|
1467
|
+
payment: null,
|
|
1468
|
+
outcome,
|
|
1469
|
+
body: null,
|
|
1470
|
+
bodyRaw: null,
|
|
1471
|
+
error
|
|
1472
|
+
};
|
|
1473
|
+
if (capabilityIdRequested) result.runTrackingSkipped = [skipReason];
|
|
1474
|
+
return result;
|
|
1475
|
+
};
|
|
1476
|
+
var resolveRecordingClient = (client, opts) => {
|
|
1477
|
+
const credentials = client.getCredentials();
|
|
1478
|
+
const recordingClient = opts.account ? client.withAccount(opts.account) : client;
|
|
1479
|
+
const canRecord = opts.account !== void 0 || credentials.kind === "account" || credentials.kind === "session";
|
|
1480
|
+
return { recordingClient, canRecord };
|
|
1481
|
+
};
|
|
1482
|
+
var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride) => {
|
|
1483
|
+
const effectiveCapId = opts.capabilityId;
|
|
1484
|
+
if (effectiveCapId === void 0) return;
|
|
1485
|
+
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
1486
|
+
if (!canRecord) return;
|
|
1487
|
+
const fetchOriginForRecord = opts.capabilityId === void 0 ? "direct_url" : isShortToken(effectiveCapId) ? "from_search" : opts.fetchOrigin;
|
|
1488
|
+
try {
|
|
1489
|
+
const created = await recordingClient.runs.create({
|
|
1490
|
+
capabilityId: effectiveCapId,
|
|
1491
|
+
...opts.searchId && { searchId: opts.searchId },
|
|
1492
|
+
...fetchOriginForRecord && { fetchOrigin: fetchOriginForRecord },
|
|
1493
|
+
...result.status !== null && { status: result.status },
|
|
1494
|
+
latencyMs: result.latencyMs,
|
|
1495
|
+
...opts.requestSchema && { requestSchema: opts.requestSchema }
|
|
1496
|
+
});
|
|
1497
|
+
result.runId = created.runId;
|
|
1498
|
+
delete result.runTrackingSkipped;
|
|
1499
|
+
} catch {
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested, capabilityIdOverride) => {
|
|
1503
|
+
const result = errorFetchResult(
|
|
1504
|
+
startedAt,
|
|
1505
|
+
err.message,
|
|
1506
|
+
"timeout",
|
|
1507
|
+
capabilityIdRequested,
|
|
1508
|
+
"network_error"
|
|
1605
1509
|
);
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1510
|
+
await recordErrorFetchRun(client, opts, result);
|
|
1511
|
+
};
|
|
1512
|
+
var sniffJsonShapeBytes = (buf) => {
|
|
1513
|
+
let i = 0;
|
|
1514
|
+
if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
|
|
1515
|
+
i = 3;
|
|
1516
|
+
}
|
|
1517
|
+
while (i < buf.length && (buf[i] === 32 || buf[i] === 9 || buf[i] === 10 || buf[i] === 13)) {
|
|
1518
|
+
i++;
|
|
1519
|
+
}
|
|
1520
|
+
if (i >= buf.length) return false;
|
|
1521
|
+
return buf[i] === 123 || buf[i] === 91;
|
|
1522
|
+
};
|
|
1523
|
+
var withDefaultContentType = (headers, body) => {
|
|
1524
|
+
if (!headers && body === void 0) return void 0;
|
|
1525
|
+
const next = headers ? { ...headers } : {};
|
|
1526
|
+
if (body === void 0) return next;
|
|
1527
|
+
const hasContentType = Object.keys(next).some(
|
|
1528
|
+
(k) => k.toLowerCase() === "content-type"
|
|
1613
1529
|
);
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1530
|
+
if (!hasContentType) {
|
|
1531
|
+
next["content-type"] = typeof body === "string" || sniffJsonShapeBytes(body) ? "application/json" : "application/octet-stream";
|
|
1532
|
+
}
|
|
1533
|
+
return next;
|
|
1534
|
+
};
|
|
1535
|
+
var clientFetch = async (client, url, opts = {}) => {
|
|
1536
|
+
const startedAt = Date.now();
|
|
1537
|
+
const capabilityIdRequested = opts.capabilityId !== void 0;
|
|
1538
|
+
const normalized = normalizeTransportEnvelopeRequest(url, {
|
|
1539
|
+
method: opts.method,
|
|
1540
|
+
body: opts.body
|
|
1541
|
+
});
|
|
1542
|
+
const requestUrl = normalized.url;
|
|
1543
|
+
const requestBody = normalized.body;
|
|
1544
|
+
const method = normalized.method ?? (requestBody !== void 0 ? "POST" : "GET");
|
|
1545
|
+
const { canRecord: canRecordForResolve } = resolveRecordingClient(
|
|
1546
|
+
client,
|
|
1547
|
+
opts
|
|
1626
1548
|
);
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
await request(
|
|
1635
|
-
this.client,
|
|
1636
|
-
{
|
|
1637
|
-
method: "POST",
|
|
1638
|
-
path: "/v1/auth/logout",
|
|
1639
|
-
body: { refreshToken },
|
|
1640
|
-
signal: opts.signal
|
|
1641
|
-
},
|
|
1642
|
-
zod.z.unknown()
|
|
1643
|
-
);
|
|
1549
|
+
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl(requestUrl), method).catch(() => null) : Promise.resolve(null);
|
|
1550
|
+
const probeHeaders = withDefaultContentType(opts.headers, requestBody);
|
|
1551
|
+
const requestInit = {
|
|
1552
|
+
method,
|
|
1553
|
+
headers: probeHeaders,
|
|
1554
|
+
body: requestBody,
|
|
1555
|
+
signal: opts.signal
|
|
1644
1556
|
};
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1557
|
+
const configuredFetch = buildConfiguredFetch(client, {
|
|
1558
|
+
timeoutMs: opts.timeoutMs
|
|
1559
|
+
});
|
|
1560
|
+
let response;
|
|
1561
|
+
let payment = null;
|
|
1562
|
+
const skipReasons = [];
|
|
1563
|
+
const warnings = [];
|
|
1564
|
+
try {
|
|
1565
|
+
response = await configuredFetch(requestUrl, requestInit);
|
|
1566
|
+
} catch (err) {
|
|
1567
|
+
if (err instanceof ZeroTimeoutError) {
|
|
1568
|
+
await recordTimeoutRun(
|
|
1569
|
+
client,
|
|
1570
|
+
opts,
|
|
1571
|
+
err,
|
|
1572
|
+
startedAt,
|
|
1573
|
+
capabilityIdRequested
|
|
1662
1574
|
);
|
|
1575
|
+
throw err;
|
|
1663
1576
|
}
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
const
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1577
|
+
if (err instanceof ZeroError) throw err;
|
|
1578
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
1579
|
+
const result2 = errorFetchResult(
|
|
1580
|
+
startedAt,
|
|
1581
|
+
errMessage,
|
|
1582
|
+
"fetch_failed_before_response",
|
|
1583
|
+
capabilityIdRequested,
|
|
1584
|
+
"network_error"
|
|
1585
|
+
);
|
|
1586
|
+
await recordErrorFetchRun(client, opts, result2);
|
|
1587
|
+
return result2;
|
|
1588
|
+
}
|
|
1589
|
+
if (response.status === 402) {
|
|
1590
|
+
const requirement = await detectPaymentRequirement(response);
|
|
1591
|
+
if (requirement?.protocol === "x402" || requirement?.protocol === "mpp") {
|
|
1592
|
+
const payCall = requirement.protocol === "x402" ? client.payments.pay : client.payments.payMpp;
|
|
1671
1593
|
try {
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1594
|
+
const paid = await payCall({
|
|
1595
|
+
url: requestUrl,
|
|
1596
|
+
method,
|
|
1597
|
+
// Fresh clone for the paid retry — same rationale as
|
|
1598
|
+
// the probe-side clone above. Re-derives the default
|
|
1599
|
+
// Content-Type so the paid leg matches the probe.
|
|
1600
|
+
headers: withDefaultContentType(opts.headers, requestBody),
|
|
1601
|
+
body: requestBody,
|
|
1602
|
+
maxPay: opts.maxPay,
|
|
1603
|
+
account: opts.account,
|
|
1604
|
+
signal: opts.signal,
|
|
1605
|
+
timeoutMs: opts.timeoutMs,
|
|
1606
|
+
...opts.displayCostAmount && {
|
|
1607
|
+
displayCostAmount: opts.displayCostAmount
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
response = paid.response;
|
|
1611
|
+
payment = paid.payment;
|
|
1612
|
+
if (paid.warnings) warnings.push(...paid.warnings);
|
|
1683
1613
|
} catch (err) {
|
|
1684
|
-
|
|
1614
|
+
if (err instanceof ZeroSessionCloseFailedError) {
|
|
1615
|
+
response = err.response;
|
|
1616
|
+
payment = {
|
|
1617
|
+
protocol: "mpp",
|
|
1618
|
+
chain: tempoChainLabelFromId(err.session.chainId),
|
|
1619
|
+
txHash: null,
|
|
1620
|
+
amount: err.capturedAmount,
|
|
1621
|
+
asset: "USDC",
|
|
1622
|
+
session: err.session
|
|
1623
|
+
};
|
|
1624
|
+
warnings.push(FETCH_WARNINGS.mppSessionCloseFailed);
|
|
1625
|
+
} else if (err instanceof ZeroInsufficientFundsError) {
|
|
1626
|
+
return errorFetchResult(
|
|
1627
|
+
startedAt,
|
|
1628
|
+
err.message,
|
|
1629
|
+
FETCH_SKIP_REASONS.insufficientFunds,
|
|
1630
|
+
capabilityIdRequested,
|
|
1631
|
+
"insufficient_funds",
|
|
1632
|
+
null
|
|
1633
|
+
);
|
|
1634
|
+
} else if (err instanceof ZeroPaymentError || err instanceof ZeroAuthError) {
|
|
1635
|
+
const result2 = errorFetchResult(
|
|
1636
|
+
startedAt,
|
|
1637
|
+
err.message,
|
|
1638
|
+
"payment_failed",
|
|
1639
|
+
capabilityIdRequested,
|
|
1640
|
+
"payment_failed",
|
|
1641
|
+
402
|
|
1642
|
+
);
|
|
1643
|
+
await recordErrorFetchRun(client, opts, result2);
|
|
1644
|
+
return result2;
|
|
1645
|
+
} else if (err instanceof ZeroTimeoutError) {
|
|
1646
|
+
await recordTimeoutRun(
|
|
1647
|
+
client,
|
|
1648
|
+
opts,
|
|
1649
|
+
err,
|
|
1650
|
+
startedAt,
|
|
1651
|
+
capabilityIdRequested
|
|
1652
|
+
);
|
|
1653
|
+
throw err;
|
|
1654
|
+
} else {
|
|
1655
|
+
throw err;
|
|
1656
|
+
}
|
|
1685
1657
|
}
|
|
1658
|
+
} else if (requirement?.protocol === "unknown") {
|
|
1659
|
+
const result2 = errorFetchResult(
|
|
1660
|
+
startedAt,
|
|
1661
|
+
"Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
|
|
1662
|
+
"unrecognized_402_protocol",
|
|
1663
|
+
capabilityIdRequested,
|
|
1664
|
+
"payment_failed",
|
|
1665
|
+
402
|
|
1666
|
+
);
|
|
1667
|
+
await recordErrorFetchRun(client, opts, result2);
|
|
1668
|
+
return result2;
|
|
1686
1669
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
const
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
);
|
|
1706
|
-
this.assertSignerMatches(parsed.walletAddress, opts.expectedAddress);
|
|
1707
|
-
return parsed.signature;
|
|
1708
|
-
} catch (err) {
|
|
1709
|
-
repackageSignFailure(err, "signTransaction");
|
|
1710
|
-
}
|
|
1670
|
+
}
|
|
1671
|
+
const latencyMs = Date.now() - startedAt;
|
|
1672
|
+
const maxResponseBytes = opts.maxResponseBytes ?? MAX_RESPONSE_BYTES;
|
|
1673
|
+
let body;
|
|
1674
|
+
let bodyRaw;
|
|
1675
|
+
let bodyEncoding;
|
|
1676
|
+
try {
|
|
1677
|
+
const parsed = await parseResponseBody(response, maxResponseBytes);
|
|
1678
|
+
body = parsed.body;
|
|
1679
|
+
bodyRaw = parsed.bodyRaw;
|
|
1680
|
+
bodyEncoding = parsed.bodyEncoding;
|
|
1681
|
+
if (parsed.truncated) warnings.push(FETCH_WARNINGS.bodyTruncated);
|
|
1682
|
+
} catch (err) {
|
|
1683
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
1684
|
+
throw new ZeroApiError("Request aborted by caller", {
|
|
1685
|
+
status: 0,
|
|
1686
|
+
cause: err
|
|
1687
|
+
});
|
|
1711
1688
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
);
|
|
1689
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1690
|
+
const skips = [];
|
|
1691
|
+
const settledLocally = paymentHasAnchor(payment);
|
|
1692
|
+
if (settledLocally && response.status === 402) {
|
|
1693
|
+
warnings.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
1694
|
+
skips.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
1717
1695
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
);
|
|
1722
|
-
};
|
|
1723
|
-
signTypedData = async (input, opts = {}) => {
|
|
1724
|
-
const credentials = this.client.getCredentials();
|
|
1725
|
-
if (credentials.kind === "account") {
|
|
1726
|
-
if (!credentials.account.signTypedData) {
|
|
1727
|
-
throw new ZeroAuthError(
|
|
1728
|
-
"auth_error",
|
|
1729
|
-
"The configured viem account does not implement signTypedData."
|
|
1730
|
-
);
|
|
1731
|
-
}
|
|
1732
|
-
return await credentials.account.signTypedData(input);
|
|
1696
|
+
if (payment !== null && !settledLocally) {
|
|
1697
|
+
warnings.push(FETCH_WARNINGS.paymentSettlementUnconfirmed);
|
|
1698
|
+
skips.push(FETCH_WARNINGS.paymentSettlementUnconfirmed);
|
|
1733
1699
|
}
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1736
|
-
const parsed = await request(
|
|
1737
|
-
this.client,
|
|
1738
|
-
{
|
|
1739
|
-
method: "POST",
|
|
1740
|
-
path: "/v1/users/me/sign-typed-data",
|
|
1741
|
-
body: { typedData: input }
|
|
1742
|
-
},
|
|
1743
|
-
signResponseSchema
|
|
1744
|
-
);
|
|
1745
|
-
this.assertSignerMatches(parsed.walletAddress, opts.expectedAddress);
|
|
1746
|
-
return parsed.signature;
|
|
1747
|
-
} catch (err) {
|
|
1748
|
-
repackageSignFailure(err, "signTypedData");
|
|
1749
|
-
}
|
|
1700
|
+
if (payment !== null && payment.amount === "unknown") {
|
|
1701
|
+
warnings.push(FETCH_WARNINGS.paymentAmountUnknown);
|
|
1750
1702
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
if (
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
"auth_error",
|
|
1767
|
-
`Managed signing wallet changed (caller expected ${canonicalExpected}, server signed as ${canonicalServer}). Cache cleared \u2014 retry to rebuild against the current wallet.`
|
|
1768
|
-
);
|
|
1769
|
-
};
|
|
1770
|
-
};
|
|
1771
|
-
var BUG_REPORT_CATEGORIES = [
|
|
1772
|
-
"search_relevance",
|
|
1773
|
-
"ranking_issue",
|
|
1774
|
-
"missing_capability",
|
|
1775
|
-
"wrong_schema",
|
|
1776
|
-
"misleading_description",
|
|
1777
|
-
"broken_execution",
|
|
1778
|
-
"payment_failure",
|
|
1779
|
-
"billing_anomaly",
|
|
1780
|
-
"cli_bug",
|
|
1781
|
-
"security",
|
|
1782
|
-
"other"
|
|
1783
|
-
];
|
|
1784
|
-
var createBugReportResponseSchema = zod.z.object({
|
|
1785
|
-
bugReportId: zod.z.string(),
|
|
1786
|
-
status: zod.z.string(),
|
|
1787
|
-
deduped: zod.z.boolean(),
|
|
1788
|
-
category: zod.z.enum(BUG_REPORT_CATEGORIES).nullable(),
|
|
1789
|
-
title: zod.z.string().nullable(),
|
|
1790
|
-
attached: zod.z.object({
|
|
1791
|
-
capabilityId: zod.z.number().nullable(),
|
|
1792
|
-
runId: zod.z.number().nullable(),
|
|
1793
|
-
searchId: zod.z.number().nullable()
|
|
1794
|
-
})
|
|
1795
|
-
});
|
|
1796
|
-
|
|
1797
|
-
// src/namespaces/bug-reports.ts
|
|
1798
|
-
var BugReports = class {
|
|
1799
|
-
constructor(client) {
|
|
1800
|
-
this.client = client;
|
|
1703
|
+
skips.push(FETCH_SKIP_REASONS.bodyReadFailed);
|
|
1704
|
+
const result2 = {
|
|
1705
|
+
runId: null,
|
|
1706
|
+
ok: false,
|
|
1707
|
+
status: response.status,
|
|
1708
|
+
latencyMs: Date.now() - startedAt,
|
|
1709
|
+
payment,
|
|
1710
|
+
outcome: computeOutcome(response.status, payment, warnings),
|
|
1711
|
+
body: null,
|
|
1712
|
+
bodyRaw: null,
|
|
1713
|
+
error: message
|
|
1714
|
+
};
|
|
1715
|
+
if (capabilityIdRequested) result2.runTrackingSkipped = skips;
|
|
1716
|
+
if (warnings.length > 0) result2.warnings = warnings;
|
|
1717
|
+
return result2;
|
|
1801
1718
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
body: input,
|
|
1811
|
-
signal: opts.signal
|
|
1812
|
-
},
|
|
1813
|
-
createBugReportResponseSchema
|
|
1814
|
-
);
|
|
1815
|
-
};
|
|
1816
|
-
var ratingSchema = zod.z.object({
|
|
1817
|
-
score: zod.z.string(),
|
|
1818
|
-
successRate: zod.z.string(),
|
|
1819
|
-
reviews: zod.z.number(),
|
|
1820
|
-
stars: zod.z.string().nullable().optional(),
|
|
1821
|
-
state: zod.z.enum(["unrated", "rated"]).optional()
|
|
1822
|
-
});
|
|
1823
|
-
|
|
1824
|
-
// src/schemas/capabilities.ts
|
|
1825
|
-
var capabilityResponseSchema = zod.z.object({
|
|
1826
|
-
uid: zod.z.string(),
|
|
1827
|
-
slug: zod.z.string(),
|
|
1828
|
-
name: zod.z.string(),
|
|
1829
|
-
description: zod.z.string(),
|
|
1830
|
-
url: zod.z.string(),
|
|
1831
|
-
urlTemplate: zod.z.string().nullable().optional(),
|
|
1832
|
-
method: zod.z.string(),
|
|
1833
|
-
headers: zod.z.record(zod.z.string(), zod.z.string()).nullable(),
|
|
1834
|
-
bodySchema: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
|
|
1835
|
-
responseSchema: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
|
|
1836
|
-
example: zod.z.object({ request: zod.z.unknown(), response: zod.z.unknown() }).nullable(),
|
|
1837
|
-
tags: zod.z.array(zod.z.string()).nullable(),
|
|
1838
|
-
exampleAgentPrompt: zod.z.string().nullable().optional(),
|
|
1839
|
-
displayCostAmount: zod.z.string(),
|
|
1840
|
-
displayCostAsset: zod.z.string(),
|
|
1841
|
-
reviewCount: zod.z.number(),
|
|
1842
|
-
rating: ratingSchema,
|
|
1843
|
-
priceObserved: zod.z.object({
|
|
1844
|
-
minCents: zod.z.string().nullable(),
|
|
1845
|
-
medianCents: zod.z.string().nullable(),
|
|
1846
|
-
maxCents: zod.z.string().nullable(),
|
|
1847
|
-
// Deprecated alias for maxCents; kept for back-compat with older
|
|
1848
|
-
// API versions that still emit it.
|
|
1849
|
-
p95Cents: zod.z.string().nullable(),
|
|
1850
|
-
sampleCount: zod.z.number(),
|
|
1851
|
-
varies: zod.z.boolean(),
|
|
1852
|
-
failureChargeRate: zod.z.number().nullable()
|
|
1853
|
-
}).nullable().optional(),
|
|
1854
|
-
paymentMethods: zod.z.array(
|
|
1855
|
-
zod.z.object({
|
|
1856
|
-
uid: zod.z.string(),
|
|
1857
|
-
protocol: zod.z.string(),
|
|
1858
|
-
methodType: zod.z.string(),
|
|
1859
|
-
chain: zod.z.string().nullable(),
|
|
1860
|
-
mode: zod.z.string(),
|
|
1861
|
-
costAmount: zod.z.string(),
|
|
1862
|
-
costPer: zod.z.string(),
|
|
1863
|
-
priority: zod.z.number()
|
|
1864
|
-
})
|
|
1865
|
-
).nullable(),
|
|
1866
|
-
availabilityStatus: zod.z.enum(["healthy", "unknown", "down"]).nullable().optional(),
|
|
1867
|
-
/**
|
|
1868
|
-
* @deprecated The API no longer emits `displayStatus`; it has been replaced
|
|
1869
|
-
* by the consolidated 3-value {@link capabilityResponseSchema.shape.availabilityStatus}.
|
|
1870
|
-
* Kept as an optional field for one release for back-compat (ZERO-89 soft
|
|
1871
|
-
* migration) and will be removed in the next major version.
|
|
1872
|
-
*/
|
|
1873
|
-
displayStatus: zod.z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
|
|
1874
|
-
activationCount: zod.z.number().optional(),
|
|
1875
|
-
lastUsedAt: zod.z.string().nullable().optional(),
|
|
1876
|
-
lastSuccessfullyRanAt: zod.z.string().nullable().optional()
|
|
1877
|
-
});
|
|
1878
|
-
var resolveCapabilityResponseSchema = zod.z.object({
|
|
1879
|
-
capabilityId: zod.z.string(),
|
|
1880
|
-
capabilitySlug: zod.z.string(),
|
|
1881
|
-
matchedVia: zod.z.enum(["exact", "template"])
|
|
1882
|
-
});
|
|
1883
|
-
|
|
1884
|
-
// src/namespaces/capabilities.ts
|
|
1885
|
-
var Capabilities = class {
|
|
1886
|
-
constructor(client) {
|
|
1887
|
-
this.client = client;
|
|
1719
|
+
const settled = paymentHasAnchor(payment);
|
|
1720
|
+
const paidButStill402 = settled && response.status === 402;
|
|
1721
|
+
const settlementUnconfirmed = payment !== null && !settled;
|
|
1722
|
+
if (paidButStill402) warnings.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
1723
|
+
if (settlementUnconfirmed)
|
|
1724
|
+
warnings.push(FETCH_WARNINGS.paymentSettlementUnconfirmed);
|
|
1725
|
+
if (payment !== null && payment.amount === "unknown") {
|
|
1726
|
+
warnings.push(FETCH_WARNINGS.paymentAmountUnknown);
|
|
1888
1727
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
signal: opts.signal
|
|
1896
|
-
},
|
|
1897
|
-
capabilityResponseSchema
|
|
1728
|
+
let runId = null;
|
|
1729
|
+
const closeFailed = warnings.includes(FETCH_WARNINGS.mppSessionCloseFailed);
|
|
1730
|
+
const upstreamErrorForRecord = buildUpstreamError(
|
|
1731
|
+
response.status,
|
|
1732
|
+
bodyRaw,
|
|
1733
|
+
bodyEncoding
|
|
1898
1734
|
);
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1735
|
+
if (capabilityIdRequested) {
|
|
1736
|
+
if (paidButStill402)
|
|
1737
|
+
skipReasons.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
1738
|
+
else if (closeFailed)
|
|
1739
|
+
skipReasons.push(FETCH_SKIP_REASONS.mppSessionCloseFailedNotRecorded);
|
|
1740
|
+
}
|
|
1741
|
+
const resolvedCap = await resolvePromise;
|
|
1742
|
+
const effectiveCapabilityId = opts.capabilityId ?? resolvedCap?.capabilityId;
|
|
1743
|
+
const capabilityResolution = !capabilityIdRequested && canRecordForResolve ? resolvedCap !== null ? {
|
|
1744
|
+
resolved: true,
|
|
1745
|
+
capabilityId: resolvedCap.capabilityId,
|
|
1746
|
+
capabilitySlug: resolvedCap.capabilitySlug,
|
|
1747
|
+
matchedVia: resolvedCap.matchedVia
|
|
1748
|
+
} : { resolved: false } : void 0;
|
|
1749
|
+
if (effectiveCapabilityId !== void 0 && !paidButStill402 && !closeFailed) {
|
|
1750
|
+
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
1751
|
+
if (!canRecord) {
|
|
1752
|
+
skipReasons.push("no_credentials");
|
|
1753
|
+
} else {
|
|
1754
|
+
const knownAmount = payment !== null && payment.amount !== "unknown";
|
|
1755
|
+
try {
|
|
1756
|
+
let derived;
|
|
1757
|
+
if (opts.deriveRunMetadata) {
|
|
1758
|
+
try {
|
|
1759
|
+
derived = opts.deriveRunMetadata({
|
|
1760
|
+
status: response.status,
|
|
1761
|
+
ok: response.ok,
|
|
1762
|
+
bodyRaw,
|
|
1763
|
+
...bodyEncoding && { bodyEncoding }
|
|
1764
|
+
});
|
|
1765
|
+
} catch {
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
const result2 = await recordingClient.runs.create({
|
|
1769
|
+
capabilityId: effectiveCapabilityId,
|
|
1770
|
+
searchId: opts.searchId,
|
|
1771
|
+
// Auto-resolved runs are always direct_url — they only fire when
|
|
1772
|
+
// no capabilityId was supplied (the direct_url path by definition).
|
|
1773
|
+
...opts.capabilityId === void 0 ? { fetchOrigin: "direct_url" } : opts.fetchOrigin && { fetchOrigin: opts.fetchOrigin },
|
|
1774
|
+
status: response.status,
|
|
1775
|
+
latencyMs,
|
|
1776
|
+
...opts.requestSchema && { requestSchema: opts.requestSchema },
|
|
1777
|
+
...derived?.responseSchema && {
|
|
1778
|
+
responseSchema: derived.responseSchema
|
|
1779
|
+
},
|
|
1780
|
+
...upstreamErrorForRecord && {
|
|
1781
|
+
errorSnippetHash: upstreamErrorForRecord.snippetHash,
|
|
1782
|
+
errorSnippetLength: upstreamErrorForRecord.snippetLength
|
|
1783
|
+
},
|
|
1784
|
+
...payment && {
|
|
1785
|
+
...knownAmount && {
|
|
1786
|
+
costAmount: payment.amount,
|
|
1787
|
+
costAsset: payment.asset
|
|
1788
|
+
},
|
|
1789
|
+
paymentProtocol: payment.protocol,
|
|
1790
|
+
paymentChain: payment.chain,
|
|
1791
|
+
paymentTxHash: payment.txHash ?? void 0,
|
|
1792
|
+
paymentMode: payment.session ? "session" : "charge"
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
runId = result2.runId;
|
|
1796
|
+
} catch (err) {
|
|
1797
|
+
const errorMessage2 = err instanceof Error ? err.message : String(err);
|
|
1798
|
+
const code = err instanceof ZeroError ? err.code : void 0;
|
|
1799
|
+
const skipMsg = code ? `run_create_failed:${code}: ${errorMessage2}` : `run_create_failed: ${errorMessage2}`;
|
|
1800
|
+
skipReasons.push(skipMsg);
|
|
1801
|
+
client.logger?.({
|
|
1802
|
+
level: "warn",
|
|
1803
|
+
message: "Failed to record run for fetch",
|
|
1804
|
+
meta: {
|
|
1805
|
+
url: redactUrl(url),
|
|
1806
|
+
capabilityId: effectiveCapabilityId,
|
|
1807
|
+
error: errorMessage2,
|
|
1808
|
+
errorCode: code
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1922
1812
|
}
|
|
1813
|
+
}
|
|
1814
|
+
const result = {
|
|
1815
|
+
runId,
|
|
1816
|
+
ok: response.ok,
|
|
1817
|
+
status: response.status,
|
|
1818
|
+
latencyMs,
|
|
1819
|
+
payment,
|
|
1820
|
+
outcome: computeOutcome(response.status, payment, warnings),
|
|
1821
|
+
body,
|
|
1822
|
+
bodyRaw
|
|
1923
1823
|
};
|
|
1824
|
+
if (bodyEncoding) result.bodyEncoding = bodyEncoding;
|
|
1825
|
+
if (!response.ok) {
|
|
1826
|
+
const candidate = bodyRaw !== null && bodyRaw.length > 0 && bodyEncoding !== "base64" ? bodyRaw.slice(0, 240) : null;
|
|
1827
|
+
result.error = candidate !== null && !requestBodyEchoed(candidate, opts.body) ? candidate : `HTTP ${response.status}`;
|
|
1828
|
+
if (upstreamErrorForRecord) result.upstreamError = upstreamErrorForRecord;
|
|
1829
|
+
}
|
|
1830
|
+
if (capabilityIdRequested && skipReasons.length > 0) {
|
|
1831
|
+
result.runTrackingSkipped = skipReasons;
|
|
1832
|
+
}
|
|
1833
|
+
if (warnings.length > 0) result.warnings = warnings;
|
|
1834
|
+
if (capabilityResolution !== void 0)
|
|
1835
|
+
result.capabilityResolution = capabilityResolution;
|
|
1836
|
+
return result;
|
|
1924
1837
|
};
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
}).nullable(),
|
|
1942
|
-
createdAt: zod.z.coerce.date(),
|
|
1943
|
-
reviewed: zod.z.boolean()
|
|
1838
|
+
|
|
1839
|
+
// package.json
|
|
1840
|
+
var package_default = {
|
|
1841
|
+
version: "0.7.0"};
|
|
1842
|
+
|
|
1843
|
+
// src/version.ts
|
|
1844
|
+
var SDK_VERSION = package_default.version;
|
|
1845
|
+
var userWalletDtoSchema = zod.z.object({
|
|
1846
|
+
walletAddress: zod.z.string(),
|
|
1847
|
+
source: zod.z.enum(["self_custody", "privy_embedded"]),
|
|
1848
|
+
isPrimary: zod.z.boolean(),
|
|
1849
|
+
linkedAt: zod.z.union([zod.z.string(), zod.z.date()]).nullable().optional(),
|
|
1850
|
+
delegationGranted: zod.z.boolean(),
|
|
1851
|
+
signerQuorumId: zod.z.string().nullable(),
|
|
1852
|
+
// Per-transaction USDC cap in base units (6 dp). null = unlimited, 0 = free-only.
|
|
1853
|
+
maxTransactionUsdcBaseUnits: zod.z.number().int().nullable()
|
|
1944
1854
|
});
|
|
1945
|
-
var
|
|
1946
|
-
|
|
1947
|
-
|
|
1855
|
+
var welcomeBonusSummarySchema = zod.z.object({
|
|
1856
|
+
status: zod.z.string(),
|
|
1857
|
+
amountUsd: zod.z.number()
|
|
1948
1858
|
});
|
|
1949
|
-
var
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
slug: zod.z.string(),
|
|
1965
|
-
name: zod.z.string(),
|
|
1966
|
-
url: zod.z.string(),
|
|
1967
|
-
method: zod.z.string(),
|
|
1968
|
-
whatItDoes: zod.z.string().nullable(),
|
|
1969
|
-
tags: zod.z.array(zod.z.string())
|
|
1859
|
+
var internalUserDtoSchema = zod.z.object({
|
|
1860
|
+
id: zod.z.string(),
|
|
1861
|
+
email: zod.z.string().nullable(),
|
|
1862
|
+
createdAt: zod.z.union([zod.z.string(), zod.z.date()]).optional(),
|
|
1863
|
+
lastLoginAt: zod.z.union([zod.z.string(), zod.z.date()]).nullable().optional(),
|
|
1864
|
+
onboardingCompleted: zod.z.boolean().optional(),
|
|
1865
|
+
delegationGranted: zod.z.boolean().optional(),
|
|
1866
|
+
wallets: zod.z.array(userWalletDtoSchema).optional(),
|
|
1867
|
+
balance: zod.z.object({ amount: zod.z.string(), asset: zod.z.string() }).nullable().optional(),
|
|
1868
|
+
welcomeBonus: welcomeBonusSummarySchema.nullable().optional()
|
|
1869
|
+
});
|
|
1870
|
+
var publicUserDtoSchema = zod.z.object({
|
|
1871
|
+
user: zod.z.object({
|
|
1872
|
+
id: zod.z.string(),
|
|
1873
|
+
email: zod.z.string().nullable()
|
|
1970
1874
|
}),
|
|
1971
|
-
|
|
1875
|
+
walletAddress: zod.z.string().nullable(),
|
|
1876
|
+
balance: zod.z.object({ amount: zod.z.string(), asset: zod.z.string() }).nullable(),
|
|
1877
|
+
welcomeBonus: welcomeBonusSummarySchema.nullable()
|
|
1972
1878
|
});
|
|
1973
|
-
var
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
updated: zod.z.boolean().optional()
|
|
1879
|
+
var signResponseSchema = zod.z.object({
|
|
1880
|
+
signature: zod.z.string().regex(/^0x[0-9a-fA-F]+$/, "must be 0x-prefixed hex"),
|
|
1881
|
+
walletAddress: zod.z.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be 0x-prefixed 40-char hex address")
|
|
1977
1882
|
});
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
),
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1883
|
+
|
|
1884
|
+
// src/schemas/device.ts
|
|
1885
|
+
var deviceStartResponseSchema = zod.z.object({
|
|
1886
|
+
deviceCode: zod.z.string(),
|
|
1887
|
+
userCode: zod.z.string(),
|
|
1888
|
+
verificationUri: zod.z.string(),
|
|
1889
|
+
pollInterval: zod.z.number(),
|
|
1890
|
+
expiresAt: zod.z.number()
|
|
1891
|
+
});
|
|
1892
|
+
var devicePollResponseSchema = zod.z.union([
|
|
1893
|
+
// userCode + verificationUri are optional: older API deployments don't
|
|
1894
|
+
// echo them on pending.
|
|
1895
|
+
zod.z.object({
|
|
1896
|
+
error: zod.z.literal("authorization_pending"),
|
|
1897
|
+
userCode: zod.z.string().optional(),
|
|
1898
|
+
verificationUri: zod.z.string().optional()
|
|
1899
|
+
}),
|
|
1900
|
+
zod.z.object({ error: zod.z.literal("expired_token") }),
|
|
1901
|
+
zod.z.object({
|
|
1902
|
+
accessToken: zod.z.string(),
|
|
1903
|
+
refreshToken: zod.z.string(),
|
|
1904
|
+
expiresIn: zod.z.number(),
|
|
1905
|
+
user: internalUserDtoSchema
|
|
1999
1906
|
})
|
|
1907
|
+
]);
|
|
1908
|
+
var sessionExchangeResponseSchema = zod.z.object({
|
|
1909
|
+
token: zod.z.string(),
|
|
1910
|
+
expiresAt: zod.z.number()
|
|
1911
|
+
});
|
|
1912
|
+
var refreshResponseSchema = zod.z.object({
|
|
1913
|
+
accessToken: zod.z.string(),
|
|
1914
|
+
refreshToken: zod.z.string()
|
|
1915
|
+
});
|
|
1916
|
+
var tryRefreshSession = async (client, callerSignal) => {
|
|
1917
|
+
const credentials = client.getCredentials();
|
|
1918
|
+
if (credentials.kind !== "session") return false;
|
|
1919
|
+
if (!credentials.refreshToken) return false;
|
|
1920
|
+
const url = `${client.baseUrl.replace(/\/$/, "")}/v1/auth/refresh`;
|
|
1921
|
+
const timeoutSignal = AbortSignal.timeout(client.timeout);
|
|
1922
|
+
const signal = callerSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : timeoutSignal;
|
|
1923
|
+
let response;
|
|
1924
|
+
try {
|
|
1925
|
+
response = await client.fetchImpl(url, {
|
|
1926
|
+
method: "POST",
|
|
1927
|
+
headers: { "content-type": "application/json" },
|
|
1928
|
+
body: JSON.stringify({ refreshToken: credentials.refreshToken }),
|
|
1929
|
+
signal
|
|
1930
|
+
});
|
|
1931
|
+
} catch {
|
|
1932
|
+
return false;
|
|
1933
|
+
}
|
|
1934
|
+
if (!response.ok) return false;
|
|
1935
|
+
let body;
|
|
1936
|
+
try {
|
|
1937
|
+
body = await response.json();
|
|
1938
|
+
} catch {
|
|
1939
|
+
return false;
|
|
1940
|
+
}
|
|
1941
|
+
const parsed = refreshResponseSchema.safeParse(body);
|
|
1942
|
+
if (!parsed.success) return false;
|
|
1943
|
+
await client.applyRefreshedTokens({
|
|
1944
|
+
accessToken: parsed.data.accessToken,
|
|
1945
|
+
refreshToken: parsed.data.refreshToken
|
|
1946
|
+
});
|
|
1947
|
+
return true;
|
|
1948
|
+
};
|
|
1949
|
+
var buildSessionAuthHeaders = (accessToken) => ({
|
|
1950
|
+
authorization: `Bearer ${accessToken}`
|
|
2000
1951
|
});
|
|
1952
|
+
var buildCanonicalMessage = (method, pathWithQuery, body, timestamp, nonce) => {
|
|
1953
|
+
const bodyHash = crypto$1.createHash("sha256").update(body ?? "").digest("hex");
|
|
1954
|
+
return `${method}:${pathWithQuery}:${bodyHash}:${timestamp}:${nonce}`;
|
|
1955
|
+
};
|
|
1956
|
+
var buildAccountAuthHeaders = async (account, method, pathWithQuery, body) => {
|
|
1957
|
+
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
1958
|
+
const nonce = crypto.randomUUID();
|
|
1959
|
+
const message = buildCanonicalMessage(
|
|
1960
|
+
method,
|
|
1961
|
+
pathWithQuery,
|
|
1962
|
+
body,
|
|
1963
|
+
timestamp,
|
|
1964
|
+
nonce
|
|
1965
|
+
);
|
|
1966
|
+
const signature = await account.signMessage({ message });
|
|
1967
|
+
return {
|
|
1968
|
+
"x-zero-address": account.address,
|
|
1969
|
+
"x-zero-timestamp": timestamp,
|
|
1970
|
+
"x-zero-nonce": nonce,
|
|
1971
|
+
"x-zero-signature": signature
|
|
1972
|
+
};
|
|
1973
|
+
};
|
|
1974
|
+
|
|
1975
|
+
// src/transport/http.ts
|
|
1976
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 502, 503, 504]);
|
|
1977
|
+
var sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
1978
|
+
if (signal?.aborted) {
|
|
1979
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
const timer = setTimeout(() => {
|
|
1983
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1984
|
+
resolve();
|
|
1985
|
+
}, ms);
|
|
1986
|
+
const onAbort = () => {
|
|
1987
|
+
clearTimeout(timer);
|
|
1988
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
1989
|
+
};
|
|
1990
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1991
|
+
});
|
|
1992
|
+
var buildPathWithQuery = (path, query) => {
|
|
1993
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1994
|
+
if (!query) return normalizedPath;
|
|
1995
|
+
const params = new URLSearchParams();
|
|
1996
|
+
for (const [key, value] of Object.entries(query)) {
|
|
1997
|
+
if (value !== void 0) params.set(key, String(value));
|
|
1998
|
+
}
|
|
1999
|
+
const qs = params.toString();
|
|
2000
|
+
return qs ? `${normalizedPath}?${qs}` : normalizedPath;
|
|
2001
|
+
};
|
|
2002
|
+
var joinUrl = (baseUrl, pathWithQuery) => {
|
|
2003
|
+
const base3 = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
2004
|
+
return `${base3}${pathWithQuery}`;
|
|
2005
|
+
};
|
|
2006
|
+
var buildHeaders = async (client, method, pathWithQuery, hasBody, bodyStr) => {
|
|
2007
|
+
const headers = { ...client.defaultHeaders };
|
|
2008
|
+
if (hasBody) headers["content-type"] = "application/json";
|
|
2009
|
+
headers["x-zero-sdk-version"] = SDK_VERSION;
|
|
2010
|
+
if (client.apiVersion) headers["x-zero-api-version"] = client.apiVersion;
|
|
2011
|
+
const credentials = client.getCredentials();
|
|
2012
|
+
if (credentials.kind === "session") {
|
|
2013
|
+
Object.assign(headers, buildSessionAuthHeaders(credentials.accessToken));
|
|
2014
|
+
} else if (credentials.kind === "account") {
|
|
2015
|
+
const signed = await buildAccountAuthHeaders(
|
|
2016
|
+
credentials.account,
|
|
2017
|
+
method,
|
|
2018
|
+
pathWithQuery,
|
|
2019
|
+
bodyStr
|
|
2020
|
+
);
|
|
2021
|
+
Object.assign(headers, signed);
|
|
2022
|
+
}
|
|
2023
|
+
return headers;
|
|
2024
|
+
};
|
|
2025
|
+
var parseErrorBody = async (response) => {
|
|
2026
|
+
try {
|
|
2027
|
+
return await response.clone().json();
|
|
2028
|
+
} catch {
|
|
2029
|
+
try {
|
|
2030
|
+
return await response.text();
|
|
2031
|
+
} catch {
|
|
2032
|
+
return void 0;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
var errorMessageFromBody = (body, status) => {
|
|
2037
|
+
if (body !== null && typeof body === "object" && "error" in body && typeof body.error === "string") {
|
|
2038
|
+
return body.error;
|
|
2039
|
+
}
|
|
2040
|
+
return `HTTP ${status}`;
|
|
2041
|
+
};
|
|
2042
|
+
var request = async (client, opts, schema) => {
|
|
2043
|
+
const pathWithQuery = buildPathWithQuery(opts.path, opts.query);
|
|
2044
|
+
const url = joinUrl(client.baseUrl, pathWithQuery);
|
|
2045
|
+
const hasBody = opts.body !== void 0;
|
|
2046
|
+
const bodyStr = hasBody ? JSON.stringify(
|
|
2047
|
+
opts.body,
|
|
2048
|
+
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
2049
|
+
) : void 0;
|
|
2050
|
+
const configuredFetch = buildConfiguredFetch(client);
|
|
2051
|
+
const performOnce = async () => configuredFetch(url, {
|
|
2052
|
+
method: opts.method,
|
|
2053
|
+
headers: await buildHeaders(
|
|
2054
|
+
client,
|
|
2055
|
+
opts.method,
|
|
2056
|
+
pathWithQuery,
|
|
2057
|
+
hasBody,
|
|
2058
|
+
bodyStr
|
|
2059
|
+
),
|
|
2060
|
+
body: bodyStr,
|
|
2061
|
+
signal: opts.signal
|
|
2062
|
+
});
|
|
2063
|
+
let refreshAttempted = false;
|
|
2064
|
+
const executeWithRefresh = async () => {
|
|
2065
|
+
const response = await performOnce();
|
|
2066
|
+
if (response.status !== 401 || refreshAttempted) return response;
|
|
2067
|
+
const credentials = client.getCredentials();
|
|
2068
|
+
if (credentials.kind !== "session") return response;
|
|
2069
|
+
refreshAttempted = true;
|
|
2070
|
+
const refreshed = await client.refreshSessionOnce(opts.signal);
|
|
2071
|
+
if (!refreshed) return response;
|
|
2072
|
+
return await performOnce();
|
|
2073
|
+
};
|
|
2074
|
+
let lastNetworkError;
|
|
2075
|
+
for (let attempt = 0; attempt <= client.maxRetries; attempt++) {
|
|
2076
|
+
let response;
|
|
2077
|
+
try {
|
|
2078
|
+
response = await executeWithRefresh();
|
|
2079
|
+
} catch (e) {
|
|
2080
|
+
if (e instanceof ZeroError) throw e;
|
|
2081
|
+
lastNetworkError = e;
|
|
2082
|
+
if (attempt < client.maxRetries) {
|
|
2083
|
+
try {
|
|
2084
|
+
await sleep(2 ** attempt * 200, opts.signal);
|
|
2085
|
+
} catch (sleepErr) {
|
|
2086
|
+
throw new ZeroApiError("Request aborted by caller", {
|
|
2087
|
+
status: 0,
|
|
2088
|
+
cause: sleepErr
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
continue;
|
|
2092
|
+
}
|
|
2093
|
+
throw new ZeroApiError("Network request failed", {
|
|
2094
|
+
status: 0,
|
|
2095
|
+
cause: e
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
2098
|
+
if (response.ok) {
|
|
2099
|
+
let text;
|
|
2100
|
+
try {
|
|
2101
|
+
text = await response.text();
|
|
2102
|
+
} catch (e) {
|
|
2103
|
+
throw new ZeroApiError("Response body read failed", {
|
|
2104
|
+
status: response.status,
|
|
2105
|
+
cause: e
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
let json;
|
|
2109
|
+
try {
|
|
2110
|
+
json = JSON.parse(text);
|
|
2111
|
+
} catch {
|
|
2112
|
+
}
|
|
2113
|
+
const parsed = schema.safeParse(json);
|
|
2114
|
+
if (!parsed.success) {
|
|
2115
|
+
throw new ZeroValidationError(
|
|
2116
|
+
`Response did not match expected schema for ${opts.method} ${opts.path}`,
|
|
2117
|
+
{ cause: parsed.error, body: text }
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2120
|
+
return parsed.data;
|
|
2121
|
+
}
|
|
2122
|
+
if (RETRYABLE_STATUS.has(response.status) && attempt < client.maxRetries) {
|
|
2123
|
+
try {
|
|
2124
|
+
await sleep(2 ** attempt * 200, opts.signal);
|
|
2125
|
+
} catch (sleepErr) {
|
|
2126
|
+
throw new ZeroApiError("Request aborted by caller", {
|
|
2127
|
+
status: 0,
|
|
2128
|
+
cause: sleepErr
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
continue;
|
|
2132
|
+
}
|
|
2133
|
+
const errorBody = await parseErrorBody(response);
|
|
2134
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
2135
|
+
throw new ZeroApiError(errorMessageFromBody(errorBody, response.status), {
|
|
2136
|
+
status: response.status,
|
|
2137
|
+
requestId,
|
|
2138
|
+
body: errorBody
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
throw new ZeroApiError("Exhausted retries", {
|
|
2142
|
+
status: 0,
|
|
2143
|
+
cause: lastNetworkError
|
|
2144
|
+
});
|
|
2145
|
+
};
|
|
2001
2146
|
|
|
2002
|
-
// src/namespaces/
|
|
2003
|
-
var
|
|
2147
|
+
// src/namespaces/auth-device.ts
|
|
2148
|
+
var AuthDevice = class {
|
|
2004
2149
|
constructor(client) {
|
|
2005
2150
|
this.client = client;
|
|
2006
2151
|
}
|
|
2007
|
-
|
|
2152
|
+
start = (opts = {}) => request(
|
|
2008
2153
|
this.client,
|
|
2009
2154
|
{
|
|
2010
2155
|
method: "POST",
|
|
2011
|
-
path: "/v1/
|
|
2012
|
-
body: input,
|
|
2156
|
+
path: "/v1/auth/device/start",
|
|
2013
2157
|
signal: opts.signal
|
|
2014
2158
|
},
|
|
2015
|
-
|
|
2159
|
+
deviceStartResponseSchema
|
|
2016
2160
|
);
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
if (opts.signal?.aborted) {
|
|
2020
|
-
return Promise.reject(
|
|
2021
|
-
new ZeroApiError("Request aborted by caller", { status: 0 })
|
|
2022
|
-
);
|
|
2023
|
-
}
|
|
2024
|
-
if (params.cursor === void 0) {
|
|
2025
|
-
return Promise.reject(
|
|
2026
|
-
new ZeroApiError(
|
|
2027
|
-
"runs.list({ limit: 0 }) requires a cursor \u2014 without one the empty page is indistinguishable from end-of-stream",
|
|
2028
|
-
{ status: 0 }
|
|
2029
|
-
)
|
|
2030
|
-
);
|
|
2031
|
-
}
|
|
2032
|
-
return Promise.resolve({
|
|
2033
|
-
runs: [],
|
|
2034
|
-
nextCursor: params.cursor
|
|
2035
|
-
});
|
|
2036
|
-
}
|
|
2037
|
-
const query = {};
|
|
2038
|
-
if (params.capabilityId !== void 0)
|
|
2039
|
-
query.capabilityId = params.capabilityId;
|
|
2040
|
-
if (params.unreviewed !== void 0) query.unreviewed = params.unreviewed;
|
|
2041
|
-
if (params.limit !== void 0) query.limit = params.limit;
|
|
2042
|
-
if (params.cursor !== void 0) query.cursor = params.cursor;
|
|
2043
|
-
return request(
|
|
2161
|
+
poll = async (deviceCode, opts = {}) => {
|
|
2162
|
+
const parsed = await request(
|
|
2044
2163
|
this.client,
|
|
2045
2164
|
{
|
|
2046
|
-
method: "
|
|
2047
|
-
path: "/v1/
|
|
2048
|
-
|
|
2165
|
+
method: "POST",
|
|
2166
|
+
path: "/v1/auth/device/poll",
|
|
2167
|
+
body: { deviceCode },
|
|
2049
2168
|
signal: opts.signal
|
|
2050
2169
|
},
|
|
2051
|
-
|
|
2170
|
+
devicePollResponseSchema
|
|
2052
2171
|
);
|
|
2172
|
+
if ("error" in parsed) {
|
|
2173
|
+
return parsed.error === "authorization_pending" ? {
|
|
2174
|
+
status: "pending",
|
|
2175
|
+
userCode: parsed.userCode,
|
|
2176
|
+
verificationUri: parsed.verificationUri
|
|
2177
|
+
} : { status: "expired" };
|
|
2178
|
+
}
|
|
2179
|
+
return {
|
|
2180
|
+
status: "ok",
|
|
2181
|
+
accessToken: parsed.accessToken,
|
|
2182
|
+
refreshToken: parsed.refreshToken,
|
|
2183
|
+
expiresIn: parsed.expiresIn,
|
|
2184
|
+
user: parsed.user
|
|
2185
|
+
};
|
|
2053
2186
|
};
|
|
2054
|
-
get = (runId, opts = {}) => request(
|
|
2055
|
-
this.client,
|
|
2056
|
-
{
|
|
2057
|
-
method: "GET",
|
|
2058
|
-
path: `/v1/runs/${runId}`,
|
|
2059
|
-
signal: opts.signal
|
|
2060
|
-
},
|
|
2061
|
-
runDetailSchema
|
|
2062
|
-
);
|
|
2063
|
-
review = (input, opts = {}) => request(
|
|
2064
|
-
this.client,
|
|
2065
|
-
{
|
|
2066
|
-
method: "POST",
|
|
2067
|
-
path: "/v1/reviews",
|
|
2068
|
-
body: input,
|
|
2069
|
-
signal: opts.signal
|
|
2070
|
-
},
|
|
2071
|
-
createReviewResponseSchema
|
|
2072
|
-
);
|
|
2073
|
-
// Bulk review submission. The CLI's bulk JSONL parser stays CLI-side —
|
|
2074
|
-
// SDK consumers pass already-parsed structured input.
|
|
2075
|
-
createReviewsBatch = (reviews, opts = {}) => request(
|
|
2076
|
-
this.client,
|
|
2077
|
-
{
|
|
2078
|
-
method: "POST",
|
|
2079
|
-
path: "/v1/reviews/batch",
|
|
2080
|
-
body: { reviews },
|
|
2081
|
-
signal: opts.signal
|
|
2082
|
-
},
|
|
2083
|
-
batchReviewResponseSchema
|
|
2084
|
-
);
|
|
2085
2187
|
};
|
|
2086
|
-
var
|
|
2087
|
-
var
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
id: TEMPO_CHAIN_ID2,
|
|
2092
|
-
name: "Tempo",
|
|
2093
|
-
nativeCurrency: { name: "USD", symbol: "USD", decimals: 18 },
|
|
2094
|
-
rpcUrls: {
|
|
2095
|
-
default: { http: ["https://rpc.tempo.xyz"] }
|
|
2096
|
-
}
|
|
2188
|
+
var userWalletsSchema = zod.z.array(userWalletDtoSchema);
|
|
2189
|
+
var normalizeMessage = (message) => {
|
|
2190
|
+
if (typeof message === "string") return message;
|
|
2191
|
+
if (typeof message.raw === "string") return message.raw;
|
|
2192
|
+
return viem.bytesToHex(message.raw);
|
|
2097
2193
|
};
|
|
2098
|
-
var
|
|
2099
|
-
{
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2194
|
+
var repackageSignFailure = (err, op) => {
|
|
2195
|
+
if (err instanceof ZeroApiError && err.status === 402) {
|
|
2196
|
+
const body = err.body;
|
|
2197
|
+
const detail = body && typeof body.error === "string" ? `: ${body.error}` : "";
|
|
2198
|
+
throw new ZeroPaymentError(
|
|
2199
|
+
`Sign endpoint refused ${op} (HTTP 402)${detail}`,
|
|
2200
|
+
{ cause: err }
|
|
2201
|
+
);
|
|
2105
2202
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
// src/namespaces/wallet.ts
|
|
2110
|
-
var fundingUrlResponseSchema = zod.z.object({ url: zod.z.string() });
|
|
2111
|
-
var userWalletListSchema = zod.z.array(userWalletDtoSchema);
|
|
2112
|
-
var migrateAuthorizationResponseSchema = zod.z.object({
|
|
2113
|
-
transactionHash: zod.z.string()
|
|
2114
|
-
});
|
|
2115
|
-
var errorMessage = (reason) => reason instanceof Error ? reason.message : String(reason);
|
|
2116
|
-
var Wallet = class {
|
|
2203
|
+
throw err;
|
|
2204
|
+
};
|
|
2205
|
+
var Auth = class {
|
|
2117
2206
|
constructor(client) {
|
|
2118
2207
|
this.client = client;
|
|
2208
|
+
this.device = new AuthDevice(client);
|
|
2119
2209
|
}
|
|
2120
|
-
|
|
2121
|
-
// The
|
|
2122
|
-
//
|
|
2123
|
-
|
|
2124
|
-
const credentials = this.client.getCredentials();
|
|
2125
|
-
if (credentials.kind !== "account") return null;
|
|
2126
|
-
return credentials.account.address;
|
|
2127
|
-
}
|
|
2128
|
-
balance = async (opts = {}) => {
|
|
2129
|
-
const target = opts.address ?? this.address;
|
|
2130
|
-
if (!target) {
|
|
2131
|
-
throw new ZeroWalletError(
|
|
2132
|
-
"balance() requires either an `address` option or a client constructed with an account"
|
|
2133
|
-
);
|
|
2134
|
-
}
|
|
2135
|
-
const chain = opts.chain ?? "total";
|
|
2136
|
-
if (chain !== "total") {
|
|
2137
|
-
const raw = await this.readChainBalance(chain, target);
|
|
2138
|
-
return { amount: viem.formatUnits(raw, USDC_DECIMALS), asset: "USDC" };
|
|
2139
|
-
}
|
|
2140
|
-
const chains = ["base", "tempo"];
|
|
2141
|
-
const settled = await Promise.allSettled(
|
|
2142
|
-
chains.map((c) => this.readChainBalance(c, target))
|
|
2143
|
-
);
|
|
2144
|
-
let sum = 0n;
|
|
2145
|
-
const errors = [];
|
|
2146
|
-
for (let i = 0; i < settled.length; i++) {
|
|
2147
|
-
const result = settled[i];
|
|
2148
|
-
const chainName = chains[i];
|
|
2149
|
-
if (!result || !chainName) continue;
|
|
2150
|
-
if (result.status === "fulfilled") {
|
|
2151
|
-
sum += result.value;
|
|
2152
|
-
} else {
|
|
2153
|
-
errors.push({ chain: chainName, message: errorMessage(result.reason) });
|
|
2154
|
-
}
|
|
2155
|
-
}
|
|
2156
|
-
if (errors.length === settled.length) {
|
|
2157
|
-
throw new ZeroWalletError(
|
|
2158
|
-
`balance() failed for every chain: ${errors.map((e) => `${e.chain} (${e.message})`).join(", ")}`
|
|
2159
|
-
);
|
|
2160
|
-
}
|
|
2161
|
-
const balance = {
|
|
2162
|
-
amount: viem.formatUnits(sum, USDC_DECIMALS),
|
|
2163
|
-
asset: "USDC"
|
|
2164
|
-
};
|
|
2165
|
-
if (errors.length > 0) balance.errors = errors;
|
|
2166
|
-
return balance;
|
|
2167
|
-
};
|
|
2168
|
-
// All wallets linked to the authenticated session user. Session-only.
|
|
2169
|
-
list = (opts = {}) => request(
|
|
2210
|
+
device;
|
|
2211
|
+
// The internal (web-app facing) user profile. Richer than profile(): full
|
|
2212
|
+
// wallet list with per-wallet delegation/signer/limit metadata.
|
|
2213
|
+
me = (opts = {}) => request(
|
|
2170
2214
|
this.client,
|
|
2171
|
-
{
|
|
2172
|
-
|
|
2173
|
-
path: "/v1/users/me/wallets",
|
|
2174
|
-
signal: opts.signal
|
|
2175
|
-
},
|
|
2176
|
-
userWalletListSchema
|
|
2215
|
+
{ method: "GET", path: "/v1/users/me", signal: opts.signal },
|
|
2216
|
+
internalUserDtoSchema
|
|
2177
2217
|
);
|
|
2178
|
-
//
|
|
2179
|
-
//
|
|
2180
|
-
|
|
2218
|
+
// The public (agent-facing) profile — identity + primary wallet address +
|
|
2219
|
+
// balance + welcome-bonus, no per-wallet metadata. Same shape the MCP
|
|
2220
|
+
// get_profile tool returns; rendered by `zero auth whoami`.
|
|
2221
|
+
profile = (opts = {}) => request(
|
|
2222
|
+
this.client,
|
|
2223
|
+
{ method: "GET", path: "/v1/users/me/profile", signal: opts.signal },
|
|
2224
|
+
publicUserDtoSchema
|
|
2225
|
+
);
|
|
2226
|
+
// The user's wallets only. Lightweight sibling of `me()` for callers that
|
|
2227
|
+
// just need wallet addresses (e.g. managed-account resolution on the pay
|
|
2228
|
+
// path) — avoids the heavier internal-profile computation behind `me()`.
|
|
2229
|
+
wallets = (opts = {}) => request(
|
|
2181
2230
|
this.client,
|
|
2182
|
-
{
|
|
2183
|
-
|
|
2184
|
-
path: "/v1/users/me/wallets/provision",
|
|
2185
|
-
signal: opts.signal
|
|
2186
|
-
},
|
|
2187
|
-
userWalletDtoSchema
|
|
2231
|
+
{ method: "GET", path: "/v1/users/me/wallets", signal: opts.signal },
|
|
2232
|
+
userWalletsSchema
|
|
2188
2233
|
);
|
|
2189
|
-
//
|
|
2190
|
-
//
|
|
2191
|
-
//
|
|
2192
|
-
|
|
2193
|
-
// the signed payload. Session-only.
|
|
2194
|
-
migrateAuthorization = (authorization, opts = {}) => request(
|
|
2234
|
+
// Exchange an ephemeral session code (e.g. runner / sandbox handoff) for
|
|
2235
|
+
// a session access token. The returned token has no refresh path — pair
|
|
2236
|
+
// with `refreshToken: ""` when constructing the client.
|
|
2237
|
+
exchangeSessionCode = (code, opts = {}) => request(
|
|
2195
2238
|
this.client,
|
|
2196
2239
|
{
|
|
2197
2240
|
method: "POST",
|
|
2198
|
-
path: "/v1/
|
|
2199
|
-
body: {
|
|
2241
|
+
path: "/v1/session/exchange",
|
|
2242
|
+
body: { code },
|
|
2200
2243
|
signal: opts.signal
|
|
2201
2244
|
},
|
|
2202
|
-
|
|
2245
|
+
sessionExchangeResponseSchema
|
|
2203
2246
|
);
|
|
2204
|
-
//
|
|
2205
|
-
//
|
|
2206
|
-
//
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
"fundingUrl() requires a client constructed with an account or session credentials"
|
|
2213
|
-
);
|
|
2214
|
-
}
|
|
2215
|
-
const query = {
|
|
2216
|
-
provider: opts.provider ?? "coinbase"
|
|
2217
|
-
};
|
|
2218
|
-
if (opts.amount) query.amount = opts.amount;
|
|
2219
|
-
const { url } = await request(
|
|
2247
|
+
// Server-side revoke of the refresh token. Throws ZeroApiError on any
|
|
2248
|
+
// non-2xx — callers that have already cleared local state (e.g. CLI
|
|
2249
|
+
// logout) typically want to swallow with `.catch(() => {})` so a flaky
|
|
2250
|
+
// server doesn't surface as a user-visible failure for a sign-out that
|
|
2251
|
+
// already succeeded locally. Response body is opaque; schema is
|
|
2252
|
+
// `z.unknown()` and the resolved value is discarded.
|
|
2253
|
+
logout = async (refreshToken, opts = {}) => {
|
|
2254
|
+
await request(
|
|
2220
2255
|
this.client,
|
|
2221
|
-
{
|
|
2222
|
-
|
|
2256
|
+
{
|
|
2257
|
+
method: "POST",
|
|
2258
|
+
path: "/v1/auth/logout",
|
|
2259
|
+
body: { refreshToken },
|
|
2260
|
+
signal: opts.signal
|
|
2261
|
+
},
|
|
2262
|
+
zod.z.unknown()
|
|
2223
2263
|
);
|
|
2224
|
-
return url;
|
|
2225
2264
|
};
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2265
|
+
// Force a session refresh. Routes through refreshSessionOnce() so a
|
|
2266
|
+
// proactive call doesn't race a 401-driven transport refresh —
|
|
2267
|
+
// concurrent POSTs with the same refresh token kill the session
|
|
2268
|
+
// family (RFC 6819 token-theft response).
|
|
2269
|
+
refresh = async () => {
|
|
2270
|
+
const credentials = this.client.getCredentials();
|
|
2271
|
+
if (credentials.kind !== "session") {
|
|
2272
|
+
throw new ZeroAuthError(
|
|
2273
|
+
"auth_no_credentials",
|
|
2274
|
+
"refresh() requires the client to be constructed with a session \u2014 got credentials.kind=" + credentials.kind
|
|
2275
|
+
);
|
|
2235
2276
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2277
|
+
const ok = await this.client.refreshSessionOnce();
|
|
2278
|
+
if (!ok) {
|
|
2279
|
+
throw new ZeroAuthError(
|
|
2280
|
+
"auth_session_expired",
|
|
2281
|
+
"Session refresh failed. The refresh token may be revoked or expired."
|
|
2282
|
+
);
|
|
2242
2283
|
}
|
|
2243
|
-
return this.clients.tempo;
|
|
2244
|
-
};
|
|
2245
|
-
/**
|
|
2246
|
-
* @internal
|
|
2247
|
-
*
|
|
2248
|
-
* Per-chain USDC balance read. Exposed (rather than private) so unit
|
|
2249
|
-
* tests can stub it without standing up a real viem public client —
|
|
2250
|
-
* viem's `http()` transport doesn't go through `client.fetchImpl`, so
|
|
2251
|
-
* the standard mock-fetch trick doesn't cover this path.
|
|
2252
|
-
*/
|
|
2253
|
-
readChainBalance = async (chain, address) => {
|
|
2254
|
-
const publicClient = this.getPublicClient(chain);
|
|
2255
|
-
const tokenAddress = chain === "base" ? USDC_BASE2 : USDC_TEMPO2;
|
|
2256
|
-
const balance = await publicClient.readContract({
|
|
2257
|
-
address: tokenAddress,
|
|
2258
|
-
abi: ERC20_BALANCE_ABI2,
|
|
2259
|
-
functionName: "balanceOf",
|
|
2260
|
-
args: [address]
|
|
2261
|
-
});
|
|
2262
|
-
return balance;
|
|
2263
2284
|
};
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
2269
|
-
var DEFAULT_MAX_RETRIES = 2;
|
|
2270
|
-
|
|
2271
|
-
// src/auth/credentials.ts
|
|
2272
|
-
var noopRefresh = async () => {
|
|
2273
|
-
};
|
|
2274
|
-
var MAX_402_PROBE_BYTES = 1024 * 1024;
|
|
2275
|
-
var MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
2276
|
-
var TEXT_CONTENT_TYPES = [
|
|
2277
|
-
"application/json",
|
|
2278
|
-
"application/xml",
|
|
2279
|
-
"application/javascript",
|
|
2280
|
-
"application/ecmascript",
|
|
2281
|
-
"application/x-www-form-urlencoded",
|
|
2282
|
-
"text/",
|
|
2283
|
-
"+json",
|
|
2284
|
-
"+xml"
|
|
2285
|
-
];
|
|
2286
|
-
var MPP_SCHEME_TOKENS = /* @__PURE__ */ new Set(["payment", "mpp"]);
|
|
2287
|
-
var splitWwwAuthenticateChallenges = (header) => {
|
|
2288
|
-
const chunks = [];
|
|
2289
|
-
let buf = "";
|
|
2290
|
-
let inQuotes = false;
|
|
2291
|
-
for (let i = 0; i < header.length; i++) {
|
|
2292
|
-
const ch = header[i];
|
|
2293
|
-
if (inQuotes) {
|
|
2294
|
-
if (ch === "\\" && i + 1 < header.length) {
|
|
2295
|
-
buf += ch + header[i + 1];
|
|
2296
|
-
i++;
|
|
2297
|
-
continue;
|
|
2298
|
-
}
|
|
2299
|
-
if (ch === '"') inQuotes = false;
|
|
2300
|
-
buf += ch;
|
|
2301
|
-
continue;
|
|
2302
|
-
}
|
|
2303
|
-
if (ch === '"') {
|
|
2304
|
-
inQuotes = true;
|
|
2305
|
-
buf += ch;
|
|
2306
|
-
continue;
|
|
2285
|
+
signMessage = async (input, opts = {}) => {
|
|
2286
|
+
const credentials = this.client.getCredentials();
|
|
2287
|
+
if (credentials.kind === "account") {
|
|
2288
|
+
return await credentials.account.signMessage({ message: input.message });
|
|
2307
2289
|
}
|
|
2308
|
-
if (
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2290
|
+
if (credentials.kind === "session") {
|
|
2291
|
+
try {
|
|
2292
|
+
const parsed = await request(
|
|
2293
|
+
this.client,
|
|
2294
|
+
{
|
|
2295
|
+
method: "POST",
|
|
2296
|
+
path: "/v1/users/me/sign-message",
|
|
2297
|
+
body: { message: normalizeMessage(input.message) }
|
|
2298
|
+
},
|
|
2299
|
+
signResponseSchema
|
|
2300
|
+
);
|
|
2301
|
+
this.assertSignerMatches(parsed.walletAddress, opts.expectedAddress);
|
|
2302
|
+
return parsed.signature;
|
|
2303
|
+
} catch (err) {
|
|
2304
|
+
repackageSignFailure(err, "signMessage");
|
|
2305
|
+
}
|
|
2312
2306
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
};
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
);
|
|
2338
|
-
if (asString.length < ECHO_DETECT_MIN_LEN) return false;
|
|
2339
|
-
const scanLen = Math.min(asString.length, ECHO_DETECT_MAX_SCAN);
|
|
2340
|
-
for (let i = 0; i + ECHO_DETECT_MIN_LEN <= scanLen; i++) {
|
|
2341
|
-
if (candidate.includes(asString.slice(i, i + ECHO_DETECT_MIN_LEN))) {
|
|
2342
|
-
return true;
|
|
2307
|
+
throw new ZeroAuthError(
|
|
2308
|
+
"auth_no_credentials",
|
|
2309
|
+
"signMessage() requires the client to be constructed with `account` or `session`."
|
|
2310
|
+
);
|
|
2311
|
+
};
|
|
2312
|
+
// Managed-only: BYO accounts sign locally via viem's account.signTransaction.
|
|
2313
|
+
signTransaction = async (input, opts = {}) => {
|
|
2314
|
+
const credentials = this.client.getCredentials();
|
|
2315
|
+
if (credentials.kind === "session") {
|
|
2316
|
+
try {
|
|
2317
|
+
const parsed = await request(
|
|
2318
|
+
this.client,
|
|
2319
|
+
{
|
|
2320
|
+
method: "POST",
|
|
2321
|
+
path: "/v1/users/me/sign-transaction",
|
|
2322
|
+
body: { unsignedTransaction: input.unsignedTransaction }
|
|
2323
|
+
},
|
|
2324
|
+
signResponseSchema
|
|
2325
|
+
);
|
|
2326
|
+
this.assertSignerMatches(parsed.walletAddress, opts.expectedAddress);
|
|
2327
|
+
return parsed.signature;
|
|
2328
|
+
} catch (err) {
|
|
2329
|
+
repackageSignFailure(err, "signTransaction");
|
|
2330
|
+
}
|
|
2343
2331
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
try {
|
|
2349
|
-
response.body?.cancel().catch(() => {
|
|
2350
|
-
});
|
|
2351
|
-
} catch {
|
|
2352
|
-
}
|
|
2353
|
-
};
|
|
2354
|
-
var detectPaymentRequirement = async (response) => {
|
|
2355
|
-
if (response.status !== 402) return null;
|
|
2356
|
-
const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
|
|
2357
|
-
if (x402Header) {
|
|
2358
|
-
cancelBody2(response);
|
|
2359
|
-
try {
|
|
2360
|
-
const decoded = JSON.parse(
|
|
2361
|
-
Buffer.from(x402Header, "base64").toString("utf8")
|
|
2332
|
+
if (credentials.kind === "account") {
|
|
2333
|
+
throw new ZeroAuthError(
|
|
2334
|
+
"auth_error",
|
|
2335
|
+
"signTransaction() is a managed-signing operation and is not supported in account mode. Sign locally with viem's account.signTransaction instead."
|
|
2362
2336
|
);
|
|
2363
|
-
return { protocol: "x402", raw: decoded };
|
|
2364
|
-
} catch {
|
|
2365
|
-
return { protocol: "x402", raw: { encoded: x402Header } };
|
|
2366
2337
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
}
|
|
2338
|
+
throw new ZeroAuthError(
|
|
2339
|
+
"auth_no_credentials",
|
|
2340
|
+
"signTransaction() requires session credentials (managed signing)."
|
|
2341
|
+
);
|
|
2342
|
+
};
|
|
2343
|
+
signTypedData = async (input, opts = {}) => {
|
|
2344
|
+
const credentials = this.client.getCredentials();
|
|
2345
|
+
if (credentials.kind === "account") {
|
|
2346
|
+
if (!credentials.account.signTypedData) {
|
|
2347
|
+
throw new ZeroAuthError(
|
|
2348
|
+
"auth_error",
|
|
2349
|
+
"The configured viem account does not implement signTypedData."
|
|
2350
|
+
);
|
|
2381
2351
|
}
|
|
2382
|
-
|
|
2352
|
+
return await credentials.account.signTypedData(input);
|
|
2383
2353
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2354
|
+
if (credentials.kind === "session") {
|
|
2355
|
+
try {
|
|
2356
|
+
const parsed = await request(
|
|
2357
|
+
this.client,
|
|
2358
|
+
{
|
|
2359
|
+
method: "POST",
|
|
2360
|
+
path: "/v1/users/me/sign-typed-data",
|
|
2361
|
+
body: { typedData: input }
|
|
2362
|
+
},
|
|
2363
|
+
signResponseSchema
|
|
2364
|
+
);
|
|
2365
|
+
this.assertSignerMatches(parsed.walletAddress, opts.expectedAddress);
|
|
2366
|
+
return parsed.signature;
|
|
2367
|
+
} catch (err) {
|
|
2368
|
+
repackageSignFailure(err, "signTypedData");
|
|
2369
|
+
}
|
|
2393
2370
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2371
|
+
throw new ZeroAuthError(
|
|
2372
|
+
"auth_no_credentials",
|
|
2373
|
+
"signTypedData() requires the client to be constructed with `account` or `session`."
|
|
2374
|
+
);
|
|
2375
|
+
};
|
|
2376
|
+
// Compare against the caller's pinned address (not shared cache) so
|
|
2377
|
+
// concurrent pay()s can't race past each other. Mismatch → clear + throw;
|
|
2378
|
+
// the caller's retry rebuilds against the new wallet.
|
|
2379
|
+
assertSignerMatches = (serverAddr, expectedAddr) => {
|
|
2380
|
+
if (!expectedAddr) return;
|
|
2381
|
+
const canonicalServer = viem.getAddress(serverAddr);
|
|
2382
|
+
const canonicalExpected = viem.getAddress(expectedAddr);
|
|
2383
|
+
if (canonicalExpected === canonicalServer) return;
|
|
2384
|
+
this.client.clearManagedAccount();
|
|
2385
|
+
throw new ZeroAuthError(
|
|
2386
|
+
"auth_error",
|
|
2387
|
+
`Managed signing wallet changed (caller expected ${canonicalExpected}, server signed as ${canonicalServer}). Cache cleared \u2014 retry to rebuild against the current wallet.`
|
|
2388
|
+
);
|
|
2389
|
+
};
|
|
2397
2390
|
};
|
|
2398
|
-
var
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2391
|
+
var BUG_REPORT_CATEGORIES = [
|
|
2392
|
+
"search_relevance",
|
|
2393
|
+
"ranking_issue",
|
|
2394
|
+
"missing_capability",
|
|
2395
|
+
"wrong_schema",
|
|
2396
|
+
"misleading_description",
|
|
2397
|
+
"broken_execution",
|
|
2398
|
+
"payment_failure",
|
|
2399
|
+
"billing_anomaly",
|
|
2400
|
+
"cli_bug",
|
|
2401
|
+
"security",
|
|
2402
|
+
"other"
|
|
2403
|
+
];
|
|
2404
|
+
var createBugReportResponseSchema = zod.z.object({
|
|
2405
|
+
bugReportId: zod.z.string(),
|
|
2406
|
+
status: zod.z.string(),
|
|
2407
|
+
deduped: zod.z.boolean(),
|
|
2408
|
+
category: zod.z.enum(BUG_REPORT_CATEGORIES).nullable(),
|
|
2409
|
+
title: zod.z.string().nullable(),
|
|
2410
|
+
attached: zod.z.object({
|
|
2411
|
+
capabilityId: zod.z.number().nullable(),
|
|
2412
|
+
runId: zod.z.number().nullable(),
|
|
2413
|
+
searchId: zod.z.number().nullable()
|
|
2414
|
+
})
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
// src/namespaces/bug-reports.ts
|
|
2418
|
+
var BugReports = class {
|
|
2419
|
+
constructor(client) {
|
|
2420
|
+
this.client = client;
|
|
2424
2421
|
}
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2422
|
+
// POST /v1/bug-reports. Wallet-attributed server-side; the SDK client's
|
|
2423
|
+
// active credential drives attribution (account-mode → EIP-191 from the
|
|
2424
|
+
// wallet, session-mode → Bearer + server resolves the user's wallet).
|
|
2425
|
+
create = (input, opts = {}) => request(
|
|
2426
|
+
this.client,
|
|
2427
|
+
{
|
|
2428
|
+
method: "POST",
|
|
2429
|
+
path: "/v1/bug-reports",
|
|
2430
|
+
body: input,
|
|
2431
|
+
signal: opts.signal
|
|
2432
|
+
},
|
|
2433
|
+
createBugReportResponseSchema
|
|
2434
|
+
);
|
|
2430
2435
|
};
|
|
2431
|
-
var
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2436
|
+
var ratingSchema = zod.z.object({
|
|
2437
|
+
score: zod.z.string(),
|
|
2438
|
+
successRate: zod.z.string(),
|
|
2439
|
+
reviews: zod.z.number(),
|
|
2440
|
+
stars: zod.z.string().nullable().optional(),
|
|
2441
|
+
state: zod.z.enum(["unrated", "rated"]).optional()
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
// src/schemas/capabilities.ts
|
|
2445
|
+
var capabilityResponseSchema = zod.z.object({
|
|
2446
|
+
uid: zod.z.string(),
|
|
2447
|
+
slug: zod.z.string(),
|
|
2448
|
+
name: zod.z.string(),
|
|
2449
|
+
description: zod.z.string(),
|
|
2450
|
+
url: zod.z.string(),
|
|
2451
|
+
urlTemplate: zod.z.string().nullable().optional(),
|
|
2452
|
+
method: zod.z.string(),
|
|
2453
|
+
headers: zod.z.record(zod.z.string(), zod.z.string()).nullable(),
|
|
2454
|
+
bodySchema: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
|
|
2455
|
+
responseSchema: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
|
|
2456
|
+
example: zod.z.object({ request: zod.z.unknown(), response: zod.z.unknown() }).nullable(),
|
|
2457
|
+
tags: zod.z.array(zod.z.string()).nullable(),
|
|
2458
|
+
exampleAgentPrompt: zod.z.string().nullable().optional(),
|
|
2459
|
+
displayCostAmount: zod.z.string(),
|
|
2460
|
+
displayCostAsset: zod.z.string(),
|
|
2461
|
+
reviewCount: zod.z.number(),
|
|
2462
|
+
rating: ratingSchema,
|
|
2463
|
+
priceObserved: zod.z.object({
|
|
2464
|
+
minCents: zod.z.string().nullable(),
|
|
2465
|
+
medianCents: zod.z.string().nullable(),
|
|
2466
|
+
maxCents: zod.z.string().nullable(),
|
|
2467
|
+
// Deprecated alias for maxCents; kept for back-compat with older
|
|
2468
|
+
// API versions that still emit it.
|
|
2469
|
+
p95Cents: zod.z.string().nullable(),
|
|
2470
|
+
sampleCount: zod.z.number(),
|
|
2471
|
+
varies: zod.z.boolean(),
|
|
2472
|
+
failureChargeRate: zod.z.number().nullable()
|
|
2473
|
+
}).nullable().optional(),
|
|
2474
|
+
paymentMethods: zod.z.array(
|
|
2475
|
+
zod.z.object({
|
|
2476
|
+
uid: zod.z.string(),
|
|
2477
|
+
protocol: zod.z.string(),
|
|
2478
|
+
methodType: zod.z.string(),
|
|
2479
|
+
chain: zod.z.string().nullable(),
|
|
2480
|
+
mode: zod.z.string(),
|
|
2481
|
+
costAmount: zod.z.string(),
|
|
2482
|
+
costPer: zod.z.string(),
|
|
2483
|
+
priority: zod.z.number()
|
|
2484
|
+
})
|
|
2485
|
+
).nullable(),
|
|
2486
|
+
availabilityStatus: zod.z.enum(["healthy", "unknown", "down"]).nullable().optional(),
|
|
2487
|
+
/**
|
|
2488
|
+
* @deprecated The API no longer emits `displayStatus`; it has been replaced
|
|
2489
|
+
* by the consolidated 3-value {@link capabilityResponseSchema.shape.availabilityStatus}.
|
|
2490
|
+
* Kept as an optional field for one release for back-compat (ZERO-89 soft
|
|
2491
|
+
* migration) and will be removed in the next major version.
|
|
2492
|
+
*/
|
|
2493
|
+
displayStatus: zod.z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
|
|
2494
|
+
activationCount: zod.z.number().optional(),
|
|
2495
|
+
lastUsedAt: zod.z.string().nullable().optional(),
|
|
2496
|
+
lastSuccessfullyRanAt: zod.z.string().nullable().optional()
|
|
2497
|
+
});
|
|
2498
|
+
var resolveCapabilityResponseSchema = zod.z.object({
|
|
2499
|
+
capabilityId: zod.z.string(),
|
|
2500
|
+
capabilitySlug: zod.z.string(),
|
|
2501
|
+
matchedVia: zod.z.enum(["exact", "template"])
|
|
2502
|
+
});
|
|
2503
|
+
|
|
2504
|
+
// src/namespaces/capabilities.ts
|
|
2505
|
+
var Capabilities = class {
|
|
2506
|
+
constructor(client) {
|
|
2507
|
+
this.client = client;
|
|
2445
2508
|
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2509
|
+
get = (id, opts = {}) => request(
|
|
2510
|
+
this.client,
|
|
2511
|
+
{
|
|
2512
|
+
method: "GET",
|
|
2513
|
+
path: `/v1/capabilities/${encodeURIComponent(id)}`,
|
|
2514
|
+
query: opts.searchId ? { searchId: opts.searchId } : void 0,
|
|
2515
|
+
signal: opts.signal
|
|
2516
|
+
},
|
|
2517
|
+
capabilityResponseSchema
|
|
2518
|
+
);
|
|
2519
|
+
// Resolve a raw endpoint URL + method back to the capability that owns it,
|
|
2520
|
+
// for the `zero fetch <url>` case where the client has no local search
|
|
2521
|
+
// context to match against (a memoized/cross-session URL). Returns null on
|
|
2522
|
+
// 404 — i.e. no match or an ambiguous multi-match, both of which the server
|
|
2523
|
+
// reports as 404 (resolveByUrl fails closed rather than mis-attribute).
|
|
2524
|
+
// The URL travels in the POST body so it stays out of access logs and is
|
|
2525
|
+
// never stored; the caller uses the returned capabilityId to record an
|
|
2526
|
+
// attributed run without the URL ever touching the run row (ZERO-335).
|
|
2527
|
+
resolveByUrl = async (url, method, opts = {}) => {
|
|
2448
2528
|
try {
|
|
2449
|
-
return
|
|
2450
|
-
|
|
2529
|
+
return await request(
|
|
2530
|
+
this.client,
|
|
2531
|
+
{
|
|
2532
|
+
method: "POST",
|
|
2533
|
+
path: "/v1/capabilities/resolve",
|
|
2534
|
+
body: { url, method },
|
|
2535
|
+
signal: opts.signal
|
|
2536
|
+
},
|
|
2537
|
+
resolveCapabilityResponseSchema
|
|
2538
|
+
);
|
|
2539
|
+
} catch (err) {
|
|
2540
|
+
if (err instanceof ZeroApiError && err.status === 404) return null;
|
|
2541
|
+
throw err;
|
|
2451
2542
|
}
|
|
2452
|
-
}
|
|
2453
|
-
return { body: text, bodyRaw: text, truncated };
|
|
2454
|
-
};
|
|
2455
|
-
var UPSTREAM_ERROR_FIELDS = [
|
|
2456
|
-
"error",
|
|
2457
|
-
"message",
|
|
2458
|
-
"detail",
|
|
2459
|
-
"reason",
|
|
2460
|
-
"error_description"
|
|
2461
|
-
];
|
|
2462
|
-
var UPSTREAM_ERROR_MAX_LEN = 200;
|
|
2463
|
-
var ERROR_SNIPPET_BYTES = 500;
|
|
2464
|
-
var clampUpstreamMessage = (value) => {
|
|
2465
|
-
const trimmed = value.trim();
|
|
2466
|
-
if (!trimmed) return void 0;
|
|
2467
|
-
return trimmed.length > UPSTREAM_ERROR_MAX_LEN ? `${trimmed.slice(0, UPSTREAM_ERROR_MAX_LEN)}\u2026` : trimmed;
|
|
2468
|
-
};
|
|
2469
|
-
var tryParseJson = (text) => {
|
|
2470
|
-
try {
|
|
2471
|
-
return JSON.parse(text);
|
|
2472
|
-
} catch {
|
|
2473
|
-
return null;
|
|
2474
|
-
}
|
|
2543
|
+
};
|
|
2475
2544
|
};
|
|
2476
|
-
var
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2545
|
+
var createRunResponseSchema = zod.z.object({
|
|
2546
|
+
runId: zod.z.string()
|
|
2547
|
+
});
|
|
2548
|
+
var runListItemSchema = zod.z.object({
|
|
2549
|
+
uid: zod.z.string(),
|
|
2550
|
+
capabilityUid: zod.z.string(),
|
|
2551
|
+
capabilitySlug: zod.z.string(),
|
|
2552
|
+
capabilityName: zod.z.string(),
|
|
2553
|
+
status: zod.z.number().nullable(),
|
|
2554
|
+
latencyMs: zod.z.number().nullable(),
|
|
2555
|
+
cost: zod.z.object({ amount: zod.z.string(), asset: zod.z.string().nullable() }).nullable(),
|
|
2556
|
+
payment: zod.z.object({
|
|
2557
|
+
protocol: zod.z.string(),
|
|
2558
|
+
chain: zod.z.string().nullable(),
|
|
2559
|
+
txHash: zod.z.string().nullable(),
|
|
2560
|
+
mode: zod.z.string().nullable()
|
|
2561
|
+
}).nullable(),
|
|
2562
|
+
createdAt: zod.z.coerce.date(),
|
|
2563
|
+
reviewed: zod.z.boolean()
|
|
2564
|
+
});
|
|
2565
|
+
var listRunsResponseSchema = zod.z.object({
|
|
2566
|
+
runs: zod.z.array(runListItemSchema),
|
|
2567
|
+
nextCursor: zod.z.string().nullable()
|
|
2568
|
+
});
|
|
2569
|
+
var runDetailSchema = zod.z.object({
|
|
2570
|
+
runId: zod.z.string(),
|
|
2571
|
+
status: zod.z.number().nullable(),
|
|
2572
|
+
latencyMs: zod.z.number().nullable(),
|
|
2573
|
+
errorClass: zod.z.string().nullable(),
|
|
2574
|
+
createdAt: zod.z.coerce.date(),
|
|
2575
|
+
cost: zod.z.object({ amount: zod.z.string(), asset: zod.z.string().nullable() }).nullable(),
|
|
2576
|
+
payment: zod.z.object({
|
|
2577
|
+
protocol: zod.z.string(),
|
|
2578
|
+
chain: zod.z.string().nullable(),
|
|
2579
|
+
txHash: zod.z.string().nullable(),
|
|
2580
|
+
mode: zod.z.string().nullable()
|
|
2581
|
+
}).nullable(),
|
|
2582
|
+
capability: zod.z.object({
|
|
2583
|
+
uid: zod.z.string(),
|
|
2584
|
+
slug: zod.z.string(),
|
|
2585
|
+
name: zod.z.string(),
|
|
2586
|
+
url: zod.z.string(),
|
|
2587
|
+
method: zod.z.string(),
|
|
2588
|
+
whatItDoes: zod.z.string().nullable(),
|
|
2589
|
+
tags: zod.z.array(zod.z.string())
|
|
2590
|
+
}),
|
|
2591
|
+
reviewed: zod.z.boolean()
|
|
2592
|
+
});
|
|
2593
|
+
var createReviewResponseSchema = zod.z.object({
|
|
2594
|
+
reviewId: zod.z.string(),
|
|
2595
|
+
recorded: zod.z.boolean(),
|
|
2596
|
+
updated: zod.z.boolean().optional()
|
|
2597
|
+
});
|
|
2598
|
+
var batchReviewResponseSchema = zod.z.object({
|
|
2599
|
+
results: zod.z.array(
|
|
2600
|
+
zod.z.union([
|
|
2601
|
+
zod.z.object({
|
|
2602
|
+
runId: zod.z.string(),
|
|
2603
|
+
ok: zod.z.literal(true),
|
|
2604
|
+
reviewId: zod.z.string(),
|
|
2605
|
+
updated: zod.z.boolean()
|
|
2606
|
+
}),
|
|
2607
|
+
zod.z.object({
|
|
2608
|
+
runId: zod.z.string(),
|
|
2609
|
+
ok: zod.z.literal(false),
|
|
2610
|
+
status: zod.z.number(),
|
|
2611
|
+
error: zod.z.string()
|
|
2612
|
+
})
|
|
2613
|
+
])
|
|
2614
|
+
),
|
|
2615
|
+
summary: zod.z.object({
|
|
2616
|
+
total: zod.z.number(),
|
|
2617
|
+
ok: zod.z.number(),
|
|
2618
|
+
failed: zod.z.number()
|
|
2619
|
+
})
|
|
2620
|
+
});
|
|
2621
|
+
|
|
2622
|
+
// src/namespaces/runs.ts
|
|
2623
|
+
var Runs = class {
|
|
2624
|
+
constructor(client) {
|
|
2625
|
+
this.client = client;
|
|
2480
2626
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2627
|
+
create = (input, opts = {}) => request(
|
|
2628
|
+
this.client,
|
|
2629
|
+
{
|
|
2630
|
+
method: "POST",
|
|
2631
|
+
path: "/v1/runs",
|
|
2632
|
+
body: input,
|
|
2633
|
+
signal: opts.signal
|
|
2634
|
+
},
|
|
2635
|
+
createRunResponseSchema
|
|
2636
|
+
);
|
|
2637
|
+
list = (params = {}, opts = {}) => {
|
|
2638
|
+
if (params.limit === 0) {
|
|
2639
|
+
if (opts.signal?.aborted) {
|
|
2640
|
+
return Promise.reject(
|
|
2641
|
+
new ZeroApiError("Request aborted by caller", { status: 0 })
|
|
2642
|
+
);
|
|
2643
|
+
}
|
|
2644
|
+
if (params.cursor === void 0) {
|
|
2645
|
+
return Promise.reject(
|
|
2646
|
+
new ZeroApiError(
|
|
2647
|
+
"runs.list({ limit: 0 }) requires a cursor \u2014 without one the empty page is indistinguishable from end-of-stream",
|
|
2648
|
+
{ status: 0 }
|
|
2649
|
+
)
|
|
2650
|
+
);
|
|
2491
2651
|
}
|
|
2652
|
+
return Promise.resolve({
|
|
2653
|
+
runs: [],
|
|
2654
|
+
nextCursor: params.cursor
|
|
2655
|
+
});
|
|
2492
2656
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
if (warnings.includes(FETCH_WARNINGS.mppSessionCloseFailed))
|
|
2510
|
-
return "payment_close_failed";
|
|
2511
|
-
if (status === 402 && payment !== null) return "payment_rejected";
|
|
2512
|
-
if (status === 402) return "payment_failed";
|
|
2513
|
-
if (status >= 400) return "server_error";
|
|
2514
|
-
return "success";
|
|
2515
|
-
};
|
|
2516
|
-
var errorFetchResult = (startedAt, error, skipReason, capabilityIdRequested, outcome, status = null) => {
|
|
2517
|
-
const result = {
|
|
2518
|
-
runId: null,
|
|
2519
|
-
ok: false,
|
|
2520
|
-
status,
|
|
2521
|
-
latencyMs: Date.now() - startedAt,
|
|
2522
|
-
payment: null,
|
|
2523
|
-
outcome,
|
|
2524
|
-
body: null,
|
|
2525
|
-
bodyRaw: null,
|
|
2526
|
-
error
|
|
2657
|
+
const query = {};
|
|
2658
|
+
if (params.capabilityId !== void 0)
|
|
2659
|
+
query.capabilityId = params.capabilityId;
|
|
2660
|
+
if (params.unreviewed !== void 0) query.unreviewed = params.unreviewed;
|
|
2661
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
2662
|
+
if (params.cursor !== void 0) query.cursor = params.cursor;
|
|
2663
|
+
return request(
|
|
2664
|
+
this.client,
|
|
2665
|
+
{
|
|
2666
|
+
method: "GET",
|
|
2667
|
+
path: "/v1/runs",
|
|
2668
|
+
query,
|
|
2669
|
+
signal: opts.signal
|
|
2670
|
+
},
|
|
2671
|
+
listRunsResponseSchema
|
|
2672
|
+
);
|
|
2527
2673
|
};
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
const result = errorFetchResult(
|
|
2559
|
-
startedAt,
|
|
2560
|
-
err.message,
|
|
2561
|
-
"timeout",
|
|
2562
|
-
capabilityIdRequested,
|
|
2563
|
-
"network_error"
|
|
2674
|
+
get = (runId, opts = {}) => request(
|
|
2675
|
+
this.client,
|
|
2676
|
+
{
|
|
2677
|
+
method: "GET",
|
|
2678
|
+
path: `/v1/runs/${runId}`,
|
|
2679
|
+
signal: opts.signal
|
|
2680
|
+
},
|
|
2681
|
+
runDetailSchema
|
|
2682
|
+
);
|
|
2683
|
+
review = (input, opts = {}) => request(
|
|
2684
|
+
this.client,
|
|
2685
|
+
{
|
|
2686
|
+
method: "POST",
|
|
2687
|
+
path: "/v1/reviews",
|
|
2688
|
+
body: input,
|
|
2689
|
+
signal: opts.signal
|
|
2690
|
+
},
|
|
2691
|
+
createReviewResponseSchema
|
|
2692
|
+
);
|
|
2693
|
+
// Bulk review submission. The CLI's bulk JSONL parser stays CLI-side —
|
|
2694
|
+
// SDK consumers pass already-parsed structured input.
|
|
2695
|
+
createReviewsBatch = (reviews, opts = {}) => request(
|
|
2696
|
+
this.client,
|
|
2697
|
+
{
|
|
2698
|
+
method: "POST",
|
|
2699
|
+
path: "/v1/reviews/batch",
|
|
2700
|
+
body: { reviews },
|
|
2701
|
+
signal: opts.signal
|
|
2702
|
+
},
|
|
2703
|
+
batchReviewResponseSchema
|
|
2564
2704
|
);
|
|
2565
|
-
await recordErrorFetchRun(client, opts, result);
|
|
2566
2705
|
};
|
|
2567
|
-
var
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2706
|
+
var USDC_BASE2 = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
2707
|
+
var USDC_TEMPO2 = "0x20c000000000000000000000b9537d11c60e8b50";
|
|
2708
|
+
var TEMPO_CHAIN_ID2 = 4217;
|
|
2709
|
+
var baseChain = chains.base;
|
|
2710
|
+
var tempoChain2 = {
|
|
2711
|
+
id: TEMPO_CHAIN_ID2,
|
|
2712
|
+
name: "Tempo",
|
|
2713
|
+
nativeCurrency: { name: "USD", symbol: "USD", decimals: 18 },
|
|
2714
|
+
rpcUrls: {
|
|
2715
|
+
default: { http: ["https://rpc.tempo.xyz"] }
|
|
2574
2716
|
}
|
|
2575
|
-
if (i >= buf.length) return false;
|
|
2576
|
-
return buf[i] === 123 || buf[i] === 91;
|
|
2577
2717
|
};
|
|
2578
|
-
var
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
if (!hasContentType) {
|
|
2586
|
-
next["content-type"] = typeof body === "string" || sniffJsonShapeBytes(body) ? "application/json" : "application/octet-stream";
|
|
2718
|
+
var ERC20_BALANCE_ABI2 = [
|
|
2719
|
+
{
|
|
2720
|
+
inputs: [{ name: "account", type: "address" }],
|
|
2721
|
+
name: "balanceOf",
|
|
2722
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
2723
|
+
stateMutability: "view",
|
|
2724
|
+
type: "function"
|
|
2587
2725
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
client,
|
|
2602
|
-
opts
|
|
2603
|
-
);
|
|
2604
|
-
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl(requestUrl), method).catch(() => null) : Promise.resolve(null);
|
|
2605
|
-
const probeHeaders = withDefaultContentType(opts.headers, requestBody);
|
|
2606
|
-
const requestInit = {
|
|
2607
|
-
method,
|
|
2608
|
-
headers: probeHeaders,
|
|
2609
|
-
body: requestBody,
|
|
2610
|
-
signal: opts.signal
|
|
2611
|
-
};
|
|
2612
|
-
const configuredFetch = buildConfiguredFetch(client, {
|
|
2613
|
-
timeoutMs: opts.timeoutMs
|
|
2614
|
-
});
|
|
2615
|
-
let response;
|
|
2616
|
-
let payment = null;
|
|
2617
|
-
const skipReasons = [];
|
|
2618
|
-
const warnings = [];
|
|
2619
|
-
try {
|
|
2620
|
-
response = await configuredFetch(requestUrl, requestInit);
|
|
2621
|
-
} catch (err) {
|
|
2622
|
-
if (err instanceof ZeroTimeoutError) {
|
|
2623
|
-
await recordTimeoutRun(
|
|
2624
|
-
client,
|
|
2625
|
-
opts,
|
|
2626
|
-
err,
|
|
2627
|
-
startedAt,
|
|
2628
|
-
capabilityIdRequested
|
|
2629
|
-
);
|
|
2630
|
-
throw err;
|
|
2631
|
-
}
|
|
2632
|
-
if (err instanceof ZeroError) throw err;
|
|
2633
|
-
const errMessage = err instanceof Error ? err.message : String(err);
|
|
2634
|
-
const result2 = errorFetchResult(
|
|
2635
|
-
startedAt,
|
|
2636
|
-
errMessage,
|
|
2637
|
-
"fetch_failed_before_response",
|
|
2638
|
-
capabilityIdRequested,
|
|
2639
|
-
"network_error"
|
|
2640
|
-
);
|
|
2641
|
-
await recordErrorFetchRun(client, opts, result2);
|
|
2642
|
-
return result2;
|
|
2726
|
+
];
|
|
2727
|
+
var USDC_DECIMALS = 6;
|
|
2728
|
+
|
|
2729
|
+
// src/namespaces/wallet.ts
|
|
2730
|
+
var fundingUrlResponseSchema = zod.z.object({ url: zod.z.string() });
|
|
2731
|
+
var userWalletListSchema = zod.z.array(userWalletDtoSchema);
|
|
2732
|
+
var migrateAuthorizationResponseSchema = zod.z.object({
|
|
2733
|
+
transactionHash: zod.z.string()
|
|
2734
|
+
});
|
|
2735
|
+
var errorMessage = (reason) => reason instanceof Error ? reason.message : String(reason);
|
|
2736
|
+
var Wallet = class {
|
|
2737
|
+
constructor(client) {
|
|
2738
|
+
this.client = client;
|
|
2643
2739
|
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
method,
|
|
2652
|
-
// Fresh clone for the paid retry — same rationale as
|
|
2653
|
-
// the probe-side clone above. Re-derives the default
|
|
2654
|
-
// Content-Type so the paid leg matches the probe.
|
|
2655
|
-
headers: withDefaultContentType(opts.headers, requestBody),
|
|
2656
|
-
body: requestBody,
|
|
2657
|
-
maxPay: opts.maxPay,
|
|
2658
|
-
account: opts.account,
|
|
2659
|
-
signal: opts.signal,
|
|
2660
|
-
timeoutMs: opts.timeoutMs,
|
|
2661
|
-
...opts.displayCostAmount && {
|
|
2662
|
-
displayCostAmount: opts.displayCostAmount
|
|
2663
|
-
}
|
|
2664
|
-
});
|
|
2665
|
-
response = paid.response;
|
|
2666
|
-
payment = paid.payment;
|
|
2667
|
-
if (paid.warnings) warnings.push(...paid.warnings);
|
|
2668
|
-
} catch (err) {
|
|
2669
|
-
if (err instanceof ZeroSessionCloseFailedError) {
|
|
2670
|
-
response = err.response;
|
|
2671
|
-
payment = {
|
|
2672
|
-
protocol: "mpp",
|
|
2673
|
-
chain: tempoChainLabelFromId(err.session.chainId),
|
|
2674
|
-
txHash: null,
|
|
2675
|
-
amount: err.capturedAmount,
|
|
2676
|
-
asset: "USDC",
|
|
2677
|
-
session: err.session
|
|
2678
|
-
};
|
|
2679
|
-
warnings.push(FETCH_WARNINGS.mppSessionCloseFailed);
|
|
2680
|
-
} else if (err instanceof ZeroInsufficientFundsError) {
|
|
2681
|
-
return errorFetchResult(
|
|
2682
|
-
startedAt,
|
|
2683
|
-
err.message,
|
|
2684
|
-
FETCH_SKIP_REASONS.insufficientFunds,
|
|
2685
|
-
capabilityIdRequested,
|
|
2686
|
-
"insufficient_funds",
|
|
2687
|
-
null
|
|
2688
|
-
);
|
|
2689
|
-
} else if (err instanceof ZeroPaymentError || err instanceof ZeroAuthError) {
|
|
2690
|
-
const result2 = errorFetchResult(
|
|
2691
|
-
startedAt,
|
|
2692
|
-
err.message,
|
|
2693
|
-
"payment_failed",
|
|
2694
|
-
capabilityIdRequested,
|
|
2695
|
-
"payment_failed",
|
|
2696
|
-
402
|
|
2697
|
-
);
|
|
2698
|
-
await recordErrorFetchRun(client, opts, result2);
|
|
2699
|
-
return result2;
|
|
2700
|
-
} else if (err instanceof ZeroTimeoutError) {
|
|
2701
|
-
await recordTimeoutRun(
|
|
2702
|
-
client,
|
|
2703
|
-
opts,
|
|
2704
|
-
err,
|
|
2705
|
-
startedAt,
|
|
2706
|
-
capabilityIdRequested
|
|
2707
|
-
);
|
|
2708
|
-
throw err;
|
|
2709
|
-
} else {
|
|
2710
|
-
throw err;
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
} else if (requirement?.protocol === "unknown") {
|
|
2714
|
-
const result2 = errorFetchResult(
|
|
2715
|
-
startedAt,
|
|
2716
|
-
"Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
|
|
2717
|
-
"unrecognized_402_protocol",
|
|
2718
|
-
capabilityIdRequested,
|
|
2719
|
-
"payment_failed",
|
|
2720
|
-
402
|
|
2721
|
-
);
|
|
2722
|
-
await recordErrorFetchRun(client, opts, result2);
|
|
2723
|
-
return result2;
|
|
2724
|
-
}
|
|
2740
|
+
clients = {};
|
|
2741
|
+
// The configured wallet address, or null if the client wasn't constructed
|
|
2742
|
+
// with an account. Stable read — does not hit the network.
|
|
2743
|
+
get address() {
|
|
2744
|
+
const credentials = this.client.getCredentials();
|
|
2745
|
+
if (credentials.kind !== "account") return null;
|
|
2746
|
+
return credentials.account.address;
|
|
2725
2747
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
const parsed = await parseResponseBody(response, maxResponseBytes);
|
|
2733
|
-
body = parsed.body;
|
|
2734
|
-
bodyRaw = parsed.bodyRaw;
|
|
2735
|
-
bodyEncoding = parsed.bodyEncoding;
|
|
2736
|
-
if (parsed.truncated) warnings.push(FETCH_WARNINGS.bodyTruncated);
|
|
2737
|
-
} catch (err) {
|
|
2738
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
2739
|
-
throw new ZeroApiError("Request aborted by caller", {
|
|
2740
|
-
status: 0,
|
|
2741
|
-
cause: err
|
|
2742
|
-
});
|
|
2748
|
+
balance = async (opts = {}) => {
|
|
2749
|
+
const target = opts.address ?? this.address;
|
|
2750
|
+
if (!target) {
|
|
2751
|
+
throw new ZeroWalletError(
|
|
2752
|
+
"balance() requires either an `address` option or a client constructed with an account"
|
|
2753
|
+
);
|
|
2743
2754
|
}
|
|
2744
|
-
const
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
warnings.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
2749
|
-
skips.push(FETCH_WARNINGS.paidButStill402NotRecorded);
|
|
2755
|
+
const chain = opts.chain ?? "total";
|
|
2756
|
+
if (chain !== "total") {
|
|
2757
|
+
const raw = await this.readChainBalance(chain, target);
|
|
2758
|
+
return { amount: viem.formatUnits(raw, USDC_DECIMALS), asset: "USDC" };
|
|
2750
2759
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2760
|
+
const chains = ["base", "tempo"];
|
|
2761
|
+
const settled = await Promise.allSettled(
|
|
2762
|
+
chains.map((c) => this.readChainBalance(c, target))
|
|
2763
|
+
);
|
|
2764
|
+
let sum = 0n;
|
|
2765
|
+
const errors = [];
|
|
2766
|
+
for (let i = 0; i < settled.length; i++) {
|
|
2767
|
+
const result = settled[i];
|
|
2768
|
+
const chainName = chains[i];
|
|
2769
|
+
if (!result || !chainName) continue;
|
|
2770
|
+
if (result.status === "fulfilled") {
|
|
2771
|
+
sum += result.value;
|
|
2772
|
+
} else {
|
|
2773
|
+
errors.push({ chain: chainName, message: errorMessage(result.reason) });
|
|
2774
|
+
}
|
|
2754
2775
|
}
|
|
2755
|
-
if (
|
|
2756
|
-
|
|
2776
|
+
if (errors.length === settled.length) {
|
|
2777
|
+
throw new ZeroWalletError(
|
|
2778
|
+
`balance() failed for every chain: ${errors.map((e) => `${e.chain} (${e.message})`).join(", ")}`
|
|
2779
|
+
);
|
|
2757
2780
|
}
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
ok: false,
|
|
2762
|
-
status: response.status,
|
|
2763
|
-
latencyMs: Date.now() - startedAt,
|
|
2764
|
-
payment,
|
|
2765
|
-
outcome: computeOutcome(response.status, payment, warnings),
|
|
2766
|
-
body: null,
|
|
2767
|
-
bodyRaw: null,
|
|
2768
|
-
error: message
|
|
2781
|
+
const balance = {
|
|
2782
|
+
amount: viem.formatUnits(sum, USDC_DECIMALS),
|
|
2783
|
+
asset: "USDC"
|
|
2769
2784
|
};
|
|
2770
|
-
if (
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
}
|
|
2783
|
-
let runId = null;
|
|
2784
|
-
const closeFailed = warnings.includes(FETCH_WARNINGS.mppSessionCloseFailed);
|
|
2785
|
-
const upstreamErrorForRecord = buildUpstreamError(
|
|
2786
|
-
response.status,
|
|
2787
|
-
bodyRaw,
|
|
2788
|
-
bodyEncoding
|
|
2785
|
+
if (errors.length > 0) balance.errors = errors;
|
|
2786
|
+
return balance;
|
|
2787
|
+
};
|
|
2788
|
+
// All wallets linked to the authenticated session user. Session-only.
|
|
2789
|
+
list = (opts = {}) => request(
|
|
2790
|
+
this.client,
|
|
2791
|
+
{
|
|
2792
|
+
method: "GET",
|
|
2793
|
+
path: "/v1/users/me/wallets",
|
|
2794
|
+
signal: opts.signal
|
|
2795
|
+
},
|
|
2796
|
+
userWalletListSchema
|
|
2789
2797
|
);
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
paymentProtocol: payment.protocol,
|
|
2845
|
-
paymentChain: payment.chain,
|
|
2846
|
-
paymentTxHash: payment.txHash ?? void 0,
|
|
2847
|
-
paymentMode: payment.session ? "session" : "charge"
|
|
2848
|
-
}
|
|
2849
|
-
});
|
|
2850
|
-
runId = result2.runId;
|
|
2851
|
-
} catch (err) {
|
|
2852
|
-
const errorMessage2 = err instanceof Error ? err.message : String(err);
|
|
2853
|
-
const code = err instanceof ZeroError ? err.code : void 0;
|
|
2854
|
-
const skipMsg = code ? `run_create_failed:${code}: ${errorMessage2}` : `run_create_failed: ${errorMessage2}`;
|
|
2855
|
-
skipReasons.push(skipMsg);
|
|
2856
|
-
client.logger?.({
|
|
2857
|
-
level: "warn",
|
|
2858
|
-
message: "Failed to record run for fetch",
|
|
2859
|
-
meta: {
|
|
2860
|
-
url: redactUrl(url),
|
|
2861
|
-
capabilityId: effectiveCapabilityId,
|
|
2862
|
-
error: errorMessage2,
|
|
2863
|
-
errorCode: code
|
|
2864
|
-
}
|
|
2798
|
+
// Provision a managed (Privy-embedded) wallet for the session user.
|
|
2799
|
+
// Idempotent server-side — repeat calls return the existing wallet.
|
|
2800
|
+
provision = (opts = {}) => request(
|
|
2801
|
+
this.client,
|
|
2802
|
+
{
|
|
2803
|
+
method: "POST",
|
|
2804
|
+
path: "/v1/users/me/wallets/provision",
|
|
2805
|
+
signal: opts.signal
|
|
2806
|
+
},
|
|
2807
|
+
userWalletDtoSchema
|
|
2808
|
+
);
|
|
2809
|
+
// Relays a BYO-wallet-signed EIP-3009 ReceiveWithAuthorization, sweeping
|
|
2810
|
+
// USDC from the BYO wallet to the user's Zero wallet on Base via the
|
|
2811
|
+
// gas-paying relayer. The SDK does not author the authorization (chain
|
|
2812
|
+
// nonce + EIP-712 domain coupling stays caller-side); it only forwards
|
|
2813
|
+
// the signed payload. Session-only.
|
|
2814
|
+
migrateAuthorization = (authorization, opts = {}) => request(
|
|
2815
|
+
this.client,
|
|
2816
|
+
{
|
|
2817
|
+
method: "POST",
|
|
2818
|
+
path: "/v1/users/me/wallets/migrate",
|
|
2819
|
+
body: { authorization },
|
|
2820
|
+
signal: opts.signal
|
|
2821
|
+
},
|
|
2822
|
+
migrateAuthorizationResponseSchema
|
|
2823
|
+
);
|
|
2824
|
+
// Routes by identity: account mode signs EIP-191 against /v1/wallet/fund-url,
|
|
2825
|
+
// session mode hits /v1/users/me/fund-url (Bearer-authed, wallet resolved
|
|
2826
|
+
// server-side). Both honor `provider` (coinbase | stripe).
|
|
2827
|
+
fundingUrl = async (opts = {}) => {
|
|
2828
|
+
const credentials = this.client.getCredentials();
|
|
2829
|
+
const path = credentials.kind === "account" ? "/v1/wallet/fund-url" : credentials.kind === "session" ? "/v1/users/me/fund-url" : null;
|
|
2830
|
+
if (!path) {
|
|
2831
|
+
throw new ZeroWalletError(
|
|
2832
|
+
"fundingUrl() requires a client constructed with an account or session credentials"
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
const query = {
|
|
2836
|
+
provider: opts.provider ?? "coinbase"
|
|
2837
|
+
};
|
|
2838
|
+
if (opts.amount) query.amount = opts.amount;
|
|
2839
|
+
const { url } = await request(
|
|
2840
|
+
this.client,
|
|
2841
|
+
{ method: "GET", path, query, signal: opts.signal },
|
|
2842
|
+
fundingUrlResponseSchema
|
|
2843
|
+
);
|
|
2844
|
+
return url;
|
|
2845
|
+
};
|
|
2846
|
+
getPublicClient = (chain) => {
|
|
2847
|
+
if (chain === "base") {
|
|
2848
|
+
if (!this.clients.base) {
|
|
2849
|
+
this.clients.base = viem.createPublicClient({
|
|
2850
|
+
chain: baseChain,
|
|
2851
|
+
transport: viem.http()
|
|
2865
2852
|
});
|
|
2866
2853
|
}
|
|
2854
|
+
return this.clients.base;
|
|
2867
2855
|
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
body,
|
|
2877
|
-
bodyRaw
|
|
2856
|
+
if (!this.clients.tempo) {
|
|
2857
|
+
this.clients.tempo = viem.createPublicClient({
|
|
2858
|
+
// biome-ignore lint/suspicious/noExplicitAny: tempo is a custom chain object that viem's stricter Chain type rejects shape-wise but accepts at runtime
|
|
2859
|
+
chain: tempoChain2,
|
|
2860
|
+
transport: viem.http()
|
|
2861
|
+
});
|
|
2862
|
+
}
|
|
2863
|
+
return this.clients.tempo;
|
|
2878
2864
|
};
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2865
|
+
/**
|
|
2866
|
+
* @internal
|
|
2867
|
+
*
|
|
2868
|
+
* Per-chain USDC balance read. Exposed (rather than private) so unit
|
|
2869
|
+
* tests can stub it without standing up a real viem public client —
|
|
2870
|
+
* viem's `http()` transport doesn't go through `client.fetchImpl`, so
|
|
2871
|
+
* the standard mock-fetch trick doesn't cover this path.
|
|
2872
|
+
*/
|
|
2873
|
+
readChainBalance = async (chain, address) => {
|
|
2874
|
+
const publicClient = this.getPublicClient(chain);
|
|
2875
|
+
const tokenAddress = chain === "base" ? USDC_BASE2 : USDC_TEMPO2;
|
|
2876
|
+
const balance = await publicClient.readContract({
|
|
2877
|
+
address: tokenAddress,
|
|
2878
|
+
abi: ERC20_BALANCE_ABI2,
|
|
2879
|
+
functionName: "balanceOf",
|
|
2880
|
+
args: [address]
|
|
2881
|
+
});
|
|
2882
|
+
return balance;
|
|
2883
|
+
};
|
|
2884
|
+
};
|
|
2885
|
+
|
|
2886
|
+
// src/options.ts
|
|
2887
|
+
var DEFAULT_BASE_URL = "https://api.zero.xyz";
|
|
2888
|
+
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
2889
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
2890
|
+
|
|
2891
|
+
// src/auth/credentials.ts
|
|
2892
|
+
var noopRefresh = async () => {
|
|
2892
2893
|
};
|
|
2893
2894
|
var searchResultSchema = zod.z.object({
|
|
2894
2895
|
id: zod.z.string(),
|
|
2896
|
+
// Opaque attribution token (format: `z_{shortId}.{position}`). Optional
|
|
2897
|
+
// so old API deploys that don't emit it still parse cleanly. Pass as
|
|
2898
|
+
// capabilityId to client.fetch() for exact search attribution.
|
|
2899
|
+
token: zod.z.string().nullable().optional(),
|
|
2895
2900
|
position: zod.z.number(),
|
|
2896
2901
|
slug: zod.z.string(),
|
|
2897
2902
|
name: zod.z.string(),
|
|
@@ -2910,6 +2915,9 @@ var searchResultSchema = zod.z.object({
|
|
|
2910
2915
|
cost: zod.z.object({ amount: zod.z.string(), asset: zod.z.string() }),
|
|
2911
2916
|
reviewCount: zod.z.number().optional(),
|
|
2912
2917
|
rating: ratingSchema,
|
|
2918
|
+
// All-time activation count (non-deleted runs), mirroring capabilities.ts.
|
|
2919
|
+
// Optional so a response from an older API deploy still parses (ZERO-385).
|
|
2920
|
+
activationCount: zod.z.number().optional(),
|
|
2913
2921
|
availabilityStatus: zod.z.enum(["healthy", "unknown", "down"]).nullable().optional(),
|
|
2914
2922
|
/**
|
|
2915
2923
|
* @deprecated The API no longer emits `displayStatus`; it has been replaced
|
|
@@ -3331,9 +3339,10 @@ exports.asSchemaNode = asSchemaNode;
|
|
|
3331
3339
|
exports.coerceTempoChainId = coerceTempoChainId;
|
|
3332
3340
|
exports.createManagedAccount = createManagedAccount;
|
|
3333
3341
|
exports.extractInputEnvelope = extractInputEnvelope;
|
|
3342
|
+
exports.isShortToken = isShortToken;
|
|
3334
3343
|
exports.normalizeTransportEnvelopeRequest = normalizeTransportEnvelopeRequest;
|
|
3335
3344
|
exports.paymentHasAnchor = paymentHasAnchor;
|
|
3336
3345
|
exports.tempoChainLabelFromId = tempoChainLabelFromId;
|
|
3337
3346
|
exports.unwrapTransportEnvelope = unwrapTransportEnvelope;
|
|
3338
|
-
//# sourceMappingURL=chunk-
|
|
3339
|
-
//# sourceMappingURL=chunk-
|
|
3347
|
+
//# sourceMappingURL=chunk-2HZJHVDN.cjs.map
|
|
3348
|
+
//# sourceMappingURL=chunk-2HZJHVDN.cjs.map
|