@vapi-network/cli 0.9.2 → 0.9.4

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/dist/index.js CHANGED
@@ -39356,8 +39356,10 @@ var listingIdentitySchema = external_exports.looseObject({
39356
39356
  }).optional().catch(void 0)
39357
39357
  });
39358
39358
  var listingDisclosureShape = {
39359
- group: listingGroupSchema.optional(),
39360
- fee: listingFeeSchema.optional(),
39359
+ // Presentation metadata must not make an otherwise executable row vanish
39360
+ // when the registry adds a new group or changes the fee display shape.
39361
+ group: listingGroupSchema.optional().catch(void 0),
39362
+ fee: listingFeeSchema.optional().catch(void 0),
39361
39363
  verification: listingVerificationFieldSchema,
39362
39364
  liveness: listingLivenessSchema.optional().catch(void 0),
39363
39365
  conformance: listingConformanceSchema.optional().catch(void 0),
@@ -39365,11 +39367,13 @@ var listingDisclosureShape = {
39365
39367
  };
39366
39368
  var marketplaceBadgeCodeSchema = external_exports.enum([
39367
39369
  "live_x402",
39370
+ "mpp",
39368
39371
  "partner",
39369
39372
  "payout_wallet_confirmed",
39370
39373
  "vapi_verified",
39371
39374
  "external_catalog",
39372
- "approved_vendor"
39375
+ "approved_vendor",
39376
+ "unverified"
39373
39377
  ]);
39374
39378
  var marketplaceBadgeSchema = external_exports.looseObject({
39375
39379
  code: marketplaceBadgeCodeSchema,
@@ -39388,7 +39392,13 @@ var marketplaceCardSchema = external_exports.looseObject({
39388
39392
  summary: external_exports.string().trim().min(1).max(1e3),
39389
39393
  byline: external_exports.string().trim().min(1).max(160).optional(),
39390
39394
  bylineHref: marketplaceHrefSchema.optional(),
39391
- badges: external_exports.array(marketplaceBadgeSchema).max(8),
39395
+ badges: external_exports.preprocess(
39396
+ (badges) => Array.isArray(badges) ? badges.flatMap((badge) => {
39397
+ const parsed = marketplaceBadgeSchema.safeParse(badge);
39398
+ return parsed.success ? [parsed.data] : [];
39399
+ }) : badges,
39400
+ external_exports.array(marketplaceBadgeSchema).max(8)
39401
+ ),
39392
39402
  facts: external_exports.array(marketplacePublicFactSchema).max(12)
39393
39403
  });
39394
39404
  var marketplaceHitBase = {
@@ -44869,9 +44879,9 @@ function createPublicFetch(options) {
44869
44879
  });
44870
44880
  });
44871
44881
  }
