@zeroxyz/sdk 0.2.0 → 0.3.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 CHANGED
@@ -4,6 +4,16 @@ 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.3.0
8
+
9
+ ### Added
10
+
11
+ - `SearchResult` now carries `method` (the capability's HTTP verb) and `brandName`. Both are already returned by the search API but were previously stripped by the SDK's response schema. Surfacing `method` lets a caller tell GET from POST straight from a search result — enough to `fetch()` a no-body GET without a `capabilities.get()` round-trip. Both fields are optional, so a response that omits them still parses. (#593)
12
+
13
+ ### Documentation
14
+
15
+ - Expanded the README with a **Wallet & funding** section (`wallet.balance()` / `wallet.fundingUrl()`), the full `FetchResult` shape, the `runId`-requires-`capabilityId` precondition, and search → get → fetch guidance. (#593)
16
+
7
17
  ## 0.2.0
8
18
 
9
19
  ### Changed
package/README.md CHANGED
@@ -25,7 +25,7 @@ const client = new ZeroClient();
25
25
 
26
26
  const { capabilities } = await client.search("current weather in tokyo");
27
27
  for (const cap of capabilities) {
28
- console.log(cap.id, cap.name, cap.url, cap.availabilityStatus);
28
+ console.log(cap.id, cap.name, cap.method, cap.url, cap.availabilityStatus);
29
29
  }
30
30
  ```
31
31
 
@@ -102,6 +102,8 @@ The SDK refreshes the access token automatically after a `401`, and every refres
102
102
 
103
103
  Endpoints that don't charge pass straight through: a `200` on the first request returns with `payment: null` and `outcome: "success"`. No payment is attempted.
104
104
 
105
+ **Building the request — search → get → fetch.** A `search()` result carries the `url` and `method`, so a no-body `GET` capability can go straight to `fetch()`. For anything that takes a request body, call `capabilities.get()` first: its `bodySchema`, `method`, and `headers` are what tell you how to construct the call. Don't guess the body from the search summary.
106
+
105
107
  ```ts
106
108
  const result = await client.fetch(url, {
107
109
  method: "POST",
@@ -142,12 +144,65 @@ for (const warning of result.warnings ?? []) {
142
144
  }
143
145
  ```
144
146
 
147
+ ### The `FetchResult`
148
+
149
+ `fetch()` always resolves to one object — it doesn't reject for expected runtime failures (those come back as an `outcome`; see [Errors](#errors)). The full shape:
150
+
151
+ | Field | Type | Notes |
152
+ | --- | --- | --- |
153
+ | `outcome` | `FetchOutcome` | The closed enum above — branch on this first. |
154
+ | `ok` | `boolean` | `true` iff `status` is 2xx. Convenience for the HTTP-success check; `outcome === "success"` is the same signal at the payment-and-HTTP level. |
155
+ | `status` | `number \| null` | Upstream HTTP status; `null` if the request never reached the server. |
156
+ | `body` | `unknown` | Parsed JSON when the response is JSON, otherwise the text (base64 for binary). |
157
+ | `bodyRaw` | `string \| null` | The exact response text, for hashing/forwarding. `bodyEncoding: "base64"` is set when binary. |
158
+ | `payment` | `PaymentResult \| null` | `{ protocol, chain, txHash, amount, asset, … }` when a payment settled; `null` on a free call. |
159
+ | `runId` | `string \| null` | The recorded run, for `runs.review()`. **`null` unless you pass `capabilityId`** (and a wallet is configured). |
160
+ | `latencyMs` | `number` | End-to-end call latency. |
161
+ | `upstreamError` | `UpstreamError?` | Present on `server_error` — the capability's own 4xx/5xx detail. |
162
+ | `warnings` | `string[]?` | Non-fatal notes (truncated body, MPP close failure, …) — keyed by `FETCH_WARNINGS`. |
163
+ | `runTrackingSkipped` | `string[]?` | Why a run wasn't recorded (e.g. no `capabilityId`) — keyed by `FETCH_SKIP_REASONS`. |
164
+
165
+ `capabilityId` accepts the capability's `uid` (`cap_…`) or `slug` — i.e. the `id`/`slug` from a `search()` result or the `uid`/`slug` from `capabilities.get()`.
166
+
145
167
  ### `maxPay`
146
168
 
147
169
  `maxPay` is your hard per-call ceiling, in USDC. The challenge amount is checked against it **before** anything is signed; an over-cap challenge aborts with `outcome: "payment_failed"` and no on-chain spend. Set it on every paid call — it's the guardrail that keeps a mispriced or hostile endpoint from draining the wallet.
148
170
 
149
171
  To put a human in the loop before any spend, read the price up front (`cost.amount` is on every search result and on `capabilities.get()`), show it to your user, and only call `fetch()` with `maxPay` once they approve.
150
172
 
173
+ ## Wallet & funding
174
+
175
+ The wallet you construct the client with **is** the agent's identity — paid calls draw USDC from it, and there are no per-service API keys to provision. Keeping it funded is the only operational task. Two funding models, both first-class:
176
+
177
+ - **Partner-funded shared wallet** *(the common default).* You hold one wallet on behalf of all your users, keep it topped up as a backend cost, and recoup it through your own billing. Per-user spend tracking and caps live in your app — `maxPay` is the per-call guard.
178
+ - **End-user top-up.** Each user funds the wallet directly; you surface a funding link when their balance runs low. Pairs with a per-user wallet.
179
+
180
+ The same two primitives serve both:
181
+
182
+ ```ts
183
+ // The configured address (null in session mode until the first paid call resolves it).
184
+ client.wallet.address;
185
+
186
+ // Balance in USDC. Sums Base + Tempo by default; pass a chain for just one.
187
+ const { amount } = await client.wallet.balance(); // e.g. "12.50"
188
+ const onBase = await client.wallet.balance({ chain: "base" });
189
+
190
+ // A one-time hosted top-up link — Coinbase by default, or provider: "stripe".
191
+ // USDC settles on Base.
192
+ const url = await client.wallet.fundingUrl({ amount: "10" });
193
+ ```
194
+
195
+ Poll `balance()` to decide when to top up. Then either open `fundingUrl()` yourself to refill the shared wallet — from an ops dashboard, a low-balance alert, or alongside a direct USDC transfer to `wallet.address` — or hand the link to the end user. Either way the link is **single-use** and burns when opened, so generate it at the moment of funding and don't pre-open one you intend to give to someone else.
196
+
197
+ In **session mode** (acting for a Zero user) the wallet is Zero-managed, and a couple more methods apply:
198
+
199
+ ```ts
200
+ await client.wallet.list(); // every wallet linked to the session user
201
+ await client.wallet.provision(); // create the user's managed wallet (idempotent)
202
+ ```
203
+
204
+ To move funds from a user's own (BYO) wallet into their Zero-managed wallet, sign an EIP-3009 `ReceiveWithAuthorization` and relay it with `client.wallet.migrateAuthorization(authorization)` — Zero pays the gas and sweeps the USDC to Base.
205
+
151
206
  ## Namespaces
152
207
 
153
208
  Beyond `search()` and `fetch()`, the client groups the rest of the API into resource namespaces:
@@ -162,10 +217,9 @@ const { capabilities } = await client.search("translate text to french", {
162
217
  // Capabilities — full detail for one capability by id
163
218
  const cap = await client.capabilities.get("cap_abc");
164
219
 
165
- // Wallet (account or session mode)
166
- const balance = await client.wallet.balance(); // Base + Tempo
167
- const onBase = await client.wallet.balance({ chain: "base" }); // a single chain
168
- const fundUrl = await client.wallet.fundingUrl({ amount: "10" }); // onramp link
220
+ // Wallet balance + one-time funding URL. See "Wallet & funding" above.
221
+ const { amount } = await client.wallet.balance();
222
+ const fundUrl = await client.wallet.fundingUrl({ amount: "10" });
169
223
 
170
224
  // Runs — fetch() records these for you on paid calls; reach for them
171
225
  // directly when you want to log or review a call yourself
@@ -1098,7 +1098,7 @@ var Payments = class {
1098
1098
 
1099
1099
  // package.json
1100
1100
  var package_default = {
1101
- version: "0.2.0"};
1101
+ version: "0.3.0"};
1102
1102
 
1103
1103
  // src/version.ts
1104
1104
  var SDK_VERSION = package_default.version;
@@ -2677,8 +2677,15 @@ var searchResultSchema = z.object({
2677
2677
  slug: z.string(),
2678
2678
  name: z.string(),
2679
2679
  canonicalName: z.string().nullable().optional(),
2680
+ brandName: z.string().nullable().optional(),
2680
2681
  description: z.string(),
2681
2682
  whatItDoes: z.string().nullable().optional(),
2683
+ // HTTP verb the capability expects. Surfaced on the search row so a caller
2684
+ // can tell GET from POST without a `capabilities.get()` round-trip — enough
2685
+ // to `fetch()` a no-body GET directly. POST bodies still need `get()` for
2686
+ // the `bodySchema`. Optional (not required) so a response that omits it —
2687
+ // an older API deploy — still parses rather than failing the whole search.
2688
+ method: z.string().optional(),
2682
2689
  url: z.string(),
2683
2690
  urlTemplate: z.string().nullable().optional(),
2684
2691
  cost: z.object({ amount: z.string(), asset: z.string() }),
@@ -3076,5 +3083,5 @@ var ZeroClient = class _ZeroClient {
3076
3083
  };
3077
3084
 
3078
3085
  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 };
3079
- //# sourceMappingURL=chunk-SLXRHGE4.js.map
3080
- //# sourceMappingURL=chunk-SLXRHGE4.js.map
3086
+ //# sourceMappingURL=chunk-FH6C6TXR.js.map
3087
+ //# sourceMappingURL=chunk-FH6C6TXR.js.map