@zeroxyz/sdk 0.1.0 → 0.2.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,22 @@ 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.2.0
8
+
9
+ ### Changed
10
+
11
+ - The default per-leg fetch timeout is now **180s** (was 60s). It applies to each HTTP leg (the 402 probe and the paid retry), not as a wall-clock deadline. Sized from production: across 30 days of successful runs p50 is ~0.9s and p99 ~29s, but the slow tail is all legitimate generative media — Grok video (~95s), MiniMax music (~136s), Nano Banana / GPT-5 images (~80s) — which 60s false-timed-out _after_ payment had settled. 180s covers the full observed working range with headroom; it is nearly free because the timeout is a ceiling, not a wait (fast calls still return in ms). Override per-client via `timeout` or per-call via `FetchOptions.timeoutMs`. (#565)
12
+
13
+ ### Added
14
+
15
+ - `client.fetch()` now records a failed run when a fetch leg times out. Previously a per-leg timeout threw `ZeroTimeoutError` with no trace, so a slow-but-broken capability accrued zero failure signal (and a paid leg that timed out after settlement left no row for the spend). Both the probe and paid-retry legs now record a status-null (→ `network`) run as a best-effort side-effect before re-throwing the original `ZeroTimeoutError` — the typed-error retry/cancel contract is unchanged. Note: the recorded row has `payment: null` (no txHash on a mid-flight timeout), so it restores the reliability signal, not a financial trail. No-op without a `capabilityId`/credentials. (#566)
16
+
17
+ ## 0.1.1
18
+
19
+ ### Fixed
20
+
21
+ - `client.fetch()` now defaults the request `Content-Type` when a body is present and the caller set none — string bodies use `application/json`, byte bodies are sniffed (`{`/`[` ⇒ `application/json`, otherwise `application/octet-stream`). This mirrors the CLI's existing inference. Without it, strict providers (e.g. Locus MPP's `express.json()`) leave `req.body` undefined and crash reading a field off it (`Cannot read properties of undefined (reading '…')`), while lenient providers tolerate the omission — a confusing, provider-dependent failure. A caller-supplied `Content-Type` (any casing) always wins. (#560)
22
+
7
23
  ## 0.1.0
8
24
 
9
25
  Initial public release.
@@ -1100,7 +1100,7 @@ var Payments = class {
1100
1100
 
1101
1101
  // package.json
1102
1102
  var package_default = {
1103
- version: "0.1.0"};
1103
+ version: "0.2.0"};
1104
1104
 
1105
1105
  // src/version.ts
1106
1106
  var SDK_VERSION = package_default.version;
@@ -1152,7 +1152,13 @@ var deviceStartResponseSchema = zod.z.object({
1152
1152
  expiresAt: zod.z.number()
1153
1153
  });
1154
1154
  var devicePollResponseSchema = zod.z.union([
1155
- zod.z.object({ error: zod.z.literal("authorization_pending") }),
1155
+ // userCode + verificationUri are optional: older API deployments don't
1156
+ // echo them on pending.
1157
+ zod.z.object({
1158
+ error: zod.z.literal("authorization_pending"),
1159
+ userCode: zod.z.string().optional(),
1160
+ verificationUri: zod.z.string().optional()
1161
+ }),
1156
1162
  zod.z.object({ error: zod.z.literal("expired_token") }),
1157
1163
  zod.z.object({
1158
1164
  accessToken: zod.z.string(),
@@ -1426,7 +1432,11 @@ var AuthDevice = class {
1426
1432
  devicePollResponseSchema
1427
1433
  );
1428
1434
  if ("error" in parsed) {
1429
- return parsed.error === "authorization_pending" ? { status: "pending" } : { status: "expired" };
1435
+ return parsed.error === "authorization_pending" ? {
1436
+ status: "pending",
1437
+ userCode: parsed.userCode,
1438
+ verificationUri: parsed.verificationUri
1439
+ } : { status: "expired" };
1430
1440
  }
1431
1441
  return {
1432
1442
  status: "ok",
@@ -2074,7 +2084,7 @@ var Wallet = class {
2074
2084
 
2075
2085
  // src/options.ts
2076
2086
  var DEFAULT_BASE_URL = "https://api.zero.xyz";
2077
- var DEFAULT_TIMEOUT_MS = 6e4;
2087
+ var DEFAULT_TIMEOUT_MS = 18e4;
2078
2088
  var DEFAULT_MAX_RETRIES = 2;
2079
2089
 
2080
2090
  // src/auth/credentials.ts
@@ -2360,11 +2370,44 @@ var recordErrorFetchRun = async (client, opts, result) => {
2360
2370
  } catch {
2361
2371
  }
2362
2372
  };
2373
+ var recordTimeoutRun = async (client, opts, err, startedAt, capabilityIdRequested) => {
2374
+ const result = errorFetchResult(
2375
+ startedAt,
2376
+ err.message,
2377
+ "timeout",
2378
+ capabilityIdRequested,
2379
+ "network_error"
2380
+ );
2381
+ await recordErrorFetchRun(client, opts, result);
2382
+ };
2383
+ var sniffJsonShapeBytes = (buf) => {
2384
+ let i = 0;
2385
+ if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) {
2386
+ i = 3;
2387
+ }
2388
+ while (i < buf.length && (buf[i] === 32 || buf[i] === 9 || buf[i] === 10 || buf[i] === 13)) {
2389
+ i++;
2390
+ }
2391
+ if (i >= buf.length) return false;
2392
+ return buf[i] === 123 || buf[i] === 91;
2393
+ };
2394
+ var withDefaultContentType = (headers, body) => {
2395
+ if (!headers && body === void 0) return void 0;
2396
+ const next = headers ? { ...headers } : {};
2397
+ if (body === void 0) return next;
2398
+ const hasContentType = Object.keys(next).some(
2399
+ (k) => k.toLowerCase() === "content-type"
2400
+ );
2401
+ if (!hasContentType) {
2402
+ next["content-type"] = typeof body === "string" || sniffJsonShapeBytes(body) ? "application/json" : "application/octet-stream";
2403
+ }
2404
+ return next;
2405
+ };
2363
2406
  var clientFetch = async (client, url, opts = {}) => {
2364
2407
  const startedAt = Date.now();
2365
2408
  const capabilityIdRequested = opts.capabilityId !== void 0;
2366
2409
  const method = opts.method ?? (opts.body !== void 0 ? "POST" : "GET");
2367
- const probeHeaders = opts.headers ? { ...opts.headers } : void 0;
2410
+ const probeHeaders = withDefaultContentType(opts.headers, opts.body);
2368
2411
  const requestInit = {
2369
2412
  method,
2370
2413
  headers: probeHeaders,
@@ -2381,6 +2424,16 @@ var clientFetch = async (client, url, opts = {}) => {
2381
2424
  try {
2382
2425
  response = await configuredFetch(url, requestInit);
2383
2426
  } catch (err) {
2427
+ if (err instanceof ZeroTimeoutError) {
2428
+ await recordTimeoutRun(
2429
+ client,
2430
+ opts,
2431
+ err,
2432
+ startedAt,
2433
+ capabilityIdRequested
2434
+ );
2435
+ throw err;
2436
+ }
2384
2437
  if (err instanceof ZeroError) throw err;
2385
2438
  const errMessage = err instanceof Error ? err.message : String(err);
2386
2439
  const result2 = errorFetchResult(
@@ -2402,8 +2455,9 @@ var clientFetch = async (client, url, opts = {}) => {
2402
2455
  url,
2403
2456
  method,
2404
2457
  // Fresh clone for the paid retry — same rationale as
2405
- // the probe-side clone above.
2406
- headers: opts.headers ? { ...opts.headers } : void 0,
2458
+ // the probe-side clone above. Re-derives the default
2459
+ // Content-Type so the paid leg matches the probe.
2460
+ headers: withDefaultContentType(opts.headers, opts.body),
2407
2461
  body: opts.body,
2408
2462
  maxPay: opts.maxPay,
2409
2463
  account: opts.account,
@@ -2439,6 +2493,15 @@ var clientFetch = async (client, url, opts = {}) => {
2439
2493
  );
2440
2494
  await recordErrorFetchRun(client, opts, result2);
2441
2495
  return result2;
2496
+ } else if (err instanceof ZeroTimeoutError) {
2497
+ await recordTimeoutRun(
2498
+ client,
2499
+ opts,
2500
+ err,
2501
+ startedAt,
2502
+ capabilityIdRequested
2503
+ );
2504
+ throw err;
2442
2505
  } else {
2443
2506
  throw err;
2444
2507
  }
@@ -3044,5 +3107,5 @@ exports.coerceTempoChainId = coerceTempoChainId;
3044
3107
  exports.createManagedAccount = createManagedAccount;
3045
3108
  exports.paymentHasAnchor = paymentHasAnchor;
3046
3109
  exports.tempoChainLabelFromId = tempoChainLabelFromId;
3047
- //# sourceMappingURL=chunk-7STN754W.cjs.map
3048
- //# sourceMappingURL=chunk-7STN754W.cjs.map
3110
+ //# sourceMappingURL=chunk-LHS7KBN7.cjs.map
3111
+ //# sourceMappingURL=chunk-LHS7KBN7.cjs.map