44872
- function pinnedLookup(lookup) {
44882
+ function pinnedLookup(lookup2) {
44873
44883
  return (hostname3, dnsOptions, callback) => {
44874
- void lookup(normalizeHostname(hostname3)).then((addresses) => {
44884
+ void lookup2(normalizeHostname(hostname3)).then((addresses) => {
44875
44885
  if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
44876
44886
  callback(guardError(new URL(`https://${hostname3}`)), "");
44877
44887
  return;
@@ -46009,9 +46019,9 @@ function isRecord2(value) {
46009
46019
  var CALLABLE_CATEGORIES = ["ai", "data", "crypto", "compute", "search"];
46010
46020
  var callableCategorySchema = external_exports.enum(CALLABLE_CATEGORIES);
46011
46021
  var DISCOVERY_CATEGORIES = [...CALLABLE_CATEGORIES, "other"];
46012
- var discoveryCategorySchema = external_exports.enum(DISCOVERY_CATEGORIES);
46022
+ var discoveryCategorySchema = external_exports.string().trim().min(1);
46013
46023
  var CALLABLE_CATEGORY_SET = new Set(CALLABLE_CATEGORIES);
46014
- var serviceTierSchema = external_exports.enum(["listed", "verified", "partner"]);
46024
+ var serviceTierSchema = external_exports.string().trim().min(1);
46015
46025
  var discoveryEndpointSchema = external_exports.looseObject({
46016
46026
  name: external_exports.string(),
46017
46027
  method: external_exports.string(),
@@ -46041,6 +46051,24 @@ var discoveryEndpointSchema = external_exports.looseObject({
46041
46051
  asset: external_exports.string().refine(isSolanaAddress, "Expected a Solana base58 address."),
46042
46052
  payTo: external_exports.string().refine(isSolanaAddress, "Expected a Solana base58 address."),
46043
46053
  checkedAt: external_exports.iso.datetime()
46054
+ }),
46055
+ external_exports.looseObject({
46056
+ protocol: external_exports.literal("mpp"),
46057
+ intent: external_exports.enum(["charge", "authorize", "subscription"]).nullable(),
46058
+ method: external_exports.string().trim().min(1).max(40).nullable(),
46059
+ checkedAt: external_exports.iso.datetime(),
46060
+ // Keep common x402 properties readable on the union while making it
46061
+ // impossible for MPP metadata to masquerade as executable x402 terms.
46062
+ network: external_exports.never().optional(),
46063
+ payTo: external_exports.never().optional()
46064
+ }),
46065
+ external_exports.looseObject({
46066
+ // Future payment protocols remain visible to callers so the payment
46067
+ // layer can refuse them explicitly instead of discovery losing the row.
46068
+ protocol: external_exports.string().trim().min(1).max(40),
46069
+ checkedAt: external_exports.iso.datetime(),
46070
+ network: external_exports.never().optional(),
46071
+ payTo: external_exports.never().optional()
46044
46072
  })
46045
46073
  ]).optional()
46046
46074
  });
@@ -46134,7 +46162,7 @@ function resolveTarget(service, endpointName) {
46134
46162
  }
46135
46163
  if (targets.size !== 1) {
46136
46164
  const paymentNetworks = service.endpoints.flatMap(
46137
- (endpoint) => endpoint.payment ? [endpoint.payment.network] : []
46165
+ (endpoint) => typeof endpoint.payment?.network === "string" ? [endpoint.payment.network] : []
46138
46166
  );
46139
46167
  throw new DiscoveryCatalogError(
46140
46168
  "ambiguous_default",
@@ -47109,7 +47137,8 @@ function getVapiPaths(directory = process.env.VAPI_HOME?.trim() || join2(homedir
47109
47137
  keystore: join2(directory, "keystore.json"),
47110
47138
  receipts: join2(directory, "receipts.jsonl"),
47111
47139
  searches: join2(directory, "searches.jsonl"),
47112
- ledger: join2(directory, "spend-ledger.json")
47140
+ ledger: join2(directory, "spend-ledger.json"),
47141
+ updateCheck: join2(directory, "update-check.json")
47113
47142
  };
47114
47143
  }
47115
47144
  var getAgentCashPaths = getVapiPaths;
@@ -70373,7 +70402,7 @@ function windowsDataProtectionStore(platform2, run, env, installed) {
70373
70402
  };
70374
70403
  }
70375
70404
  function libsecretStore(platform2, run, installed) {
70376
- const lookup = async (name) => {
70405
+ const lookup2 = async (name) => {
70377
70406
  const result = await run(SECRET_TOOL_BINARY, [
70378
70407
  "lookup",
70379
70408
  "service",
@@ -70392,9 +70421,9 @@ function libsecretStore(platform2, run, installed) {
70392
70421
  available: installed(SECRET_TOOL_BINARY),
70393
70422
  platform: platform2,
70394
70423
  description: "the libsecret keyring",
70395
- get: lookup,
70424
+ get: lookup2,
70396
70425
  async has(name) {
70397
- return await lookup(name) !== void 0;
70426
+ return await lookup2(name) !== void 0;
70398
70427
  },
70399
70428
  async set(name, passphrase) {
70400
70429
  requirePassphrase(passphrase);
@@ -70416,7 +70445,7 @@ function libsecretStore(platform2, run, installed) {
70416
70445
  requireSuccess(result, `store the passphrase of ${name} in the secret service`);
70417
70446
  },
70418
70447
  async remove(name) {
70419
- const existed = await lookup(name) !== void 0;
70448
+ const existed = await lookup2(name) !== void 0;
70420
70449
  const result = await run(SECRET_TOOL_BINARY, [
70421
70450
  "clear",
70422
70451
  "service",
@@ -71479,6 +71508,8 @@ var VAULT_KEY_ACCOUNT = "vault-key";
71479
71508
  var VAULT_SESSION_ACCOUNT = "vault-session";
71480
71509
  var DEVICE_KEY_LENGTH = 32;
71481
71510
  var DEFAULT_SESSION_HOURS = 8;
71511
+ var RESTORE_GAP_LIMIT = 5;
71512
+ var MAX_RESTORE_ACCOUNTS = 1e4;
71482
71513
  var BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
71483
71514
  var deviceKeyOperations = Promise.resolve();
71484
71515
  var sessionSchema = external_exports.object({
@@ -71628,26 +71659,41 @@ async function restoreVault(args) {
71628
71659
  throw new VaultError("corrupt", "That recovery phrase is not valid.", { cause: error61 });
71629
71660
  }
71630
71661
  let seed;
71631
- let discoveredAccounts = 0;
71662
+ if (args.accountCount !== void 0 && (!Number.isSafeInteger(args.accountCount) || args.accountCount < 1 || args.accountCount > MAX_RESTORE_ACCOUNTS)) {
71663
+ throw new VaultError(
71664
+ "corrupt",
71665
+ `Account count must be a positive integer no greater than ${MAX_RESTORE_ACCOUNTS}.`
71666
+ );
71667
+ }
71668
+ let discoveredAccounts = args.accountCount ?? 0;
71669
+ let scannedAddresses = 0;
71632
71670
  try {
71633
71671
  seed = phraseToSeed(phrase);
71634
71672
  } catch (error61) {
71635
71673
  throw asVaultError2(error61, "Unable to derive an account while restoring the vault.");
71636
71674
  }
71637
71675
  try {
71638
- for (let index2 = 0; ; index2 += 1) {
71676
+ for (let index2 = 0, emptyRun = 0; args.accountCount === void 0; index2 += 1) {
71639
71677
  let address4;
71640
71678
  try {
71641
71679
  address4 = privateKeyToAccount(deriveEvmPrivateKey(seed, `m/44'/60'/0'/0/${index2}`)).address;
71642
71680
  } catch (error61) {
71643
71681
  throw asVaultError2(error61, "Unable to derive an account while restoring the vault.");
71644
71682
  }
71645
- if (!await args.probe(address4)) break;
71646
- discoveredAccounts += 1;
71683
+ const funded = await args.probe(address4);
71684
+ scannedAddresses += 1;
71685
+ if (funded) {
71686
+ discoveredAccounts = index2 + 1;
71687
+ emptyRun = 0;
71688
+ } else {
71689
+ emptyRun += 1;
71690
+ if (emptyRun === RESTORE_GAP_LIMIT) break;
71691
+ }
71647
71692
  }
71648
71693
  } finally {
71649
71694
  seed.fill(0);
71650
71695
  }
71696
+ args.onScanComplete?.(scannedAddresses);
71651
71697
  let vault;
71652
71698
  try {
71653
71699
  vault = await createVault({ path: args.path, key: args.key, phrase, now: args.now });
@@ -72136,6 +72182,26 @@ var WalletStore = class _WalletStore {
72136
72182
  }
72137
72183
  );
72138
72184
  }
72185
+ /** Checks a cached signer's current vault session without decrypting its account again. */
72186
+ async assertSigningAuthority(name) {
72187
+ const stored = await this.readVaultUnlocked();
72188
+ if (!stored?.protected || !stored.accounts.some((account) => account.name === name)) return;
72189
+ try {
72190
+ const key2 = await unlockProtectedVault({
72191
+ path: this.vaultPath,
72192
+ secrets: this.secrets,
72193
+ env: this.environment,
72194
+ now: () => this.now()
72195
+ });
72196
+ key2.fill(0);
72197
+ } catch (error61) {
72198
+ this.dropVaultCache();
72199
+ if (error61 instanceof VaultError && error61.code === "password_required") {
72200
+ throw new KeystoreError(VAULT_LOCKED_MESSAGE, { cause: error61 });
72201
+ }
72202
+ throw error61;
72203
+ }
72204
+ }
72139
72205
  /** Returns one wallet's vault signer, migrating its legacy keystore if needed. */
72140
72206
  async unlock(name, passphrase) {
72141
72207
  const wallet = this.resolve({ name });
@@ -77522,7 +77588,7 @@ function createRunBudget(args) {
77522
77588
  import { mkdir as mkdir15, writeFile as writeFile8 } from "node:fs/promises";
77523
77589
  import { arch, platform, release } from "node:os";
77524
77590
  import { join as join13 } from "node:path";
77525
- var VAPI_CLIENT_VERSION = "0.9.2";
77591
+ var VAPI_CLIENT_VERSION = "0.9.4";
77526
77592
  async function createSupportReport(options) {
77527
77593
  const message = options.message.trim();
77528
77594
  if (!message) throw new Error("Support report message must not be empty.");
@@ -77795,7 +77861,7 @@ async function completeX402Payment(args) {
77795
77861
  let paidAttempt;
77796
77862
  const requestStarted = nowMs();
77797
77863
  try {
77798
- paidAttempt = await args.send(paidRequest);
77864
+ paidAttempt = await args.send(paidRequest, quote);
77799
77865
  } catch (error61) {
77800
77866
  if (trace) trace.phases.requestMs = elapsed(nowMs, requestStarted);
77801
77867
  throw settlementUnknown(
@@ -77813,7 +77879,7 @@ async function completeX402Payment(args) {
77813
77879
  const settleStarted = nowMs();
77814
77880
  const settlement = parseSettlementResponse(paidResponse.headers);
77815
77881
  const settlementOutcome = classifySettlement(settlement);
77816
- const receiptSettlement = sanitizeReceiptValue(settlement, receiptSecrets);
77882
+ const receiptSettlement = sanitizeReturnedValue(settlement, receiptSecrets);
77817
77883
  if (trace) {
77818
77884
  const transaction2 = settlementTransaction(receiptSettlement);
77819
77885
  const explorerUrl = transaction2 ? explorerTransactionUrl(quote.accepted.network, transaction2) : void 0;
@@ -77890,6 +77956,7 @@ async function completeX402Payment(args) {
77890
77956
  trace.phases.requestMs = (trace.phases.requestMs ?? 0) + elapsed(nowMs, bodyStarted);
77891
77957
  }
77892
77958
  }
77959
+ body = sanitizeReturnedValue(body, receiptSecrets);
77893
77960
  }
77894
77961
  const result = {
77895
77962
  response: paidResponse,
@@ -77898,7 +77965,11 @@ async function completeX402Payment(args) {
77898
77965
  quote,
77899
77966
  payer,
77900
77967
  ...payment.paymentId ? { paymentId: payment.paymentId } : {},
77901
- settlement,
77968
+ paymentProof: sanitizeReturnedValue(
77969
+ paidResponse.headers.get("x-vapi-payment-proof"),
77970
+ receiptSecrets
77971
+ ),
77972
+ settlement: receiptSettlement,
77902
77973
  settlementOutcome
77903
77974
  };
77904
77975
  if (settlementOutcome === "succeeded" && args.ceilingSweep) {
@@ -78035,19 +78106,70 @@ function sanitizeThrownError(error61, secrets) {
78035
78106
  }
78036
78107
  return new Error(message, cause === void 0 ? void 0 : { cause });
78037
78108
  }
78038
- function sanitizeReceiptValue(value, secrets, depth = 0) {
78109
+ function sanitizeReturnedValue(value, secrets) {
78039
78110
  if (typeof value === "string") return redactKnownSecrets(value, secrets);
78040
- if (value === null || typeof value !== "object") return value;
78041
- if (depth >= 16) return "[redacted nested settlement value]";
78042
- if (Array.isArray(value)) {
78043
- return value.map((item) => sanitizeReceiptValue(item, secrets, depth + 1));
78111
+ if (!isPlainReturnedContainer(value)) return value;
78112
+ const nodes = /* @__PURE__ */ new WeakMap();
78113
+ const ordered = [];
78114
+ const nodeFor = (source) => {
78115
+ const existing = nodes.get(source);
78116
+ if (existing) return existing;
78117
+ const copy = Array.isArray(source) ? new Array(source.length) : Object.create(Object.getPrototypeOf(source));
78118
+ const node2 = { source, copy, parents: /* @__PURE__ */ new Set(), changed: false };
78119
+ nodes.set(source, node2);
78120
+ ordered.push(node2);
78121
+ return node2;
78122
+ };
78123
+ const root = nodeFor(value);
78124
+ for (let index2 = 0; index2 < ordered.length; index2 += 1) {
78125
+ const node2 = ordered[index2];
78126
+ for (const [key2, item] of Object.entries(node2.source)) {
78127
+ const safeKey = Array.isArray(node2.source) ? key2 : redactKnownSecrets(key2, secrets);
78128
+ if (safeKey !== key2) node2.changed = true;
78129
+ if (typeof item === "string") {
78130
+ const safeItem = redactKnownSecrets(item, secrets);
78131
+ defineReturnedProperty(node2.copy, safeKey, safeItem);
78132
+ if (safeItem !== item) node2.changed = true;
78133
+ } else if (isPlainReturnedContainer(item)) {
78134
+ const child = nodeFor(item);
78135
+ child.parents.add(node2);
78136
+ defineReturnedProperty(node2.copy, safeKey, child.copy);
78137
+ } else {
78138
+ defineReturnedProperty(node2.copy, safeKey, item);
78139
+ }
78140
+ }
78044
78141
  }
78045
- return Object.fromEntries(
78046
- Object.entries(value).map(([key2, item]) => [
78047
- redactKnownSecrets(key2, secrets),
78048
- sanitizeReceiptValue(item, secrets, depth + 1)
78049
- ])
78050
- );
78142
+ const changed = ordered.filter((node2) => node2.changed);
78143
+ for (let index2 = 0; index2 < changed.length; index2 += 1) {
78144
+ for (const parent of changed[index2].parents) {
78145
+ if (parent.changed) continue;
78146
+ parent.changed = true;
78147
+ changed.push(parent);
78148
+ }
78149
+ }
78150
+ for (const node2 of ordered) {
78151
+ for (const [key2, item] of Object.entries(node2.source)) {
78152
+ if (!isPlainReturnedContainer(item)) continue;
78153
+ const safeKey = Array.isArray(node2.source) ? key2 : redactKnownSecrets(key2, secrets);
78154
+ const child = nodes.get(item);
78155
+ defineReturnedProperty(node2.copy, safeKey, child.changed ? child.copy : item);
78156
+ }
78157
+ }
78158
+ return root.changed ? root.copy : value;
78159
+ }
78160
+ function defineReturnedProperty(target, key2, value) {
78161
+ Object.defineProperty(target, key2, {
78162
+ value,
78163
+ enumerable: true,
78164
+ configurable: true,
78165
+ writable: true
78166
+ });
78167
+ }
78168
+ function isPlainReturnedContainer(value) {
78169
+ if (Array.isArray(value)) return true;
78170
+ if (value === null || typeof value !== "object") return false;
78171
+ const prototype = Object.getPrototypeOf(value);
78172
+ return prototype === Object.prototype || prototype === null;
78051
78173
  }
78052
78174
  function redactKnownSecrets(value, secrets) {
78053
78175
  let redacted = value;
@@ -78082,9 +78204,7 @@ function possibleSettlement(quote, payment, payer, receipt) {
78082
78204
  payTo: quote.accepted.payTo,
78083
78205
  payer,
78084
78206
  ...payment.paymentId ? { paymentId: payment.paymentId } : {},
78085
- ...isSvmPaymentRequirements(quote.accepted) ? {
78086
- authorizationTransaction: "transaction" in payment.payload.payload ? payment.payload.payload.transaction : ""
78087
- } : "authorization" in payment.payload.payload ? {
78207
+ ...isSvmPaymentRequirements(quote.accepted) ? {} : "authorization" in payment.payload.payload ? {
78088
78208
  authorizationNonce: payment.payload.payload.authorization.nonce,
78089
78209
  authorizationExpiresAt: payment.payload.payload.authorization.validBefore
78090
78210
  } : {},
@@ -78462,13 +78582,22 @@ async function sendRouterChat(deps, routerBaseUrl, routerKey, request, keyUsed)
78462
78582
  }
78463
78583
  const body = await responseText(response);
78464
78584
  if (!response.ok) {
78465
- if (response.status === 429 || body.includes("Budget has been exceeded") || body.includes("ExceededBudget")) {
78585
+ if (/budget (?:has been )?exceeded|exceededbudget/iu.test(body)) {
78466
78586
  throw new RouterClientError(
78467
78587
  "budget_exhausted",
78468
78588
  "The Router key has no remaining budget.",
78469
78589
  response.status
78470
78590
  );
78471
78591
  }
78592
+ if (response.status === 429) {
78593
+ const retryAfter = response.headers.get("retry-after")?.trim();
78594
+ const retrySeconds = retryAfter !== void 0 && /^\d+$/u.test(retryAfter) ? Number(retryAfter) : void 0;
78595
+ throw new RouterClientError(
78596
+ "rate_limited",
78597
+ `The vAPI Router is rate limited. ${retrySeconds !== void 0 && Number.isFinite(retrySeconds) ? `Retry after ${retrySeconds} seconds.` : "Wait and retry shortly."}`,
78598
+ response.status
78599
+ );
78600
+ }
78472
78601
  if (response.status === 401) {
78473
78602
  throw new RouterClientError(
78474
78603
  "no_router_key",
@@ -87745,12 +87874,13 @@ var BODY_HEADER_NAMES = [
87745
87874
  "content-type"
87746
87875
  ];
87747
87876
  async function callService(args) {
87877
+ validateTimeoutSeconds(args.input.timeoutSeconds);
87748
87878
  const trace = createCallTrace(args);
87749
87879
  let execution;
87750
87880
  try {
87751
87881
  execution = await executeCallService(args, trace);
87752
87882
  } catch (error61) {
87753
- if (!(error61 instanceof VapiCallError && error61.code === "unsupported_network")) {
87883
+ if (!(error61 instanceof VapiCallError && (error61.code === "unsupported_network" || error61.code === "unsupported_payment"))) {
87754
87884
  await recordCallError(args, error61, trace).catch(() => void 0);
87755
87885
  }
87756
87886
  throw error61;
@@ -87864,6 +87994,8 @@ async function executeCallService(args, trace) {
87864
87994
  body: method === "GET" || method === "HEAD" ? void 0 : requestBody
87865
87995
  });
87866
87996
  const request = createRequest(headers);
87997
+ const probeTimeoutMs = input2.timeoutSeconds === void 0 ? args.timeoutMs ?? 3e4 : Math.min(input2.timeoutSeconds, 30) * 1e3;
87998
+ let requestTimeoutMs = probeTimeoutMs;
87867
87999
  const fetchWithGuardedRedirects = async (candidateRequest, followRedirects = true) => {
87868
88000
  let currentRequest = candidateRequest;
87869
88001
  let followedRedirects = 0;
@@ -87871,7 +88003,7 @@ async function executeCallService(args, trace) {
87871
88003
  const attempt = await fetchAttempt(
87872
88004
  fetchImpl,
87873
88005
  new Request(currentRequest.clone(), { redirect: "manual" }),
87874
- args.timeoutMs ?? 3e4
88006
+ requestTimeoutMs
87875
88007
  );
87876
88008
  const response = attempt.response;
87877
88009
  if (!isRedirectStatus2(response.status)) {
@@ -88026,7 +88158,12 @@ async function executeCallService(args, trace) {
88026
88158
  account,
88027
88159
  caps: args.spendCaps ?? config2.spendCaps,
88028
88160
  config: payableConfig(config2, account),
88029
- send: async (paidRequest) => {
88161
+ send: async (paidRequest, quote) => {
88162
+ requestTimeoutMs = paidRequestTimeoutMs(
88163
+ input2.timeoutSeconds,
88164
+ args.timeoutMs,
88165
+ quote.accepted.maxTimeoutSeconds
88166
+ );
88030
88167
  paidAttempt = await fetchWithGuardedRedirects(paidRequest, false);
88031
88168
  return paidAttempt;
88032
88169
  },
@@ -88065,7 +88202,7 @@ async function executeCallService(args, trace) {
88065
88202
  asset: completed.quote.accepted.asset,
88066
88203
  payTo: completed.quote.accepted.payTo,
88067
88204
  settlement: settlementWithExplorer2(completed.settlement, completed.quote.accepted.network),
88068
- proof: completed.response.headers.get("x-vapi-payment-proof")
88205
+ proof: completed.paymentProof
88069
88206
  },
88070
88207
  ...verificationFor(endpoint),
88071
88208
  ...expectedRequestFor(endpoint, completed.response.status)
@@ -88312,8 +88449,16 @@ async function resolveCallEndpoint(id2, endpointName, marketplaceHit, config2, f
88312
88449
  );
88313
88450
  }
88314
88451
  function registeredEndpoint(listing, verification) {
88452
+ const { payment, ...endpoint } = listing.endpoint;
88453
+ if (payment && (typeof payment.protocol === "string" || typeof payment.network !== "string")) {
88454
+ throw new VapiCallError(
88455
+ "unsupported_payment",
88456
+ `Payment protocol ${payment.protocol} is not supported. This client pays x402 exact USDC endpoints only.`
88457
+ );
88458
+ }
88315
88459
  return {
88316
- ...listing.endpoint,
88460
+ ...endpoint,
88461
+ ...payment ? { payment: { network: payment.network, payTo: payment.payTo } } : {},
88317
88462
  verification: verification ?? listing.service.verification,
88318
88463
  serviceNetworks: listing.service.networks,
88319
88464
  registered: true,
@@ -88475,7 +88620,7 @@ async function readResponseBody2(response) {
88475
88620
  async function fetchAttempt(fetchImpl, request, timeoutMs) {
88476
88621
  const controller = new AbortController();
88477
88622
  let rejectTimeout = null;
88478
- const timeoutError = new Error(`API request timed out after ${timeoutMs}ms.`);
88623
+ const timeoutError = new Error(`API request timed out after ${timeoutMs / 1e3} seconds.`);
88479
88624
  const timedOut = new Promise((_resolve, reject) => {
88480
88625
  rejectTimeout = reject;
88481
88626
  });
@@ -88515,6 +88660,19 @@ async function fetchAttempt(fetchImpl, request, timeoutMs) {
88515
88660
  throw error61;
88516
88661
  }
88517
88662
  }
88663
+ function validateTimeoutSeconds(timeoutSeconds) {
88664
+ if (timeoutSeconds !== void 0 && (!Number.isInteger(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 300)) {
88665
+ throw new Error("call timeoutSeconds must be an integer from 1 to 300 seconds.");
88666
+ }
88667
+ }
88668
+ function paidRequestTimeoutMs(timeoutSeconds, internalTimeoutMs, offerTimeoutSeconds) {
88669
+ const usableOfferTimeout = Number.isInteger(offerTimeoutSeconds) && offerTimeoutSeconds > 0 ? offerTimeoutSeconds : void 0;
88670
+ if (timeoutSeconds !== void 0) {
88671
+ return Math.min(timeoutSeconds, usableOfferTimeout ?? timeoutSeconds) * 1e3;
88672
+ }
88673
+ if (internalTimeoutMs !== void 0) return internalTimeoutMs;
88674
+ return usableOfferTimeout === void 0 ? 12e4 : Math.min(12e4, Math.max(3e4, usableOfferTimeout * 1e3));
88675
+ }
88518
88676
  function mapX402PaymentError(error61, resumeId) {
88519
88677
  if (!(error61 instanceof X402PaymentError)) return error61;
88520
88678
  if (error61.code === "payment_rejected") {
@@ -88530,9 +88688,10 @@ function mapX402PaymentError(error61, resumeId) {
88530
88688
  });
88531
88689
  }
88532
88690
  const resume = resumeId !== void 0 && error61.possibleSettlement?.authorizationNonce ? ` Check whether it settled with \`vapi pay --resume ${resumeId}\` before paying again.` : "";
88691
+ const timeoutDetail = error61.cause instanceof Error && error61.cause.message.startsWith("API request timed out after ") ? `${error61.cause.message} ` : "";
88533
88692
  return new VapiCallError(
88534
88693
  "settlement_unknown",
88535
- `${error61.message}${resume}`,
88694
+ `${timeoutDetail}${error61.message}${resume}`,
88536
88695
  error61.possibleSettlement,
88537
88696
  { cause: error61.cause }
88538
88697
  );
@@ -88664,13 +88823,7 @@ var inspectToolResultSchema = external_exports.object({
88664
88823
  liveness: listingLivenessSchema.optional(),
88665
88824
  conformance: listingConformanceSchema.optional(),
88666
88825
  identity: listingIdentitySchema.optional(),
88667
- payment: external_exports.object({
88668
- scheme: external_exports.literal("exact"),
88669
- network: external_exports.string(),
88670
- asset: external_exports.string(),
88671
- payTo: external_exports.string(),
88672
- checkedAt: external_exports.string()
88673
- }).nullable()
88826
+ payment: discoveryEndpointSchema.shape.payment.unwrap().nullable()
88674
88827
  });
88675
88828
  var callSearchInputSchema = external_exports.object({
88676
88829
  query: external_exports.string().trim().max(200).optional().describe("Capability, API, service, or request."),
@@ -88699,7 +88852,10 @@ var callPayInputSchema = external_exports.object({
88699
88852
  (value) => /^0x[0-9a-fA-F]{40}$/.test(value) || isSolanaAddress(value),
88700
88853
  "Expected an EVM or Solana address."
88701
88854
  ).optional(),
88702
- maxPriceUsd: external_exports.union([external_exports.number().nonnegative(), external_exports.string().regex(/^\d+(?:\.\d{1,6})?$/)]).optional()
88855
+ maxPriceUsd: external_exports.union([external_exports.number().nonnegative(), external_exports.string().regex(/^\d+(?:\.\d{1,6})?$/)]).optional(),
88856
+ timeoutSeconds: external_exports.number().int().min(1).max(300).optional().describe(
88857
+ "Seconds to wait for the paid response. Default: the provider's maxTimeoutSeconds, at most 120."
88858
+ )
88703
88859
  });
88704
88860
  var callSearch = defineAction({
88705
88861
  name: "call.search",
@@ -88962,7 +89118,7 @@ async function readResult(response, signal, secrets = []) {
88962
89118
  return {
88963
89119
  status: response.status,
88964
89120
  contentType: contentType === null ? null : redactKnownSecrets2(contentType, secrets),
88965
- body: sanitizeReturnedValue(await readResponseBody3(response, contentType, signal), secrets)
89121
+ body: sanitizeReturnedValue2(await readResponseBody3(response, contentType, signal), secrets)
88966
89122
  };
88967
89123
  }
88968
89124
  async function readResponseBody3(response, contentType, signal) {
@@ -89007,17 +89163,17 @@ function isJsonContentType2(value) {
89007
89163
  const mediaType = value?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
89008
89164
  return mediaType === "application/json" || mediaType.endsWith("+json");
89009
89165
  }
89010
- function sanitizeReturnedValue(value, secrets, depth = 0) {
89166
+ function sanitizeReturnedValue2(value, secrets, depth = 0) {
89011
89167
  if (typeof value === "string") return redactKnownSecrets2(value, secrets);
89012
89168
  if (value === null || typeof value !== "object") return value;
89013
89169
  if (depth >= 16) return "[redacted nested response value]";
89014
89170
  if (Array.isArray(value)) {
89015
- return value.map((item) => sanitizeReturnedValue(item, secrets, depth + 1));
89171
+ return value.map((item) => sanitizeReturnedValue2(item, secrets, depth + 1));
89016
89172
  }
89017
89173
  return Object.fromEntries(
89018
89174
  Object.entries(value).map(([key2, item]) => [
89019
89175
  redactKnownSecrets2(key2, secrets),
89020
- sanitizeReturnedValue(item, secrets, depth + 1)
89176
+ sanitizeReturnedValue2(item, secrets, depth + 1)
89021
89177
  ])
89022
89178
  );
89023
89179
  }
@@ -94523,7 +94679,13 @@ function toolError(error61) {
94523
94679
  {
94524
94680
  error: error61.message,
94525
94681
  code: error61.code,
94526
- ...error61.possibleSettlement ? { possibleSettlement: error61.possibleSettlement } : {},
94682
+ ...error61.possibleSettlement ? {
94683
+ possibleSettlement: Object.fromEntries(
94684
+ Object.entries(error61.possibleSettlement).filter(
94685
+ ([key2]) => key2 !== "authorizationTransaction"
94686
+ )
94687
+ )
94688
+ } : {},
94527
94689
  ...error61.paymentRejection ? { paymentRejection: error61.paymentRejection } : {},
94528
94690
  ...error61.confirmedSettlement ? { confirmedSettlement: error61.confirmedSettlement } : {}
94529
94691
  },
@@ -98017,7 +98179,7 @@ async function readProcessStdin() {
98017
98179
  }
98018
98180
 
98019
98181
  // src/version.ts
98020
- var CLI_VERSION = "0.9.2";
98182
+ var CLI_VERSION = "0.9.4";
98021
98183
 
98022
98184
  // src/status.ts
98023
98185
  async function statusCommand(argv, json2, io, dependencies) {
@@ -101519,7 +101681,7 @@ function createLocalRuntime(options) {
101519
101681
  const processCommand = options.processCommand ?? defaultProcessCommand;
101520
101682
  const ownsProcess = (handle, pid) => processCommand(pid)?.includes(runResultPath(home, handle.runId)) === true;
101521
101683
  const closeFd = options.closeFd ?? closeSync2;
101522
- const readFile29 = options.readFile ?? nodeReadFile;
101684
+ const readFile30 = options.readFile ?? nodeReadFile;
101523
101685
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
101524
101686
  const openLog = options.openLog ?? ((path) => {
101525
101687
  mkdirSync2(runsDirectory(home), { recursive: true, mode: 448 });
@@ -101574,7 +101736,7 @@ function createLocalRuntime(options) {
101574
101736
  return handle;
101575
101737
  },
101576
101738
  async status(handle) {
101577
- const result = await readResultFile(readFile29, runResultPath(home, handle.runId));
101739
+ const result = await readResultFile(readFile30, runResultPath(home, handle.runId));
101578
101740
  if (result !== void 0) return result;
101579
101741
  const pid = localPid(handle);
101580
101742
  if (pid === void 0 || handle.kind !== "local") {
@@ -101677,10 +101839,10 @@ function childArguments(member, run) {
101677
101839
  ...run.drawUsd ? ["--draw", run.drawUsd] : []
101678
101840
  ];
101679
101841
  }
101680
- async function readResultFile(readFile29, path) {
101842
+ async function readResultFile(readFile30, path) {
101681
101843
  let text;
101682
101844
  try {
101683
- text = await readFile29(path, "utf8");
101845
+ text = await readFile30(path, "utf8");
101684
101846
  } catch (error61) {
101685
101847
  if (hasCode3(error61, "ENOENT")) return void 0;
101686
101848
  return { state: "failed", detail: "unreadable result file" };
@@ -102530,7 +102692,7 @@ function isMcpInstallApp(value) {
102530
102692
  function serverEntry(home, registry2) {
102531
102693
  return {
102532
102694
  command: "npx",
102533
- args: ["-y", "vapi-network", "mcp"],
102695
+ args: ["-y", "vapi-network@latest", "mcp"],
102534
102696
  env: { VAPI_HOME: home, VAPI_REGISTRY_URL: registry2 }
102535
102697
  };
102536
102698
  }
@@ -102579,7 +102741,7 @@ function tomlConfig(existing, entry) {
102579
102741
  const block = [
102580
102742
  "[mcp_servers.vapi]",
102581
102743
  'command = "npx"',
102582
- 'args = ["-y", "vapi-network", "mcp"]',
102744
+ 'args = ["-y", "vapi-network@latest", "mcp"]',
102583
102745
  `env = { VAPI_HOME = "${escapeToml(entry.env.VAPI_HOME)}", VAPI_REGISTRY_URL = "${escapeToml(entry.env.VAPI_REGISTRY_URL)}" }`,
102584
102746
  ""
102585
102747
  ].join("\n");
@@ -102746,13 +102908,13 @@ async function sendConfig(dependencies) {
102746
102908
  // src/setup.ts
102747
102909
  import { rm as rm5 } from "node:fs/promises";
102748
102910
  import { join as join26 } from "node:path";
102749
- var SETUP_ARGUMENT_ERROR = "vapi setup accepts only --no-cloud-backup; a recovery phrase is typed at the prompt, never passed on the command line.";
102911
+ var SETUP_ARGUMENT_ERROR = `vapi setup accepts only --no-cloud-backup and --accounts <n> (1-${MAX_RESTORE_ACCOUNTS}); a recovery phrase is typed at the prompt, never passed on the command line.`;
102750
102912
  var VAULT_CHOICE = "Create a new vault, or restore one from a recovery phrase? [new/restore] ";
102751
102913
  async function setupCommand(argv, json2, io, dependencies) {
102752
102914
  let parsed;
102753
102915
  try {
102754
102916
  parsed = parseArguments(argv, {
102755
- valueOptions: /* @__PURE__ */ new Set(),
102917
+ valueOptions: /* @__PURE__ */ new Set(["--accounts"]),
102756
102918
  booleanOptions: /* @__PURE__ */ new Set(["--no-cloud-backup"]),
102757
102919
  maximumPositionals: 0
102758
102920
  });
@@ -102763,6 +102925,7 @@ async function setupCommand(argv, json2, io, dependencies) {
102763
102925
  const paths = getVapiPaths();
102764
102926
  const steps = [];
102765
102927
  const humanIo = json2 ? stderrIo(io) : io;
102928
+ const accountCount = parseAccountCount(parsed.one("--accounts"));
102766
102929
  if (!await fileExists2(paths.config)) {
102767
102930
  await writeDefaultConfig(paths.config, process.env, { networks: ["base"] });
102768
102931
  steps.push("config");
@@ -102773,6 +102936,7 @@ async function setupCommand(argv, json2, io, dependencies) {
102773
102936
  let changedVault = false;
102774
102937
  let changedAccount = false;
102775
102938
  let changedLink = false;
102939
+ let scannedAddresses;
102776
102940
  if (!await fileExists2(join26(paths.directory, "vault.json"))) {
102777
102941
  const choice = await vaultChoice(dependencies);
102778
102942
  if (choice === "restore") {
@@ -102780,12 +102944,14 @@ async function setupCommand(argv, json2, io, dependencies) {
102780
102944
  throw new Error("Restoring needs a terminal to type the phrase.");
102781
102945
  }
102782
102946
  const readSecret = dependencies.prompts?.secret ?? promptForSecret;
102783
- await restoreVaultFromPhrase(
102947
+ const restored = await restoreVaultFromPhrase(
102784
102948
  await readSecret("Recovery phrase: "),
102785
102949
  config2,
102786
102950
  humanIo,
102787
- dependencies
102951
+ dependencies,
102952
+ accountCount
102788
102953
  );
102954
+ scannedAddresses = restored.scannedAddresses;
102789
102955
  store = await WalletStore.open(paths.directory, {
102790
102956
  secrets: getSecretStore(dependencies),
102791
102957
  env: dependencies.env ?? process.env,
@@ -102838,22 +103004,35 @@ async function setupCommand(argv, json2, io, dependencies) {
102838
103004
  }
102839
103005
  if (json2) {
102840
103006
  io.stdout(
102841
- JSON.stringify({ vault, account, address: address4, linked, steps, cloudBackup })
103007
+ JSON.stringify({
103008
+ vault,
103009
+ account,
103010
+ address: address4,
103011
+ linked,
103012
+ steps,
103013
+ cloudBackup,
103014
+ ...scannedAddresses === void 0 ? {} : { scannedAddresses }
103015
+ })
102842
103016
  );
102843
103017
  }
102844
103018
  }
102845
- async function restoreVaultFromPhrase(phrase, config2, io, dependencies) {
103019
+ async function restoreVaultFromPhrase(phrase, config2, io, dependencies, accountCount) {
102846
103020
  const paths = getVapiPaths();
102847
103021
  const validatedPhrase = validateRecoveryPhrase(phrase);
102848
103022
  const readBalance3 = baseUsdcBalanceReader(config2, dependencies);
102849
103023
  const key2 = await loadOrCreateDeviceKey({ secrets: getSecretStore(dependencies) });
102850
103024
  let names;
103025
+ let scannedAddresses = 0;
102851
103026
  try {
102852
103027
  const restored = await restoreVault({
102853
103028
  path: join26(paths.directory, "vault.json"),
102854
103029
  key: key2,
102855
103030
  phrase: validatedPhrase,
102856
103031
  probe: async (address4) => await readBalance3(address4) > 0n,
103032
+ ...accountCount === void 0 ? {} : { accountCount },
103033
+ onScanComplete: (count) => {
103034
+ scannedAddresses = count;
103035
+ },
102857
103036
  ...dependencies.now === void 0 ? {} : { now: dependencies.now }
102858
103037
  });
102859
103038
  names = restored.accounts().map((account) => account.name);
@@ -102865,8 +103044,25 @@ async function restoreVaultFromPhrase(phrase, config2, io, dependencies) {
102865
103044
  ...names[0] === void 0 ? {} : { wallet: names[0] },
102866
103045
  detail: `${names.length} account(s)`
102867
103046
  });
102868
- io.stdout(`Vault restored with ${names.length} account(s): ${names.join(", ")}`);
102869
- return { names };
103047
+ io.stdout(
103048
+ `Vault restored with ${names.length} account(s): ${names.join(", ")}. ${scannedAddresses} address(es) scanned.`
103049
+ );
103050
+ return { names, scannedAddresses };
103051
+ }
103052
+ function parseAccountCount(value) {
103053
+ if (value === void 0) return void 0;
103054
+ if (!/^\d+$/u.test(value)) {
103055
+ throw new UsageError(
103056
+ `--accounts must be a positive integer no greater than ${MAX_RESTORE_ACCOUNTS}.`
103057
+ );
103058
+ }
103059
+ const count = Number(value);
103060
+ if (!Number.isSafeInteger(count) || count < 1 || count > MAX_RESTORE_ACCOUNTS) {
103061
+ throw new UsageError(
103062
+ `--accounts must be a positive integer no greater than ${MAX_RESTORE_ACCOUNTS}.`
103063
+ );
103064
+ }
103065
+ return count;
102870
103066
  }
102871
103067
  async function vaultChoice(dependencies) {
102872
103068
  const answer = dependencies.prompts?.line === void 0 ? isInteractive(dependencies) ? await promptForLine(VAULT_CHOICE) : "" : await dependencies.prompts.line(VAULT_CHOICE);
@@ -104974,6 +105170,7 @@ async function referencedSleep(milliseconds, signal) {
104974
105170
  // src/vault.ts
104975
105171
  import { join as join27 } from "node:path";
104976
105172
  var VAULT_USAGE = "Usage: vapi vault protect|unprotect|lock|unlock|status [--json]";
105173
+ var RESTORE_USAGE = "Usage: vapi restore [--accounts <n> | --from-owner [--owner <0x\u2026>]] [--json]";
104977
105174
  var LEGACY_PASSWORD_NOTICE = "VAPI_KEYSTORE_PASSWORD is deprecated for vault passwords; use VAPI_VAULT_PASSWORD instead.";
104978
105175
  async function vaultCommand(argv, json2, io, dependencies) {
104979
105176
  const subcommand = argv[0];
@@ -105003,9 +105200,17 @@ async function restoreCommand(argv, json2, io, dependencies) {
105003
105200
  await restoreFromOwnerCommand(argv, json2, io, dependencies);
105004
105201
  return;
105005
105202
  }
105006
- if (argv.length > 0) {
105007
- throw new UsageError("Usage: vapi restore [--from-owner [--owner <0x\u2026>]] [--json]");
105203
+ let parsed;
105204
+ try {
105205
+ parsed = parseArguments(argv, {
105206
+ valueOptions: /* @__PURE__ */ new Set(["--accounts"]),
105207
+ maximumPositionals: 0
105208
+ });
105209
+ } catch (error61) {
105210
+ if (error61 instanceof UsageError) throw new UsageError(RESTORE_USAGE);
105211
+ throw error61;
105008
105212
  }
105213
+ const accountCount = parseRestoreAccountCount(parsed.one("--accounts"));
105009
105214
  const paths = getVapiPaths();
105010
105215
  const path = join27(paths.directory, "vault.json");
105011
105216
  if (await fileExists2(path)) {
@@ -105019,13 +105224,39 @@ async function restoreCommand(argv, json2, io, dependencies) {
105019
105224
  const config2 = await readConfig(paths.config, json2 ? quietIo(io) : io);
105020
105225
  const phrase = isStdinInteractive(dependencies) ? await getPrompts(dependencies).secret("Recovery phrase: ") : await (dependencies.readStdin ?? readProcessStdin3)();
105021
105226
  const restoreIo = json2 ? quietIo(io) : io;
105022
- const { names } = await restoreVaultFromPhrase(phrase.trim(), config2, restoreIo, dependencies);
105227
+ const { names, scannedAddresses } = await restoreVaultFromPhrase(
105228
+ phrase.trim(),
105229
+ config2,
105230
+ restoreIo,
105231
+ dependencies,
105232
+ accountCount
105233
+ );
105023
105234
  if (json2) {
105024
- output3(io, true, { command: "restore", vault: "restored", accounts: names }, "");
105235
+ output3(
105236
+ io,
105237
+ true,
105238
+ { command: "restore", vault: "restored", accounts: names, scannedAddresses },
105239
+ ""
105240
+ );
105025
105241
  return;
105026
105242
  }
105027
105243
  io.stdout(`Run vapi setup to link ${names[0]}.`);
105028
105244
  }
105245
+ function parseRestoreAccountCount(value) {
105246
+ if (value === void 0) return void 0;
105247
+ if (!/^\d+$/u.test(value)) {
105248
+ throw new UsageError(
105249
+ `--accounts must be a positive integer no greater than ${MAX_RESTORE_ACCOUNTS}.`
105250
+ );
105251
+ }
105252
+ const count = Number(value);
105253
+ if (!Number.isSafeInteger(count) || count < 1 || count > MAX_RESTORE_ACCOUNTS) {
105254
+ throw new UsageError(
105255
+ `--accounts must be a positive integer no greater than ${MAX_RESTORE_ACCOUNTS}.`
105256
+ );
105257
+ }
105258
+ return count;
105259
+ }
105029
105260
  async function protectCommand(argv, json2, io, dependencies) {
105030
105261
  requireNoArguments(argv);
105031
105262
  const env = getEnvironment(dependencies);
@@ -105155,8 +105386,8 @@ var HELP_HEADING = "vAPI Network";
105155
105386
  var HELP = `${HELP_HEADING}
105156
105387
 
105157
105388
  Usage:
105158
- vapi init [--networks <base,arc,solana>] [--json]
105159
- vapi setup [--no-cloud-backup] [--json]
105389
+ vapi init [--networks <base,arc>] [--json]
105390
+ vapi setup [--no-cloud-backup] [--accounts <n>] [--json]
105160
105391
  vapi accounts [--all] [--json]
105161
105392
  vapi accounts add <name> [--label <text>] [--no-link] [--json]
105162
105393
  vapi accounts import <name> [--keystore <path> | --key-file <path>] [--label <text>] [--json]
@@ -105186,7 +105417,7 @@ Usage:
105186
105417
  vapi docs read <url-or-path> [--json]
105187
105418
  vapi search [query] [--kind <kind>] [--network <caip2>] [--limit <n>] [--cursor <cursor>] [--include-unverified] [--json]
105188
105419
  vapi inspect <id> [--endpoint <name>] [--json]
105189
- vapi pay <id-or-url> [--method <method>] [--endpoint <name>] [--body <json>] [--content-type <type>] [--network <caip2>] [--expected-pay-to <address>] [--max <amount>] [--account <name>] [--json]
105420
+ vapi pay <id-or-url> [--method <method>] [--endpoint <name>] [--body <json>] [--content-type <type>] [--network <caip2>] [--expected-pay-to <address>] [--max <amount>] [--timeout <seconds>] [--account <name>] [--json]
105190
105421
  vapi pay --resume <receipt-id> [--json]
105191
105422
  vapi check <url> [--method <method>] [--json]
105192
105423
  vapi balance [--account <name>] [--json]
@@ -105232,8 +105463,8 @@ Usage:
105232
105463
  vapi task status <id> [--account <name>] [--json]
105233
105464
  vapi export-key [--network <caip2>] [--account <name>] [--json]
105234
105465
  vapi backup [--account <name>] [--cloud [off]] [--json]
105235
- vapi restore [--from-owner [--owner <0x\u2026>]] [--json]
105236
- vapi import (--phrase | --key) [--account <name>] [--networks <base,arc,solana>] [--replace] [--force] [--json]
105466
+ vapi restore [--accounts <n> | --from-owner [--owner <0x\u2026>]] [--json]
105467
+ vapi import (--phrase | --key) [--account <name>] [--networks <base,arc>] [--replace] [--force] [--json]
105237
105468
  vapi passphrase [--account <name>] [--json]
105238
105469
  vapi vault protect [--json]
105239
105470
  vapi vault unprotect [--json]
@@ -105261,6 +105492,8 @@ Every command that touches a wallet takes \`--account <name>\`, falls back to \`
105261
105492
 
105262
105493
  \`vapi search\` answers with vAPI-verified listings plus the mirrored external catalogs. \`--include-unverified\` also returns self-listed APIs that passed vAPI's automated x402 probe but were never reviewed; every result is tagged \`[verified]\`, \`[requested]\`, \`[unverified]\` or \`[external]\`.
105263
105494
 
105495
+ Solana listings remain searchable; inspect and pay return \`unsupported_network\`. Solana keys are not part of the device vault yet.
105496
+
105264
105497
  \`vapi docs\` asks the public vAPI documentation assistant; \`vapi docs search\` searches documentation excerpts and \`vapi docs read\` reads one Markdown page. They need no account, wallet or payment.
105265
105498
 
105266
105499
  \`vapi task --help\` lists task options and availability. Task exit codes: 0 ok, 1 error, 2 policy refusal (JSON ok:false with a policy. reason) or invalid usage (JSON error), 3 approval needed in non-interactive mode. Posting moves no money; the current create-order contract does not store amount, deadline, intake, max awards or webhook yet.
@@ -105273,7 +105506,7 @@ Every command that touches a wallet takes \`--account <name>\`, falls back to \`
105273
105506
 
105274
105507
  \`vapi vault protect\` adds a password to the device vault. \`vapi vault unlock\` opens it on this device for 8 hours; for unattended use, set \`VAPI_VAULT_PASSWORD\`. \`vapi unlock\` and \`vapi lock\` remain aliases for one release.
105275
105508
 
105276
- \`vapi backup\` and \`vapi export-key\` print a secret, so they run only on a real terminal, never for an agent, and ask you to type the wallet name first. \`vapi backup --cloud\` keeps an encrypted vault copy that only the owner can approve for recovery. \`vapi restore\` rebuilds the vault from the phrase and re-derives accounts until an unused address. Set \`VAPI_NO_SECRETS=1\` to switch exports off entirely. Every export and every wallet change is logged to ~/.vapi/audit.log.
105509
+ \`vapi backup\` and \`vapi export-key\` print a secret, so they run only on a real terminal, never for an agent, and ask you to type the wallet name first. \`vapi backup --cloud\` keeps an encrypted vault copy that only the owner can approve for recovery. \`vapi restore\` rebuilds the vault from the phrase and re-derives accounts until five consecutive addresses have no Base USDC, and reports the number scanned. Use \`--accounts <n>\` with restore or setup to recover a fixed count without querying balances. Set \`VAPI_NO_SECRETS=1\` to switch exports off entirely. Every export and every wallet change is logged to ~/.vapi/audit.log.
105277
105510
 
105278
105511
  \`vapi publish <url>\` lists an API you own. vAPI probes the URL \u2014 an origin, one endpoint, or an OpenAPI document \u2014 you choose which endpoints to list, and your wallet signs one line naming where the payouts go. Listing is permissionless: a listing that passed the probe goes live with \`vapi publish activate <slug>\`, and \`vapi publish verify-request <slug>\` asks for the review that puts it in the default search. Deploying the FeeSplitter that receives the payouts is a wallet transaction and stays in the console. A catalog of more than 20 endpoints is listed as several listings of up to 20, with one result line per endpoint; \`--resume\` skips every endpoint this key already lists.
105279
105512
 
@@ -106062,7 +106295,7 @@ async function inspectCommand(argv, json2, io, dependencies) {
106062
106295
  );
106063
106296
  output3(io, json2, result, formatInspect(result));
106064
106297
  }
106065
- var PAY_USAGE = "Usage: vapi pay <id-or-url> [--method <method>] [--endpoint <name>] [--body <json>] [--content-type <type>] [--network <caip2>] [--expected-pay-to <address>] [--max <amount>] [--account <name>] [--json]";
106298
+ var PAY_USAGE = "Usage: vapi pay <id-or-url> [--method <method>] [--endpoint <name>] [--body <json>] [--content-type <type>] [--network <caip2>] [--expected-pay-to <address>] [--max <amount>] [--timeout <seconds>] [--account <name>] [--json]";
106066
106299
  async function payCommand(argv, json2, io, dependencies) {
106067
106300
  if (argv.includes(RESUME_OPTION)) {
106068
106301
  await payResumeCommand(argv, json2, io, dependencies);
@@ -106078,11 +106311,13 @@ async function payCommand(argv, json2, io, dependencies) {
106078
106311
  "--expected-pay-to",
106079
106312
  "--max",
106080
106313
  "--max-price-usd",
106314
+ "--timeout",
106081
106315
  WALLET_OPTION5
106082
106316
  ]),
106083
106317
  maximumPositionals: 1
106084
106318
  });
106085
106319
  const target = requiredPositional(parsed.positionals[0], "<id-or-url>", PAY_USAGE);
106320
+ const timeoutSeconds = optionalBoundedInteger(parsed.one("--timeout"), "--timeout", 1, 300);
106086
106321
  const paths = getVapiPaths();
106087
106322
  const config2 = await readConfig(paths.config, io);
106088
106323
  const wallet = await targetWallet(parsed, dependencies);
@@ -106098,7 +106333,8 @@ async function payCommand(argv, json2, io, dependencies) {
106098
106333
  ...parsed.one("--content-type") ? { contentType: parsed.one("--content-type") } : {},
106099
106334
  ...parsed.one("--network") ? { network: parsed.one("--network") } : {},
106100
106335
  ...parsed.one("--expected-pay-to") ? { expectedPayTo: parsed.one("--expected-pay-to") } : {},
106101
- ...maxPriceUsd ? { maxPriceUsd } : {}
106336
+ ...maxPriceUsd ? { maxPriceUsd } : {},
106337
+ ...timeoutSeconds === void 0 ? {} : { timeoutSeconds }
106102
106338
  };
106103
106339
  const call2 = createCallPort({
106104
106340
  config: config2,
@@ -107773,7 +108009,7 @@ function buildNextSteps(address4) {
107773
108009
  formatNextStep("Pay", "vapi pay <ref> --max 0.02"),
107774
108010
  formatNextStep(
107775
108011
  "Agent",
107776
- 'add {"command":"npx","args":["-y","vapi-network","mcp"]} to your MCP config'
108012
+ 'add {"command":"npx","args":["-y","vapi-network@latest","mcp"]} to your MCP config'
107777
108013
  )
107778
108014
  ];
107779
108015
  }
@@ -107954,6 +108190,17 @@ function optionalPositiveInteger(value, option) {
107954
108190
  if (result === 0) throw new UsageError(`${option} must be a positive integer.`);
107955
108191
  return result;
107956
108192
  }
108193
+ function optionalBoundedInteger(value, option, minimum, maximum) {
108194
+ if (value === void 0) return void 0;
108195
+ if (!/^\d+$/.test(value)) {
108196
+ throw new UsageError(`${option} must be an integer from ${minimum} to ${maximum}.`);
108197
+ }
108198
+ const parsed = Number(value);
108199
+ if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {
108200
+ throw new UsageError(`${option} must be an integer from ${minimum} to ${maximum}.`);
108201
+ }
108202
+ return parsed;
108203
+ }
107957
108204
  function optionalUsdAmount(value, option) {
107958
108205
  if (value === void 0) return void 0;
107959
108206
  if (!/^\d+(?:\.\d{1,2})?$/.test(value)) {
@@ -108014,17 +108261,144 @@ function parseInitNetworks(value) {
108014
108261
  }
108015
108262
  for (const network of networks) {
108016
108263
  if (network !== "base" && network !== "arc" && network !== "solana") {
108017
- throw new UsageError("--networks supports base, arc and solana.");
108264
+ throw new UsageError("--networks supports base and arc; Solana vault setup is unavailable.");
108018
108265
  }
108019
108266
  }
108020
108267
  return networks;
108021
108268
  }
108269
+
108270
+ // src/update-check.ts
108271
+ import { lookup } from "node:dns/promises";
108272
+ import { mkdir as mkdir21, readFile as readFile29, writeFile as writeFile12 } from "node:fs/promises";
108273
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
108274
+ var CHECK_TIMEOUT_MS = 1500;
108275
+ var LATEST_URL = "https://registry.npmjs.org/vapi-network/latest";
108276
+ async function runCliWithUpdateCheck(argv = process.argv.slice(2), io = {
108277
+ stdout: (message) => console.log(message),
108278
+ stderr: (message) => console.error(message)
108279
+ }, dependencies = {}, options = {}) {
108280
+ const notice = checkForUpdate({ ...options, env: options.env ?? dependencies.env, argv });
108281
+ const code = await runCli(argv, io, dependencies);
108282
+ const message = await notice;
108283
+ if (message) io.stderr(message);
108284
+ return code;
108285
+ }
108286
+ async function checkForUpdate(options = {}) {
108287
+ const env = options.env ?? process.env;
108288
+ const argv = options.argv ?? process.argv.slice(2);
108289
+ if (!(options.stderrIsTTY ?? process.stderr.isTTY) || argv.includes("--json") || argv[0] === "mcp" && argv[1] !== "install" || env.VAPI_NO_UPDATE_CHECK === "1" || env.CI !== void 0) {
108290
+ return void 0;
108291
+ }
108292
+ const controller = new AbortController();
108293
+ let timer;
108294
+ try {
108295
+ return await Promise.race([
108296
+ latestNotice(options, env, controller.signal),
108297
+ new Promise((resolve2) => {
108298
+ timer = setTimeout(() => {
108299
+ controller.abort();
108300
+ resolve2(void 0);
108301
+ }, CHECK_TIMEOUT_MS);
108302
+ })
108303
+ ]);
108304
+ } catch {
108305
+ return void 0;
108306
+ } finally {
108307
+ if (timer !== void 0) clearTimeout(timer);
108308
+ controller.abort();
108309
+ }
108310
+ }
108311
+ async function latestNotice(options, env, signal) {
108312
+ const paths = getVapiPaths(options.home ?? (env.VAPI_HOME?.trim() || void 0));
108313
+ const now = (options.nowMs ?? Date.now)();
108314
+ let cached2;
108315
+ try {
108316
+ const value = JSON.parse(await readFile29(paths.updateCheck, "utf8"));
108317
+ if (isRecord12(value) && typeof value.checkedAt === "number" && Number.isFinite(value.checkedAt) && typeof value.latest === "string" && parseVersion(value.latest)) {
108318
+ cached2 = { checkedAt: value.checkedAt, latest: value.latest };
108319
+ }
108320
+ } catch {
108321
+ }
108322
+ signal.throwIfAborted();
108323
+ let latest = cached2?.latest ?? CLI_VERSION;
108324
+ if (cached2 === void 0 || now - cached2.checkedAt >= CHECK_INTERVAL_MS || now < cached2.checkedAt) {
108325
+ await mkdir21(paths.directory, { recursive: true });
108326
+ signal.throwIfAborted();
108327
+ await writeFile12(paths.updateCheck, JSON.stringify({ checkedAt: now, latest }), { mode: 384 });
108328
+ signal.throwIfAborted();
108329
+ const fetchImpl = options.fetchImpl ?? createPublicFetch({
108330
+ allowPrivateNetwork: false,
108331
+ lookup: async (hostname3) => {
108332
+ let onAbort;
108333
+ const aborted2 = new Promise((_resolve, reject) => {
108334
+ onAbort = () => reject(signal.reason);
108335
+ signal.addEventListener("abort", onAbort, { once: true });
108336
+ });
108337
+ try {
108338
+ signal.throwIfAborted();
108339
+ const addresses = await Promise.race([lookup(hostname3, { all: true }), aborted2]);
108340
+ return addresses.map(({ address: address4 }) => address4);
108341
+ } finally {
108342
+ signal.removeEventListener("abort", onAbort);
108343
+ }
108344
+ }
108345
+ });
108346
+ const response = await fetchImpl(LATEST_URL, { signal, redirect: "error" });
108347
+ if (!response.ok) return void 0;
108348
+ const body = await response.json();
108349
+ signal.throwIfAborted();
108350
+ if (!isRecord12(body) || typeof body.version !== "string" || !parseVersion(body.version)) {
108351
+ return void 0;
108352
+ }
108353
+ latest = body.version;
108354
+ await writeFile12(paths.updateCheck, JSON.stringify({ checkedAt: now, latest }), { mode: 384 });
108355
+ }
108356
+ signal.throwIfAborted();
108357
+ return isNewerVersion(latest, CLI_VERSION) ? `vapi-network ${latest} is available (you have ${CLI_VERSION}). Update: npm i -g vapi-network@latest` : void 0;
108358
+ }
108359
+ function isRecord12(value) {
108360
+ return typeof value === "object" && value !== null && !Array.isArray(value);
108361
+ }
108362
+ function parseVersion(version5) {
108363
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\da-zA-Z.-]+))?(?:\+[\da-zA-Z-]+(?:\.[\da-zA-Z-]+)*)?$/.exec(
108364
+ version5
108365
+ );
108366
+ if (!match) return void 0;
108367
+ const prerelease = match[4]?.split(".");
108368
+ if (prerelease?.some((part) => part === "" || /^\d+$/.test(part) && /^0\d/.test(part))) {
108369
+ return void 0;
108370
+ }
108371
+ return { core: match.slice(1, 4).map(BigInt), prerelease };
108372
+ }
108373
+ function isNewerVersion(latest, current) {
108374
+ const next = parseVersion(latest);
108375
+ const running = parseVersion(current);
108376
+ for (let index2 = 0; index2 < 3; index2 += 1) {
108377
+ if (next.core[index2] !== running.core[index2]) return next.core[index2] > running.core[index2];
108378
+ }
108379
+ if (running.prerelease === void 0) return false;
108380
+ if (next.prerelease === void 0) return true;
108381
+ for (let index2 = 0; index2 < Math.max(next.prerelease.length, running.prerelease.length); index2 += 1) {
108382
+ const a = next.prerelease[index2];
108383
+ const b = running.prerelease[index2];
108384
+ if (a === b) continue;
108385
+ if (a === void 0) return false;
108386
+ if (b === void 0) return true;
108387
+ const aNumeric = /^\d+$/.test(a);
108388
+ const bNumeric = /^\d+$/.test(b);
108389
+ if (aNumeric && bNumeric) return BigInt(a) > BigInt(b);
108390
+ if (aNumeric !== bNumeric) return !aNumeric;
108391
+ return a > b;
108392
+ }
108393
+ return false;
108394
+ }
108022
108395
  export {
108023
108396
  HELP,
108024
108397
  createLocalRuntime,
108025
108398
  parseRuntimeKind,
108026
108399
  resolveRuntime,
108027
108400
  runCli,
108401
+ runCliWithUpdateCheck,
108028
108402
  runtimeForKind
108029
108403
  };
108030
108404
  //# sourceMappingURL=index.js.map