@zeroxyz/sdk 0.3.0 → 0.5.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 +11 -0
- package/README.md +14 -7
- package/dist/{chunk-LVK77C6A.cjs → chunk-ED754B5U.cjs} +124 -18
- package/dist/chunk-ED754B5U.cjs.map +1 -0
- package/dist/{chunk-FH6C6TXR.js → chunk-RY3VFSIE.js} +124 -18
- package/dist/chunk-RY3VFSIE.js.map +1 -0
- package/dist/{client-CEC0IuN3.d.cts → client-BKAiYZYS.d.cts} +23 -2
- package/dist/{client-CEC0IuN3.d.ts → client-BKAiYZYS.d.ts} +23 -2
- package/dist/index.cjs +31 -31
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- 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 +1 -1
- package/dist/chunk-FH6C6TXR.js.map +0 -1
- package/dist/chunk-LVK77C6A.cjs.map +0 -1
|
@@ -77,6 +77,16 @@ var ZeroPaymentError = class extends ZeroError {
|
|
|
77
77
|
this.name = "ZeroPaymentError";
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
+
var ZeroInsufficientFundsError = class extends ZeroError {
|
|
81
|
+
have;
|
|
82
|
+
need;
|
|
83
|
+
constructor(message, init) {
|
|
84
|
+
super("insufficient_funds", message, { cause: init.cause });
|
|
85
|
+
this.name = "ZeroInsufficientFundsError";
|
|
86
|
+
this.have = init.have;
|
|
87
|
+
this.need = init.need;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
80
90
|
var ZeroSessionCloseFailedError = class extends ZeroError {
|
|
81
91
|
session;
|
|
82
92
|
response;
|
|
@@ -423,7 +433,12 @@ var FETCH_SKIP_REASONS = Object.freeze({
|
|
|
423
433
|
bodyReadFailed: "body_read_failed",
|
|
424
434
|
mppSessionCloseFailedNotRecorded: "mpp_session_close_failed_not_recorded",
|
|
425
435
|
paidButStill402NotRecorded: FETCH_WARNINGS.paidButStill402NotRecorded,
|
|
426
|
-
paymentSettlementUnconfirmed: FETCH_WARNINGS.paymentSettlementUnconfirmed
|
|
436
|
+
paymentSettlementUnconfirmed: FETCH_WARNINGS.paymentSettlementUnconfirmed,
|
|
437
|
+
// Pre-sign abort: deliberately NOT recorded as a run — the wallet was
|
|
438
|
+
// empty before we reached the capability, so charging it as a 402 would
|
|
439
|
+
// corrupt cap reliability. The wallet funnel is tracked via the
|
|
440
|
+
// fetch_executed.outcome analytics event instead.
|
|
441
|
+
insufficientFunds: "insufficient_funds_not_recorded"
|
|
427
442
|
});
|
|
428
443
|
var MAX_RECEIPT_HEADER_BYTES = 8 * 1024;
|
|
429
444
|
var decodeSessionReceiptHeader = (header) => {
|
|
@@ -565,6 +580,7 @@ var Payments = class {
|
|
|
565
580
|
);
|
|
566
581
|
let capturedAmount = null;
|
|
567
582
|
let capturedNetwork;
|
|
583
|
+
let preflightError = null;
|
|
568
584
|
const x402 = registerExactEvmScheme(new x402Client(), { signer: account });
|
|
569
585
|
x402.onBeforePaymentCreation(async (context) => {
|
|
570
586
|
const selected = context.selectedRequirements;
|
|
@@ -598,6 +614,29 @@ var Payments = class {
|
|
|
598
614
|
reason: `Payment of ${capturedAmount} USDC exceeds maxPay ${input.maxPay}`
|
|
599
615
|
};
|
|
600
616
|
}
|
|
617
|
+
const detected = networkToChain(capturedNetwork);
|
|
618
|
+
const balanceChain = detected === "base-sepolia" ? "base-sepolia" : "base";
|
|
619
|
+
let balance = null;
|
|
620
|
+
try {
|
|
621
|
+
balance = await this.readUsdcBalance(account.address, balanceChain);
|
|
622
|
+
} catch (readErr) {
|
|
623
|
+
this.client.logger?.({
|
|
624
|
+
level: "warn",
|
|
625
|
+
message: "Pre-flight balance read failed; proceeding to attempt payment",
|
|
626
|
+
meta: {
|
|
627
|
+
chain: balanceChain,
|
|
628
|
+
error: readErr instanceof Error ? readErr.message : String(readErr)
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (balance !== null && balance < rawAmountUnits) {
|
|
633
|
+
const have = formatUnits(balance, 6);
|
|
634
|
+
preflightError = new ZeroInsufficientFundsError(
|
|
635
|
+
`wallet has ${have} USDC on Base, needs ${capturedAmount}.`,
|
|
636
|
+
{ have, need: capturedAmount }
|
|
637
|
+
);
|
|
638
|
+
return { abort: true, reason: preflightError.message };
|
|
639
|
+
}
|
|
601
640
|
});
|
|
602
641
|
const configuredFetch = buildConfiguredFetch(this.client, {
|
|
603
642
|
timeoutMs: input.timeoutMs
|
|
@@ -618,6 +657,7 @@ var Payments = class {
|
|
|
618
657
|
signal: input.signal
|
|
619
658
|
});
|
|
620
659
|
} catch (err) {
|
|
660
|
+
if (preflightError) throw preflightError;
|
|
621
661
|
if (err instanceof ZeroError) throw err;
|
|
622
662
|
throw new ZeroPaymentError(
|
|
623
663
|
`x402 payment failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -862,23 +902,29 @@ var Payments = class {
|
|
|
862
902
|
);
|
|
863
903
|
if (tempoBalance < requiredRaw) {
|
|
864
904
|
if (coerced.chain === "tempo-testnet") {
|
|
865
|
-
|
|
866
|
-
|
|
905
|
+
const have = formatUnits(tempoBalance, 6);
|
|
906
|
+
throw new ZeroInsufficientFundsError(
|
|
907
|
+
`Insufficient pathUSD on Tempo testnet: have ${have}, need ${capturedAmount}. Fund via the Tempo testnet faucet: https://docs.tempo.xyz/quickstart/faucet`,
|
|
908
|
+
{ have, need: capturedAmount }
|
|
867
909
|
);
|
|
868
910
|
}
|
|
869
|
-
await this.bridgeBaseToTempo(account, requiredRaw - tempoBalance
|
|
911
|
+
await this.bridgeBaseToTempo(account, requiredRaw - tempoBalance, {
|
|
912
|
+
isSessionDeposit: challenge.intent === "session",
|
|
913
|
+
depositTotal: capturedAmount
|
|
914
|
+
});
|
|
870
915
|
}
|
|
871
916
|
return capturedAmount;
|
|
872
917
|
};
|
|
873
|
-
bridgeBaseToTempo = async (account, requiredAmount) => {
|
|
918
|
+
bridgeBaseToTempo = async (account, requiredAmount, depositContext) => {
|
|
874
919
|
this.ensureRelayClient();
|
|
875
920
|
const baseBalance = await this.readUsdcBalance(account.address, "base");
|
|
876
921
|
const buffer = calculateBuffer(baseBalance);
|
|
877
922
|
const bridgeAmount = requiredAmount + buffer;
|
|
878
923
|
if (baseBalance < bridgeAmount) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
)
|
|
924
|
+
const have = formatUnits(baseBalance, 6);
|
|
925
|
+
const need = formatUnits(bridgeAmount, 6);
|
|
926
|
+
const message = depositContext?.isSessionDeposit ? `wallet has ${have} USDC on Base, but this capability pre-funds a ${depositContext.depositTotal} USDC MPP payment channel up front (the channel is deposited before the call, so it asks for more than a single charge). Needs ${need} on Base to open it \u2014 fund the wallet, or pass a smaller \`maxPay\` (e.g. '0.05') to size the channel down to one cheap call.` : `wallet has ${have} USDC on Base, needs ${need} to fund this capability's MPP payment channel (${formatUnits(requiredAmount, 6)} + ${formatUnits(buffer, 6)} buffer). Tip: pass a smaller \`maxPay\` (e.g. '0.05') to size a cheaper channel.`;
|
|
927
|
+
throw new ZeroInsufficientFundsError(message, { have, need });
|
|
882
928
|
}
|
|
883
929
|
this.client.logger?.({
|
|
884
930
|
level: "info",
|
|
@@ -1098,7 +1144,7 @@ var Payments = class {
|
|
|
1098
1144
|
|
|
1099
1145
|
// package.json
|
|
1100
1146
|
var package_default = {
|
|
1101
|
-
version: "0.
|
|
1147
|
+
version: "0.5.0"};
|
|
1102
1148
|
|
|
1103
1149
|
// src/version.ts
|
|
1104
1150
|
var SDK_VERSION = package_default.version;
|
|
@@ -1755,6 +1801,11 @@ var capabilityResponseSchema = z.object({
|
|
|
1755
1801
|
lastUsedAt: z.string().nullable().optional(),
|
|
1756
1802
|
lastSuccessfullyRanAt: z.string().nullable().optional()
|
|
1757
1803
|
});
|
|
1804
|
+
var resolveCapabilityResponseSchema = z.object({
|
|
1805
|
+
capabilityId: z.string(),
|
|
1806
|
+
capabilitySlug: z.string(),
|
|
1807
|
+
matchedVia: z.enum(["exact", "template"])
|
|
1808
|
+
});
|
|
1758
1809
|
|
|
1759
1810
|
// src/namespaces/capabilities.ts
|
|
1760
1811
|
var Capabilities = class {
|
|
@@ -1771,6 +1822,31 @@ var Capabilities = class {
|
|
|
1771
1822
|
},
|
|
1772
1823
|
capabilityResponseSchema
|
|
1773
1824
|
);
|
|
1825
|
+
// Resolve a raw endpoint URL + method back to the capability that owns it,
|
|
1826
|
+
// for the `zero fetch <url>` case where the client has no local search
|
|
1827
|
+
// context to match against (a memoized/cross-session URL). Returns null on
|
|
1828
|
+
// 404 — i.e. no match or an ambiguous multi-match, both of which the server
|
|
1829
|
+
// reports as 404 (resolveByUrl fails closed rather than mis-attribute).
|
|
1830
|
+
// The URL travels in the POST body so it stays out of access logs and is
|
|
1831
|
+
// never stored; the caller uses the returned capabilityId to record an
|
|
1832
|
+
// attributed run without the URL ever touching the run row (ZERO-335).
|
|
1833
|
+
resolveByUrl = async (url, method, opts = {}) => {
|
|
1834
|
+
try {
|
|
1835
|
+
return await request(
|
|
1836
|
+
this.client,
|
|
1837
|
+
{
|
|
1838
|
+
method: "POST",
|
|
1839
|
+
path: "/v1/capabilities/resolve",
|
|
1840
|
+
body: { url, method },
|
|
1841
|
+
signal: opts.signal
|
|
1842
|
+
},
|
|
1843
|
+
resolveCapabilityResponseSchema
|
|
1844
|
+
);
|
|
1845
|
+
} catch (err) {
|
|
1846
|
+
if (err instanceof ZeroApiError && err.status === 404) return null;
|
|
1847
|
+
throw err;
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1774
1850
|
};
|
|
1775
1851
|
var createRunResponseSchema = z.object({
|
|
1776
1852
|
runId: z.string()
|
|
@@ -2351,14 +2427,17 @@ var resolveRecordingClient = (client, opts) => {
|
|
|
2351
2427
|
const canRecord = opts.account !== void 0 || credentials.kind === "account" || credentials.kind === "session";
|
|
2352
2428
|
return { recordingClient, canRecord };
|
|
2353
2429
|
};
|
|
2354
|
-
var recordErrorFetchRun = async (client, opts, result) => {
|
|
2355
|
-
|
|
2430
|
+
var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride) => {
|
|
2431
|
+
const effectiveCapId = opts.capabilityId;
|
|
2432
|
+
if (effectiveCapId === void 0) return;
|
|
2356
2433
|
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
2357
2434
|
if (!canRecord) return;
|
|
2435
|
+
const fetchOriginForRecord = opts.capabilityId === void 0 ? "direct_url" : opts.fetchOrigin;
|
|
2358
2436
|
try {
|
|
2359
2437
|
const created = await recordingClient.runs.create({
|
|
2360
|
-
capabilityId:
|
|
2438
|
+
capabilityId: effectiveCapId,
|
|
2361
2439
|
...opts.searchId && { searchId: opts.searchId },
|
|
2440
|
+
...fetchOriginForRecord && { fetchOrigin: fetchOriginForRecord },
|
|
2362
2441
|
...result.status !== null && { status: result.status },
|
|
2363
2442
|
latencyMs: result.latencyMs,
|
|
2364
2443
|
...opts.requestSchema && { requestSchema: opts.requestSchema }
|
|
@@ -2368,7 +2447,7 @@ var recordErrorFetchRun = async (client, opts, result) => {
|
|
|
2368
2447
|
} catch {
|
|
2369
2448
|
}
|
|
2370
2449
|
};
|
|
2371
|
-
var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested) => {
|
|
2450
|
+
var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested, capabilityIdOverride) => {
|
|
2372
2451
|
const result = errorFetchResult(
|
|
2373
2452
|
startedAt,
|
|
2374
2453
|
err.message,
|
|
@@ -2405,6 +2484,11 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2405
2484
|
const startedAt = Date.now();
|
|
2406
2485
|
const capabilityIdRequested = opts.capabilityId !== void 0;
|
|
2407
2486
|
const method = opts.method ?? (opts.body !== void 0 ? "POST" : "GET");
|
|
2487
|
+
const { canRecord: canRecordForResolve } = resolveRecordingClient(
|
|
2488
|
+
client,
|
|
2489
|
+
opts
|
|
2490
|
+
);
|
|
2491
|
+
const resolvePromise = !capabilityIdRequested && canRecordForResolve ? client.capabilities.resolveByUrl(redactUrl(url), method).catch(() => null) : Promise.resolve(null);
|
|
2408
2492
|
const probeHeaders = withDefaultContentType(opts.headers, opts.body);
|
|
2409
2493
|
const requestInit = {
|
|
2410
2494
|
method,
|
|
@@ -2480,6 +2564,15 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2480
2564
|
session: err.session
|
|
2481
2565
|
};
|
|
2482
2566
|
warnings.push(FETCH_WARNINGS.mppSessionCloseFailed);
|
|
2567
|
+
} else if (err instanceof ZeroInsufficientFundsError) {
|
|
2568
|
+
return errorFetchResult(
|
|
2569
|
+
startedAt,
|
|
2570
|
+
err.message,
|
|
2571
|
+
FETCH_SKIP_REASONS.insufficientFunds,
|
|
2572
|
+
capabilityIdRequested,
|
|
2573
|
+
"insufficient_funds",
|
|
2574
|
+
null
|
|
2575
|
+
);
|
|
2483
2576
|
} else if (err instanceof ZeroPaymentError || err instanceof ZeroAuthError) {
|
|
2484
2577
|
const result2 = errorFetchResult(
|
|
2485
2578
|
startedAt,
|
|
@@ -2587,7 +2680,15 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2587
2680
|
else if (closeFailed)
|
|
2588
2681
|
skipReasons.push(FETCH_SKIP_REASONS.mppSessionCloseFailedNotRecorded);
|
|
2589
2682
|
}
|
|
2590
|
-
|
|
2683
|
+
const resolvedCap = await resolvePromise;
|
|
2684
|
+
const effectiveCapabilityId = opts.capabilityId ?? resolvedCap?.capabilityId;
|
|
2685
|
+
const capabilityResolution = !capabilityIdRequested && canRecordForResolve ? resolvedCap !== null ? {
|
|
2686
|
+
resolved: true,
|
|
2687
|
+
capabilityId: resolvedCap.capabilityId,
|
|
2688
|
+
capabilitySlug: resolvedCap.capabilitySlug,
|
|
2689
|
+
matchedVia: resolvedCap.matchedVia
|
|
2690
|
+
} : { resolved: false } : void 0;
|
|
2691
|
+
if (effectiveCapabilityId !== void 0 && !paidButStill402 && !closeFailed) {
|
|
2591
2692
|
const { recordingClient, canRecord } = resolveRecordingClient(client, opts);
|
|
2592
2693
|
if (!canRecord) {
|
|
2593
2694
|
skipReasons.push("no_credentials");
|
|
@@ -2607,8 +2708,11 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2607
2708
|
}
|
|
2608
2709
|
}
|
|
2609
2710
|
const result2 = await recordingClient.runs.create({
|
|
2610
|
-
capabilityId:
|
|
2711
|
+
capabilityId: effectiveCapabilityId,
|
|
2611
2712
|
searchId: opts.searchId,
|
|
2713
|
+
// Auto-resolved runs are always direct_url — they only fire when
|
|
2714
|
+
// no capabilityId was supplied (the direct_url path by definition).
|
|
2715
|
+
...opts.capabilityId === void 0 ? { fetchOrigin: "direct_url" } : opts.fetchOrigin && { fetchOrigin: opts.fetchOrigin },
|
|
2612
2716
|
status: response.status,
|
|
2613
2717
|
latencyMs,
|
|
2614
2718
|
...opts.requestSchema && { requestSchema: opts.requestSchema },
|
|
@@ -2641,7 +2745,7 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2641
2745
|
message: "Failed to record run for fetch",
|
|
2642
2746
|
meta: {
|
|
2643
2747
|
url: redactUrl(url),
|
|
2644
|
-
capabilityId:
|
|
2748
|
+
capabilityId: effectiveCapabilityId,
|
|
2645
2749
|
error: errorMessage2,
|
|
2646
2750
|
errorCode: code
|
|
2647
2751
|
}
|
|
@@ -2669,6 +2773,8 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
2669
2773
|
result.runTrackingSkipped = skipReasons;
|
|
2670
2774
|
}
|
|
2671
2775
|
if (warnings.length > 0) result.warnings = warnings;
|
|
2776
|
+
if (capabilityResolution !== void 0)
|
|
2777
|
+
result.capabilityResolution = capabilityResolution;
|
|
2672
2778
|
return result;
|
|
2673
2779
|
};
|
|
2674
2780
|
var searchResultSchema = z.object({
|
|
@@ -3083,5 +3189,5 @@ var ZeroClient = class _ZeroClient {
|
|
|
3083
3189
|
};
|
|
3084
3190
|
|
|
3085
3191
|
export { Auth, AuthDevice, BUG_REPORT_CATEGORIES, BugReports, Capabilities, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, FETCH_SKIP_REASONS, FETCH_WARNINGS, Payments, Runs, SDK_VERSION, TEMPO_CHAIN_ID, TEMPO_TESTNET_CHAIN_ID, Wallet, ZeroApiError, ZeroAuthError, ZeroClient, ZeroConfigurationError, ZeroError, ZeroPaymentError, ZeroSessionCloseFailedError, ZeroTimeoutError, ZeroValidationError, ZeroWalletError, coerceTempoChainId, createManagedAccount, paymentHasAnchor, tempoChainLabelFromId };
|
|
3086
|
-
//# sourceMappingURL=chunk-
|
|
3087
|
-
//# sourceMappingURL=chunk-
|
|
3192
|
+
//# sourceMappingURL=chunk-RY3VFSIE.js.map
|
|
3193
|
+
//# sourceMappingURL=chunk-RY3VFSIE.js.map
|