@zeroxyz/sdk 0.12.0 → 0.14.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 +19 -0
- package/README.md +20 -6
- package/dist/{chunk-O7424YAR.cjs → chunk-AM5RDERD.cjs} +259 -66
- package/dist/chunk-AM5RDERD.cjs.map +1 -0
- package/dist/{chunk-KDWESC42.js → chunk-FWHVWIO2.js} +259 -66
- package/dist/chunk-FWHVWIO2.js.map +1 -0
- package/dist/{client-DLwdMDSu.d.cts → client-DY7QGg57.d.cts} +31 -3
- package/dist/{client-DLwdMDSu.d.ts → client-DY7QGg57.d.ts} +31 -3
- package/dist/index.cjs +44 -44
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -2
- 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-KDWESC42.js.map +0 -1
- package/dist/chunk-O7424YAR.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ All notable changes to `@zeroxyz/sdk` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) — with the pre-1.0 caveat that minor versions may include breaking changes.
|
|
6
6
|
|
|
7
|
+
## 0.14.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Explicit payment-protocol selection** — `client.fetch(url, { paymentProtocol: "x402" | "mpp" })` forces one advertised rail instead of using the default x402-first negotiation order. Selection is strict: when the requested protocol is absent, the fetch fails without silently falling back. The CLI exposes the same control as `zero fetch --protocol x402|mpp`. (#785)
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **ZeroClick-style x402 identity-then-charge flows** — `client.fetch()` now handles one zero-value identity challenge before exactly one positive-value payment attempt, reparsing the fresh post-identity 402 instead of signing the stale `$0` challenge. `maxPay` still gates the real charge before signing, and any second positive-value challenge is refused before another payment authorization is created. (#785)
|
|
16
|
+
|
|
17
|
+
## 0.13.0
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Pay and sign from a non-primary wallet** — `client.fetch()`, `payments.pay()` / `payMpp()`, and `client.auth.signMessage/signTransaction/signTypedData` accept an optional `walletAddress` (session mode). The SDK resolves the named profile wallet for the payment intent's `from`, the managed signature, and the recorded run's attribution (`runs.create` gained the same optional `walletAddress`), so per-wallet run filters reflect which wallet acted. The wallet must be on the caller's profile. Default behavior (primary wallet) is unchanged. (ZERO-488)
|
|
22
|
+
- **`client.runs.list({ walletAddress })`** — narrow session run reads to specific profile wallets (string or string[]). Default remains all profile wallets; an address not on the profile is a server-side 400, never a silent intersection. (ZERO-488)
|
|
23
|
+
- **Wallet nicknames** — `client.wallet.setNickname({ walletAddress, nickname })` (null clears), optional `nickname` on `client.wallet.import()`, and `UserWalletDto.nickname`. Nicknames are private to the authenticated user. New export `SetNicknameOptions`. (ZERO-488)
|
|
24
|
+
- **`client.wallet.revokeDelegation()` / `client.wallet.reauthorizeDelegation()`** — per-wallet delegation lifecycle (default: the primary wallet). New export `DelegationOptions`. (ZERO-488)
|
|
25
|
+
|
|
7
26
|
## 0.12.0
|
|
8
27
|
|
|
9
28
|
### Added
|
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ The SDK refreshes the access token automatically after a `401`, and every refres
|
|
|
95
95
|
`client.fetch()` is the call you'll reach for most. Given a URL, it:
|
|
96
96
|
|
|
97
97
|
1. Sends the request.
|
|
98
|
-
2. If the server answers `402 Payment Required` (x402 or MPP), reads the payment challenge and pays it.
|
|
98
|
+
2. If the server answers `402 Payment Required` (x402 or MPP), reads the payment challenge and pays it. For x402 endpoints that use a zero-dollar identity challenge before the real charge, it handles one free identity stage followed by exactly one positive-value payment attempt.
|
|
99
99
|
3. Replays the request with proof of payment.
|
|
100
100
|
4. Returns the body, status, and payment metadata together.
|
|
101
101
|
5. Records a run on Zero when you pass a `capabilityId`, so the capability's reliability signal stays current and the call stays reviewable.
|
|
@@ -131,8 +131,10 @@ const result = await client.fetch(url, {
|
|
|
131
131
|
method: "POST",
|
|
132
132
|
headers: { "content-type": "application/json" },
|
|
133
133
|
body: JSON.stringify({ city: "tokyo" }),
|
|
134
|
-
|
|
134
|
+
maxPay: "0.01", // USDC ceiling; an over-cap challenge aborts before signing
|
|
135
|
+
paymentProtocol: "mpp", // optional: force "x402" or "mpp" when both are offered
|
|
135
136
|
capabilityId: "cap_abc", // attribute the run to a known capability
|
|
137
|
+
walletAddress: "0x…", // session mode: pay from this profile wallet (default: primary)
|
|
136
138
|
signal: controller.signal,
|
|
137
139
|
});
|
|
138
140
|
|
|
@@ -194,7 +196,7 @@ for (const warning of result.warnings ?? []) {
|
|
|
194
196
|
|
|
195
197
|
### `maxPay`
|
|
196
198
|
|
|
197
|
-
`maxPay` is your hard per-call ceiling, in USDC. The challenge
|
|
199
|
+
`maxPay` is your hard per-call ceiling, in USDC. The single positive-value challenge is checked **before** it is signed; a preceding zero-value identity handshake does not consume the cap. An over-cap challenge aborts with `outcome: "payment_failed"`, and a second positive-value challenge is refused before signing. Set `maxPay` on every paid call — it's the guardrail that keeps a mispriced or hostile endpoint from draining the wallet.
|
|
198
200
|
|
|
199
201
|
To put a human in the loop before any spend, read the price up front, show it to your user, and only call `fetch()` with `maxPay` once they approve. Prefer `capabilities.get()`'s **`pricing`** object when present: `pricing.summary` is the server-resolved display string (render it verbatim — don't re-derive from raw fields), `pricing.kind` classifies the shape (`static | dynamic | session | metered | subscription | free | unknown`), and `pricing.primary.amountUsd` / `depositUsd` give the structured numbers for sizing `maxPay`. `cost.amount` remains on every search result as the raw advertised scalar, but it flattens usage-priced caps — a `dynamic` cap's real cost scales with input.
|
|
200
202
|
|
|
@@ -230,20 +232,32 @@ await client.wallet.list(); // every wallet linked to the session user
|
|
|
230
232
|
await client.wallet.provision(); // create the user's managed wallet (idempotent)
|
|
231
233
|
|
|
232
234
|
// Link an existing self-custody wallet by private key (0x prefix optional).
|
|
233
|
-
// Pass makePrimary to have it pay for the user's calls from now on
|
|
235
|
+
// Pass makePrimary to have it pay for the user's calls from now on, and an
|
|
236
|
+
// optional nickname (owner-private display name, max 64 chars).
|
|
234
237
|
const imported = await client.wallet.import({
|
|
235
238
|
privateKey: "0x…",
|
|
236
239
|
makePrimary: true,
|
|
240
|
+
nickname: "Trading bot",
|
|
237
241
|
});
|
|
238
242
|
|
|
239
243
|
// Switch which linked wallet is primary, or unlink one. remove() rejects the
|
|
240
244
|
// primary wallet and any wallet holding a balance — reassign / drain first.
|
|
241
245
|
await client.wallet.setPrimary({ walletAddress: imported.walletAddress });
|
|
242
246
|
await client.wallet.remove({ walletAddress: "0x…" });
|
|
247
|
+
|
|
248
|
+
// Nickname a wallet (or clear with null). Nicknames are private to the
|
|
249
|
+
// authenticated user — they never appear on reviews or public surfaces.
|
|
250
|
+
await client.wallet.setNickname({ walletAddress: "0x…", nickname: "Cold storage" });
|
|
251
|
+
|
|
252
|
+
// Revoke / re-grant Zero's signing delegation per wallet (default: primary).
|
|
253
|
+
await client.wallet.revokeDelegation({ walletAddress: "0x…" });
|
|
254
|
+
await client.wallet.reauthorizeDelegation({ walletAddress: "0x…" });
|
|
243
255
|
```
|
|
244
256
|
|
|
245
257
|
`wallet.address()` covers the common case (resolve — or provision — the primary managed wallet); reach for the methods above when you need the full wallet objects, explicit provisioning, or multi-wallet management. Imported wallets carry an `importedAt` timestamp on the returned wallet objects.
|
|
246
258
|
|
|
259
|
+
To **pay from a non-primary wallet**, pass `walletAddress` on the call itself — `client.fetch(url, { walletAddress })` (or `payments.pay` / `payMpp`) resolves the named profile wallet for the payment intent's `from`, the managed signature, and the recorded run's attribution, and `client.auth.sign*` accept `{ walletAddress }` too. The wallet must be a delegated Privy-embedded wallet on the session user's profile. Runs can likewise be filtered per wallet: `client.runs.list({ walletAddress: ["0x…"] })` (default remains all profile wallets; an address not on the profile is a 400).
|
|
260
|
+
|
|
247
261
|
## Namespaces
|
|
248
262
|
|
|
249
263
|
Beyond `search()` and `fetch()`, the client groups the rest of the API into resource namespaces:
|
|
@@ -262,8 +276,8 @@ const cap = await client.capabilities.get("cap_abc"); // by uid
|
|
|
262
276
|
const cap2 = await client.capabilities.get("z_Ab12cd.1"); // by search token
|
|
263
277
|
|
|
264
278
|
// Wallet — balance, one-time funding URL, and (session mode) multi-wallet
|
|
265
|
-
// management: list / provision / import / setPrimary / remove
|
|
266
|
-
// "Wallet & funding" above.
|
|
279
|
+
// management: list / provision / import / setPrimary / remove / setNickname /
|
|
280
|
+
// revokeDelegation / reauthorizeDelegation. See "Wallet & funding" above.
|
|
267
281
|
const { amount } = await client.wallet.balance();
|
|
268
282
|
const fundUrl = await client.wallet.fundingUrl({ amount: "10" });
|
|
269
283
|
|
|
@@ -8,43 +8,46 @@ var client$1 = require('@x402/core/client');
|
|
|
8
8
|
var http = require('@x402/core/http');
|
|
9
9
|
var client = require('@x402/evm/exact/client');
|
|
10
10
|
var signInWithX = require('@x402/extensions/sign-in-with-x');
|
|
11
|
-
var fetch = require('@x402/fetch');
|
|
12
11
|
var mppx = require('mppx');
|
|
13
12
|
var client$2 = require('mppx/client');
|
|
14
13
|
var crypto$1 = require('crypto');
|
|
15
14
|
var zod = require('zod');
|
|
16
15
|
|
|
17
16
|
// src/auth/managed-account.ts
|
|
18
|
-
var createManagedAccount = (client, address) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
17
|
+
var createManagedAccount = (client, address, opts = {}) => {
|
|
18
|
+
const signOptions = {
|
|
19
|
+
// expectedAddress pins verification to this adapter's frozen address.
|
|
20
|
+
expectedAddress: address,
|
|
21
|
+
...opts.explicitWallet ? { walletAddress: address } : {}
|
|
22
|
+
};
|
|
23
|
+
return accounts.toAccount({
|
|
24
|
+
address,
|
|
25
|
+
async signMessage({ message }) {
|
|
26
|
+
return await client.auth.signMessage({ message }, signOptions);
|
|
27
|
+
},
|
|
28
|
+
async signTypedData(typedData) {
|
|
29
|
+
const td = typedData;
|
|
30
|
+
return await client.auth.signTypedData(
|
|
31
|
+
{
|
|
32
|
+
domain: td.domain,
|
|
33
|
+
types: td.types,
|
|
34
|
+
primaryType: td.primaryType,
|
|
35
|
+
message: td.message
|
|
36
|
+
},
|
|
37
|
+
signOptions
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
async signTransaction(transaction, options) {
|
|
41
|
+
const serialize = options?.serializer ?? viem.serializeTransaction;
|
|
42
|
+
const unsigned = await serialize(transaction);
|
|
43
|
+
const signature = await client.auth.signTransaction(
|
|
44
|
+
{ unsignedTransaction: unsigned },
|
|
45
|
+
signOptions
|
|
46
|
+
);
|
|
47
|
+
return await serialize(transaction, viem.parseSignature(signature));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
};
|
|
48
51
|
var USDC_BASE = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
49
52
|
var USDC_TEMPO = "0x20c000000000000000000000b9537d11c60e8b50";
|
|
50
53
|
var TEMPO_CHAIN_ID = 4217;
|
|
@@ -641,12 +644,12 @@ var cancelBody = (response) => {
|
|
|
641
644
|
} catch {
|
|
642
645
|
}
|
|
643
646
|
};
|
|
644
|
-
var resolveAccount = async (client, overrideAccount, signal) => {
|
|
647
|
+
var resolveAccount = async (client, overrideAccount, signal, walletAddress) => {
|
|
645
648
|
if (overrideAccount) return overrideAccount;
|
|
646
649
|
const credentials = client.getCredentials();
|
|
647
650
|
if (credentials.kind === "account") return credentials.account;
|
|
648
651
|
if (credentials.kind === "session") {
|
|
649
|
-
return await client.resolveManagedAccount(signal);
|
|
652
|
+
return await client.resolveManagedAccount(signal, walletAddress);
|
|
650
653
|
}
|
|
651
654
|
throw new ZeroAuthError(
|
|
652
655
|
"auth_no_credentials",
|
|
@@ -692,9 +695,13 @@ var Payments = class {
|
|
|
692
695
|
const account = await resolveAccount(
|
|
693
696
|
this.client,
|
|
694
697
|
input.account,
|
|
695
|
-
input.signal
|
|
698
|
+
input.signal,
|
|
699
|
+
input.walletAddress
|
|
696
700
|
);
|
|
697
701
|
let capturedAmount = null;
|
|
702
|
+
let pendingAmountUnits = 0n;
|
|
703
|
+
let identityChallengeHandled = false;
|
|
704
|
+
let paidChallengeHandled = false;
|
|
698
705
|
let capturedNetwork;
|
|
699
706
|
let preflightError = null;
|
|
700
707
|
const x402 = client.registerExactEvmScheme(new client$1.x402Client(), { signer: account });
|
|
@@ -723,11 +730,25 @@ var Payments = class {
|
|
|
723
730
|
};
|
|
724
731
|
}
|
|
725
732
|
const rawAmountUnits = BigInt(rawAmount);
|
|
726
|
-
|
|
733
|
+
pendingAmountUnits = rawAmountUnits;
|
|
734
|
+
const challengeAmount = viem.formatUnits(rawAmountUnits, 6);
|
|
735
|
+
if (rawAmountUnits === 0n) {
|
|
736
|
+
if (identityChallengeHandled || paidChallengeHandled) {
|
|
737
|
+
return {
|
|
738
|
+
abort: true,
|
|
739
|
+
reason: "Only one zero-value identity challenge is allowed, and it must precede payment."
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
} else if (paidChallengeHandled) {
|
|
743
|
+
return {
|
|
744
|
+
abort: true,
|
|
745
|
+
reason: "A positive-value x402 payment was already attempted for this fetch; refusing a second charge."
|
|
746
|
+
};
|
|
747
|
+
}
|
|
727
748
|
if (maxPayUnits !== null && rawAmountUnits > maxPayUnits) {
|
|
728
749
|
return {
|
|
729
750
|
abort: true,
|
|
730
|
-
reason: `Payment of ${
|
|
751
|
+
reason: `Payment of ${challengeAmount} USDC exceeds maxPay ${input.maxPay}`
|
|
731
752
|
};
|
|
732
753
|
}
|
|
733
754
|
const detected = networkToChain(capturedNetwork);
|
|
@@ -747,9 +768,10 @@ var Payments = class {
|
|
|
747
768
|
}
|
|
748
769
|
if (balance !== null && balance < rawAmountUnits) {
|
|
749
770
|
const have = viem.formatUnits(balance, 6);
|
|
771
|
+
const requiredAmount = viem.formatUnits(rawAmountUnits, 6);
|
|
750
772
|
preflightError = new ZeroInsufficientFundsError(
|
|
751
|
-
`wallet has ${have} USDC on Base, needs ${
|
|
752
|
-
{ have, need:
|
|
773
|
+
`wallet has ${have} USDC on Base, needs ${requiredAmount}.`,
|
|
774
|
+
{ have, need: requiredAmount }
|
|
753
775
|
);
|
|
754
776
|
return { abort: true, reason: preflightError.message };
|
|
755
777
|
}
|
|
@@ -760,18 +782,64 @@ var Payments = class {
|
|
|
760
782
|
const httpClient = new http.x402HTTPClient(x402).onPaymentRequired(
|
|
761
783
|
signInWithX.createSIWxClientHook(account)
|
|
762
784
|
);
|
|
763
|
-
const
|
|
764
|
-
withSynthesizedX402Header(configuredFetch),
|
|
765
|
-
httpClient
|
|
766
|
-
);
|
|
785
|
+
const paymentFetch = withSynthesizedX402Header(configuredFetch);
|
|
767
786
|
let response;
|
|
768
787
|
try {
|
|
769
|
-
|
|
788
|
+
const request2 = new Request(input.url, {
|
|
770
789
|
method: input.method ?? "GET",
|
|
771
790
|
headers: input.headers,
|
|
772
791
|
body: input.body,
|
|
773
792
|
signal: input.signal
|
|
774
793
|
});
|
|
794
|
+
response = await paymentFetch(request2.clone());
|
|
795
|
+
for (let paymentStage = 0; paymentStage < 2; paymentStage++) {
|
|
796
|
+
if (response.status !== 402) break;
|
|
797
|
+
const parseChallenge = async (challengeResponse) => {
|
|
798
|
+
let body;
|
|
799
|
+
try {
|
|
800
|
+
const text = await challengeResponse.clone().text();
|
|
801
|
+
if (text) body = JSON.parse(text);
|
|
802
|
+
} catch {
|
|
803
|
+
}
|
|
804
|
+
return httpClient.getPaymentRequiredResponse(
|
|
805
|
+
(name) => challengeResponse.headers.get(name),
|
|
806
|
+
body
|
|
807
|
+
);
|
|
808
|
+
};
|
|
809
|
+
let paymentRequired = await parseChallenge(response);
|
|
810
|
+
const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired);
|
|
811
|
+
if (hookHeaders) {
|
|
812
|
+
const hookRequest = request2.clone();
|
|
813
|
+
for (const [key, value] of Object.entries(hookHeaders)) {
|
|
814
|
+
hookRequest.headers.set(key, value);
|
|
815
|
+
}
|
|
816
|
+
response = await paymentFetch(hookRequest);
|
|
817
|
+
if (response.status === 402) {
|
|
818
|
+
paymentRequired = await parseChallenge(response);
|
|
819
|
+
} else {
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
pendingAmountUnits = 0n;
|
|
824
|
+
const paymentPayload = await x402.createPaymentPayload(paymentRequired);
|
|
825
|
+
if (pendingAmountUnits === 0n) {
|
|
826
|
+
identityChallengeHandled = true;
|
|
827
|
+
capturedAmount = "0";
|
|
828
|
+
} else {
|
|
829
|
+
paidChallengeHandled = true;
|
|
830
|
+
capturedAmount = viem.formatUnits(pendingAmountUnits, 6);
|
|
831
|
+
}
|
|
832
|
+
const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);
|
|
833
|
+
const paidRequest = request2.clone();
|
|
834
|
+
for (const [key, value] of Object.entries(paymentHeaders)) {
|
|
835
|
+
paidRequest.headers.set(key, value);
|
|
836
|
+
}
|
|
837
|
+
paidRequest.headers.set(
|
|
838
|
+
"Access-Control-Expose-Headers",
|
|
839
|
+
"PAYMENT-RESPONSE,X-PAYMENT-RESPONSE"
|
|
840
|
+
);
|
|
841
|
+
response = await paymentFetch(paidRequest);
|
|
842
|
+
}
|
|
775
843
|
} catch (err) {
|
|
776
844
|
if (preflightError) throw preflightError;
|
|
777
845
|
if (err instanceof ZeroError) throw err;
|
|
@@ -827,7 +895,8 @@ var Payments = class {
|
|
|
827
895
|
const account = await resolveAccount(
|
|
828
896
|
this.client,
|
|
829
897
|
input.account,
|
|
830
|
-
input.signal
|
|
898
|
+
input.signal,
|
|
899
|
+
input.walletAddress
|
|
831
900
|
);
|
|
832
901
|
const configuredFetch = buildConfiguredFetch(this.client, {
|
|
833
902
|
timeoutMs: input.timeoutMs
|
|
@@ -1338,8 +1407,17 @@ var cancelBody2 = (response) => {
|
|
|
1338
1407
|
} catch {
|
|
1339
1408
|
}
|
|
1340
1409
|
};
|
|
1341
|
-
var detectPaymentRequirement = async (response) => {
|
|
1410
|
+
var detectPaymentRequirement = async (response, preferredProtocol) => {
|
|
1342
1411
|
if (response.status !== 402) return null;
|
|
1412
|
+
const wwwAuth = response.headers.get("www-authenticate");
|
|
1413
|
+
const advertisesMpp = wwwAuth ? splitWwwAuthenticateChallenges(wwwAuth).some((challenge) => {
|
|
1414
|
+
const scheme = challenge.trim().split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
1415
|
+
return MPP_SCHEME_TOKENS.has(scheme);
|
|
1416
|
+
}) : false;
|
|
1417
|
+
if (preferredProtocol === "mpp") {
|
|
1418
|
+
cancelBody2(response);
|
|
1419
|
+
return advertisesMpp ? { protocol: "mpp", raw: { "www-authenticate": wwwAuth } } : { protocol: "unknown", raw: { requestedProtocol: "mpp" } };
|
|
1420
|
+
}
|
|
1343
1421
|
const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
|
|
1344
1422
|
if (x402Header) {
|
|
1345
1423
|
cancelBody2(response);
|
|
@@ -1369,15 +1447,13 @@ var detectPaymentRequirement = async (response) => {
|
|
|
1369
1447
|
} catch {
|
|
1370
1448
|
}
|
|
1371
1449
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
|
|
1380
|
-
}
|
|
1450
|
+
if (preferredProtocol === "x402") {
|
|
1451
|
+
cancelBody2(response);
|
|
1452
|
+
return { protocol: "unknown", raw: { requestedProtocol: "x402" } };
|
|
1453
|
+
}
|
|
1454
|
+
if (advertisesMpp) {
|
|
1455
|
+
cancelBody2(response);
|
|
1456
|
+
return { protocol: "mpp", raw: { "www-authenticate": wwwAuth } };
|
|
1381
1457
|
}
|
|
1382
1458
|
cancelBody2(response);
|
|
1383
1459
|
return { protocol: "unknown", raw: {} };
|
|
@@ -1607,7 +1683,8 @@ var recordErrorFetchRun = async (client, opts, result, capabilityIdOverride) =>
|
|
|
1607
1683
|
...fetchOriginForRecord && { fetchOrigin: fetchOriginForRecord },
|
|
1608
1684
|
...result.status !== null && { status: result.status },
|
|
1609
1685
|
latencyMs: result.latencyMs,
|
|
1610
|
-
...opts.requestSchema && { requestSchema: opts.requestSchema }
|
|
1686
|
+
...opts.requestSchema && { requestSchema: opts.requestSchema },
|
|
1687
|
+
...opts.walletAddress && !opts.account && { walletAddress: opts.walletAddress }
|
|
1611
1688
|
});
|
|
1612
1689
|
result.runId = created.runId;
|
|
1613
1690
|
delete result.runTrackingSkipped;
|
|
@@ -1702,7 +1779,10 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
1702
1779
|
return result2;
|
|
1703
1780
|
}
|
|
1704
1781
|
if (response.status === 402) {
|
|
1705
|
-
const requirement = await detectPaymentRequirement(
|
|
1782
|
+
const requirement = await detectPaymentRequirement(
|
|
1783
|
+
response,
|
|
1784
|
+
opts.paymentProtocol
|
|
1785
|
+
);
|
|
1706
1786
|
if (requirement?.protocol === "x402" || requirement?.protocol === "mpp") {
|
|
1707
1787
|
const payCall = requirement.protocol === "x402" ? client.payments.pay : client.payments.payMpp;
|
|
1708
1788
|
try {
|
|
@@ -1716,6 +1796,7 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
1716
1796
|
body: requestBody,
|
|
1717
1797
|
maxPay: opts.maxPay,
|
|
1718
1798
|
account: opts.account,
|
|
1799
|
+
...opts.walletAddress && { walletAddress: opts.walletAddress },
|
|
1719
1800
|
signal: opts.signal,
|
|
1720
1801
|
timeoutMs: opts.timeoutMs,
|
|
1721
1802
|
...opts.displayCostAmount && {
|
|
@@ -1773,7 +1854,7 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
1773
1854
|
} else if (requirement?.protocol === "unknown") {
|
|
1774
1855
|
const result2 = errorFetchResult(
|
|
1775
1856
|
startedAt,
|
|
1776
|
-
"Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
|
|
1857
|
+
opts.paymentProtocol ? `Capability did not advertise the requested ${opts.paymentProtocol} payment protocol.` : "Capability returned 402 with an unrecognized payment protocol. Neither x402 nor MPP markers were detected in the response headers or body.",
|
|
1777
1858
|
"unrecognized_402_protocol",
|
|
1778
1859
|
capabilityIdRequested,
|
|
1779
1860
|
"payment_failed",
|
|
@@ -1888,6 +1969,10 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
1888
1969
|
...opts.capabilityId === void 0 ? { fetchOrigin: "direct_url" } : opts.fetchOrigin && { fetchOrigin: opts.fetchOrigin },
|
|
1889
1970
|
status: response.status,
|
|
1890
1971
|
latencyMs,
|
|
1972
|
+
// Attribute to the selected wallet in session mode. Skipped when a
|
|
1973
|
+
// per-call `account` override records the run — that account's own
|
|
1974
|
+
// EIP-191 identity is the attribution.
|
|
1975
|
+
...opts.walletAddress && !opts.account && { walletAddress: opts.walletAddress },
|
|
1891
1976
|
...opts.requestSchema && { requestSchema: opts.requestSchema },
|
|
1892
1977
|
...derived?.responseSchema && {
|
|
1893
1978
|
responseSchema: derived.responseSchema
|
|
@@ -1953,7 +2038,7 @@ var clientFetch = async (client, url, opts = {}) => {
|
|
|
1953
2038
|
|
|
1954
2039
|
// package.json
|
|
1955
2040
|
var package_default = {
|
|
1956
|
-
version: "0.
|
|
2041
|
+
version: "0.14.0"};
|
|
1957
2042
|
|
|
1958
2043
|
// src/version.ts
|
|
1959
2044
|
var SDK_VERSION = package_default.version;
|
|
@@ -2443,6 +2528,9 @@ var userWalletDtoSchema = zod.z.object({
|
|
|
2443
2528
|
walletAddress: zod.z.string(),
|
|
2444
2529
|
source: zod.z.enum(["self_custody", "privy_embedded"]),
|
|
2445
2530
|
isPrimary: zod.z.boolean(),
|
|
2531
|
+
// Owner-chosen display name; null/absent = unnamed (show the address).
|
|
2532
|
+
// Optional so the SDK tolerates servers that predate nicknames.
|
|
2533
|
+
nickname: zod.z.string().nullable().optional(),
|
|
2446
2534
|
linkedAt: zod.z.union([zod.z.string(), zod.z.date()]).nullable().optional(),
|
|
2447
2535
|
importedAt: zod.z.union([zod.z.string(), zod.z.date()]).nullable().optional(),
|
|
2448
2536
|
delegationGranted: zod.z.boolean(),
|
|
@@ -2660,7 +2748,10 @@ var Auth = class {
|
|
|
2660
2748
|
{
|
|
2661
2749
|
method: "POST",
|
|
2662
2750
|
path: "/v1/users/me/sign-message",
|
|
2663
|
-
body: {
|
|
2751
|
+
body: {
|
|
2752
|
+
message: normalizeMessage(input.message),
|
|
2753
|
+
...opts.walletAddress ? { walletAddress: opts.walletAddress } : {}
|
|
2754
|
+
}
|
|
2664
2755
|
},
|
|
2665
2756
|
signResponseSchema
|
|
2666
2757
|
);
|
|
@@ -2685,7 +2776,10 @@ var Auth = class {
|
|
|
2685
2776
|
{
|
|
2686
2777
|
method: "POST",
|
|
2687
2778
|
path: "/v1/users/me/sign-transaction",
|
|
2688
|
-
body: {
|
|
2779
|
+
body: {
|
|
2780
|
+
unsignedTransaction: input.unsignedTransaction,
|
|
2781
|
+
...opts.walletAddress ? { walletAddress: opts.walletAddress } : {}
|
|
2782
|
+
}
|
|
2689
2783
|
},
|
|
2690
2784
|
signResponseSchema
|
|
2691
2785
|
);
|
|
@@ -2724,7 +2818,10 @@ var Auth = class {
|
|
|
2724
2818
|
{
|
|
2725
2819
|
method: "POST",
|
|
2726
2820
|
path: "/v1/users/me/sign-typed-data",
|
|
2727
|
-
body: {
|
|
2821
|
+
body: {
|
|
2822
|
+
typedData: input,
|
|
2823
|
+
...opts.walletAddress ? { walletAddress: opts.walletAddress } : {}
|
|
2824
|
+
}
|
|
2728
2825
|
},
|
|
2729
2826
|
signResponseSchema
|
|
2730
2827
|
);
|
|
@@ -3101,6 +3198,9 @@ var Runs = class {
|
|
|
3101
3198
|
if (params.unreviewed !== void 0) query.unreviewed = params.unreviewed;
|
|
3102
3199
|
if (params.limit !== void 0) query.limit = params.limit;
|
|
3103
3200
|
if (params.cursor !== void 0) query.cursor = params.cursor;
|
|
3201
|
+
if (params.walletAddress !== void 0) {
|
|
3202
|
+
query.walletAddress = Array.isArray(params.walletAddress) ? params.walletAddress.join(",") : params.walletAddress;
|
|
3203
|
+
}
|
|
3104
3204
|
return request(
|
|
3105
3205
|
this.client,
|
|
3106
3206
|
{
|
|
@@ -3236,6 +3336,50 @@ var Wallet = class {
|
|
|
3236
3336
|
},
|
|
3237
3337
|
userWalletDtoSchema
|
|
3238
3338
|
);
|
|
3339
|
+
// Re-stamp Zero's signing delegation on a profile wallet (default: the
|
|
3340
|
+
// primary). Session-only. Naming a wallet re-authorizes THAT wallet and
|
|
3341
|
+
// never provisions; the server 404s an address not on the profile.
|
|
3342
|
+
reauthorizeDelegation = (opts = {}) => request(
|
|
3343
|
+
this.client,
|
|
3344
|
+
{
|
|
3345
|
+
method: "POST",
|
|
3346
|
+
path: "/v1/users/me/wallets/provision",
|
|
3347
|
+
...opts.walletAddress ? { body: { walletAddress: opts.walletAddress } } : {},
|
|
3348
|
+
signal: opts.signal
|
|
3349
|
+
},
|
|
3350
|
+
userWalletDtoSchema
|
|
3351
|
+
);
|
|
3352
|
+
// Revoke Zero's signing delegation on a profile wallet (default: the
|
|
3353
|
+
// primary). Session-only. Managed signing on that wallet 403s until it is
|
|
3354
|
+
// re-authorized. Note: this stamps the server-side gate — removing Zero's
|
|
3355
|
+
// signer cryptographically is owner-authorized and happens in the user's
|
|
3356
|
+
// Privy session (the web profile page does both).
|
|
3357
|
+
revokeDelegation = (opts = {}) => request(
|
|
3358
|
+
this.client,
|
|
3359
|
+
{
|
|
3360
|
+
method: "DELETE",
|
|
3361
|
+
path: "/v1/users/me/wallets/delegation",
|
|
3362
|
+
...opts.walletAddress ? { query: { walletAddress: opts.walletAddress } } : {},
|
|
3363
|
+
signal: opts.signal
|
|
3364
|
+
},
|
|
3365
|
+
userWalletDtoSchema
|
|
3366
|
+
);
|
|
3367
|
+
// Set, change, or clear (null / empty string) the owner-chosen nickname on
|
|
3368
|
+
// a profile wallet. Session-only. Nicknames are private to the
|
|
3369
|
+
// authenticated user — they never appear on reviews or public surfaces.
|
|
3370
|
+
setNickname = (opts) => request(
|
|
3371
|
+
this.client,
|
|
3372
|
+
{
|
|
3373
|
+
method: "PATCH",
|
|
3374
|
+
path: "/v1/users/me/wallets/nickname",
|
|
3375
|
+
body: {
|
|
3376
|
+
walletAddress: opts.walletAddress,
|
|
3377
|
+
nickname: opts.nickname
|
|
3378
|
+
},
|
|
3379
|
+
signal: opts.signal
|
|
3380
|
+
},
|
|
3381
|
+
userWalletDtoSchema
|
|
3382
|
+
);
|
|
3239
3383
|
// Link an existing self-custody wallet to the session user by private key.
|
|
3240
3384
|
// Session-only. 409s when the wallet is already linked (to this or another
|
|
3241
3385
|
// profile — the error message says which).
|
|
@@ -3246,7 +3390,8 @@ var Wallet = class {
|
|
|
3246
3390
|
path: "/v1/users/me/wallets/import",
|
|
3247
3391
|
body: {
|
|
3248
3392
|
privateKey: opts.privateKey,
|
|
3249
|
-
...opts.makePrimary !== void 0 ? { makePrimary: opts.makePrimary } : {}
|
|
3393
|
+
...opts.makePrimary !== void 0 ? { makePrimary: opts.makePrimary } : {},
|
|
3394
|
+
...opts.nickname !== void 0 ? { nickname: opts.nickname } : {}
|
|
3250
3395
|
},
|
|
3251
3396
|
signal: opts.signal
|
|
3252
3397
|
},
|
|
@@ -3449,6 +3594,9 @@ var ZeroClient = class _ZeroClient {
|
|
|
3449
3594
|
managedAccountInFlight = null;
|
|
3450
3595
|
managedAccountAC = null;
|
|
3451
3596
|
managedAccountGen = 0;
|
|
3597
|
+
// Explicitly-selected (non-default) managed wallets, keyed by lowercased
|
|
3598
|
+
// address. Same lifecycle as managedAccount: cleared on clearManagedAccount.
|
|
3599
|
+
managedAccountByAddress = /* @__PURE__ */ new Map();
|
|
3452
3600
|
// Multi-tenant servers calling `client.fetch(url, { account: tenantAccount })`
|
|
3453
3601
|
// on every request would otherwise construct a new ZeroClient (with
|
|
3454
3602
|
// five namespace instances) per call. Keyed by lowercased account
|
|
@@ -3670,8 +3818,16 @@ var ZeroClient = class _ZeroClient {
|
|
|
3670
3818
|
}
|
|
3671
3819
|
this.withAccountCache.clear();
|
|
3672
3820
|
};
|
|
3673
|
-
/**
|
|
3674
|
-
|
|
3821
|
+
/**
|
|
3822
|
+
* @internal — used by payments.pay() in session mode. Cached, dedupes
|
|
3823
|
+
* concurrent lookups. Pass `walletAddress` to sign as a specific profile
|
|
3824
|
+
* wallet instead of the primary; explicit wallets are cached per address
|
|
3825
|
+
* and their sign requests carry the address so intent and signer agree.
|
|
3826
|
+
*/
|
|
3827
|
+
resolveManagedAccount = (signal, walletAddress) => {
|
|
3828
|
+
if (walletAddress) {
|
|
3829
|
+
return this.resolveManagedAccountByAddress(walletAddress, signal);
|
|
3830
|
+
}
|
|
3675
3831
|
if (this.managedAccount) return Promise.resolve(this.managedAccount);
|
|
3676
3832
|
if (this.managedAccountInFlight) {
|
|
3677
3833
|
return this.raceWithSignal(this.managedAccountInFlight, signal);
|
|
@@ -3713,6 +3869,42 @@ var ZeroClient = class _ZeroClient {
|
|
|
3713
3869
|
});
|
|
3714
3870
|
return this.raceWithSignal(this.managedAccountInFlight, signal);
|
|
3715
3871
|
};
|
|
3872
|
+
// Explicit-wallet variant of resolveManagedAccount. No in-flight dedupe:
|
|
3873
|
+
// this is the rare path (per-wallet pay), the resolution is idempotent, and
|
|
3874
|
+
// the per-address cache absorbs repeat calls.
|
|
3875
|
+
resolveManagedAccountByAddress = async (walletAddress, signal) => {
|
|
3876
|
+
if (this.credentials.kind !== "session") {
|
|
3877
|
+
throw new ZeroAuthError(
|
|
3878
|
+
"auth_no_credentials",
|
|
3879
|
+
"resolveManagedAccount() requires session credentials."
|
|
3880
|
+
);
|
|
3881
|
+
}
|
|
3882
|
+
const canonical = viem.getAddress(walletAddress);
|
|
3883
|
+
const cached = this.managedAccountByAddress.get(canonical.toLowerCase());
|
|
3884
|
+
if (cached) return cached;
|
|
3885
|
+
const startedAtGen = this.managedAccountGen;
|
|
3886
|
+
const wallets = await this.auth.wallets({ signal });
|
|
3887
|
+
const match = wallets.find(
|
|
3888
|
+
(w) => w.walletAddress.toLowerCase() === canonical.toLowerCase()
|
|
3889
|
+
);
|
|
3890
|
+
if (!match || match.source !== "privy_embedded") {
|
|
3891
|
+
throw new ZeroAuthError(
|
|
3892
|
+
"auth_error",
|
|
3893
|
+
`Wallet ${canonical} is not a Privy-embedded wallet on this profile. Managed signing can only use profile wallets (see client.wallet.list()).`
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
if (this.managedAccountGen !== startedAtGen) {
|
|
3897
|
+
throw new ZeroAuthError(
|
|
3898
|
+
"auth_session_expired",
|
|
3899
|
+
"Session cleared during managed-account resolution. Retry to rebuild against the current session."
|
|
3900
|
+
);
|
|
3901
|
+
}
|
|
3902
|
+
const acc = createManagedAccount(this, canonical, {
|
|
3903
|
+
explicitWallet: true
|
|
3904
|
+
});
|
|
3905
|
+
this.managedAccountByAddress.set(canonical.toLowerCase(), acc);
|
|
3906
|
+
return acc;
|
|
3907
|
+
};
|
|
3716
3908
|
// Per-caller signal gate: each caller can reject on their own abort
|
|
3717
3909
|
// without cancelling the shared underlying promise.
|
|
3718
3910
|
raceWithSignal = (p, signal) => {
|
|
@@ -3743,6 +3935,7 @@ var ZeroClient = class _ZeroClient {
|
|
|
3743
3935
|
this.managedAccountAC?.abort();
|
|
3744
3936
|
this.managedAccountInFlight = null;
|
|
3745
3937
|
this.managedAccountAC = null;
|
|
3938
|
+
this.managedAccountByAddress.clear();
|
|
3746
3939
|
this.managedAccountGen++;
|
|
3747
3940
|
};
|
|
3748
3941
|
/** @internal — Read cached managed account without triggering resolution. */
|
|
@@ -3835,5 +4028,5 @@ exports.normalizeTransportEnvelopeRequest = normalizeTransportEnvelopeRequest;
|
|
|
3835
4028
|
exports.paymentHasAnchor = paymentHasAnchor;
|
|
3836
4029
|
exports.tempoChainLabelFromId = tempoChainLabelFromId;
|
|
3837
4030
|
exports.unwrapTransportEnvelope = unwrapTransportEnvelope;
|
|
3838
|
-
//# sourceMappingURL=chunk-
|
|
3839
|
-
//# sourceMappingURL=chunk-
|
|
4031
|
+
//# sourceMappingURL=chunk-AM5RDERD.cjs.map
|
|
4032
|
+
//# sourceMappingURL=chunk-AM5RDERD.cjs.map
|