@vapi-network/cli 0.9.0 → 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
@@ -28987,365 +28987,6 @@ function date4(params) {
28987
28987
  return _coercedDate(ZodDate, params);
28988
28988
  }
28989
28989
 
28990
- // ../core/src/marketplace-contracts.ts
28991
- var MARKETPLACE_DISCOVERY_PROTOCOL = "vapi.marketplace.discovery/1";
28992
- var MARKETPLACE_RANKING_VERSION = "marketplace-ranking-v1";
28993
- var MARKETPLACE_KINDS = ["api", "service_offer", "open_request"];
28994
- var MARKETPLACE_EXECUTION_METHODS = [
28995
- "GET",
28996
- "HEAD",
28997
- "POST",
28998
- "PUT",
28999
- "PATCH",
29000
- "DELETE"
29001
- ];
29002
- var marketplaceExecutionMethodSchema = external_exports.enum(MARKETPLACE_EXECUTION_METHODS);
29003
- var marketplaceKindSchema = external_exports.enum(MARKETPLACE_KINDS);
29004
- var EXECUTION_MODES = ["direct", "gateway"];
29005
- var executionModeSchema = external_exports.enum(EXECUTION_MODES);
29006
- var PROVENANCES = ["indexed", "self_listed", "partner"];
29007
- var provenanceSchema = external_exports.enum(PROVENANCES);
29008
- var FIRST_PARTY_PROVENANCES = ["self_listed", "partner"];
29009
- var firstPartyProvenanceSchema = external_exports.enum(FIRST_PARTY_PROVENANCES);
29010
- var LISTING_GROUPS = ["vapi", "added", "partner", "external"];
29011
- var listingGroupSchema = external_exports.enum(LISTING_GROUPS);
29012
- var listingFeeSchema = external_exports.looseObject({
29013
- bps: external_exports.number().int().min(0),
29014
- label: external_exports.string()
29015
- });
29016
- var LISTING_VERIFICATIONS = ["none", "requested", "verified"];
29017
- var listingVerificationSchema = external_exports.enum(LISTING_VERIFICATIONS);
29018
- var listingVerificationFieldSchema = listingVerificationSchema.default("none").catch("none");
29019
- var listingLivenessSchema = external_exports.looseObject({
29020
- uptime7d: external_exports.number().min(0).max(1),
29021
- latencyP50Ms: external_exports.number().nonnegative().nullable(),
29022
- latencyP95Ms: external_exports.number().nonnegative().nullable(),
29023
- checks7d: external_exports.number().int().nonnegative()
29024
- });
29025
- var listingConformanceSchema = external_exports.looseObject({
29026
- declaredVersion: external_exports.union([external_exports.literal(1), external_exports.literal(2)]).nullable(),
29027
- versionConformant: external_exports.boolean(),
29028
- offerTransport: external_exports.enum(["body", "header", "both"]),
29029
- issues: external_exports.array(external_exports.string())
29030
- });
29031
- var listingIdentitySchema = external_exports.looseObject({
29032
- erc8004Id: external_exports.string().trim().min(1),
29033
- reputation: external_exports.looseObject({
29034
- score: external_exports.number().finite(),
29035
- count: external_exports.number().int().nonnegative()
29036
- }).optional().catch(void 0)
29037
- });
29038
- var listingDisclosureShape = {
29039
- group: listingGroupSchema.optional(),
29040
- fee: listingFeeSchema.optional(),
29041
- verification: listingVerificationFieldSchema,
29042
- liveness: listingLivenessSchema.optional().catch(void 0),
29043
- conformance: listingConformanceSchema.optional().catch(void 0),
29044
- identity: listingIdentitySchema.optional().catch(void 0)
29045
- };
29046
- var marketplaceBadgeCodeSchema = external_exports.enum([
29047
- "live_x402",
29048
- "partner",
29049
- "payout_wallet_confirmed",
29050
- "vapi_verified",
29051
- "external_catalog",
29052
- "approved_vendor"
29053
- ]);
29054
- var marketplaceBadgeSchema = external_exports.looseObject({
29055
- code: marketplaceBadgeCodeSchema,
29056
- label: external_exports.string().trim().min(1).max(80)
29057
- });
29058
- var marketplacePublicFactSchema = external_exports.looseObject({
29059
- label: external_exports.string().trim().min(1).max(80),
29060
- value: external_exports.string().trim().min(1).max(160)
29061
- });
29062
- var marketplaceHrefSchema = external_exports.union([
29063
- external_exports.string().trim().min(1).max(2048).regex(/^\/(?!\/)/),
29064
- external_exports.url().max(2048).regex(/^https:\/\//)
29065
- ]);
29066
- var marketplaceCardSchema = external_exports.looseObject({
29067
- title: external_exports.string().trim().min(1).max(160),
29068
- summary: external_exports.string().trim().min(1).max(1e3),
29069
- byline: external_exports.string().trim().min(1).max(160).optional(),
29070
- bylineHref: marketplaceHrefSchema.optional(),
29071
- badges: external_exports.array(marketplaceBadgeSchema).max(8),
29072
- facts: external_exports.array(marketplacePublicFactSchema).max(12)
29073
- });
29074
- var marketplaceHitBase = {
29075
- ref: external_exports.string().trim().min(1).max(512),
29076
- card: marketplaceCardSchema,
29077
- ...listingDisclosureShape
29078
- };
29079
- var invokeApiActionSchema = external_exports.looseObject({
29080
- type: external_exports.literal("invoke_api"),
29081
- href: marketplaceHrefSchema
29082
- });
29083
- var firstPartyApiMarketplaceHitSchema = external_exports.looseObject({
29084
- ...marketplaceHitBase,
29085
- kind: external_exports.literal("api"),
29086
- provenance: firstPartyProvenanceSchema,
29087
- execution: external_exports.looseObject({
29088
- mode: executionModeSchema
29089
- }),
29090
- action: invokeApiActionSchema
29091
- });
29092
- var mirroredApiMarketplaceHitSchema = external_exports.looseObject({
29093
- ...marketplaceHitBase,
29094
- kind: external_exports.literal("api"),
29095
- provenance: external_exports.literal("indexed"),
29096
- execution: external_exports.looseObject({
29097
- mode: external_exports.literal("direct"),
29098
- url: external_exports.url().max(2048).regex(/^https:\/\/(?![^/?#]*@)/),
29099
- method: marketplaceExecutionMethodSchema.nullable(),
29100
- network: external_exports.string().trim().max(160).regex(/^eip155:[1-9]\d*$/)
29101
- }),
29102
- action: invokeApiActionSchema
29103
- });
29104
- var apiMarketplaceHitSchema = external_exports.discriminatedUnion("provenance", [
29105
- firstPartyApiMarketplaceHitSchema,
29106
- mirroredApiMarketplaceHitSchema
29107
- ]);
29108
- var serviceOfferMarketplaceHitSchema = external_exports.looseObject({
29109
- ...marketplaceHitBase,
29110
- kind: external_exports.literal("service_offer"),
29111
- action: external_exports.looseObject({
29112
- type: external_exports.literal("start_engagement"),
29113
- href: marketplaceHrefSchema
29114
- })
29115
- });
29116
- var openRequestMarketplaceHitSchema = external_exports.looseObject({
29117
- ...marketplaceHitBase,
29118
- kind: external_exports.literal("open_request"),
29119
- action: external_exports.looseObject({
29120
- type: external_exports.literal("propose_to_request"),
29121
- href: marketplaceHrefSchema
29122
- })
29123
- });
29124
- var marketplaceHitSchema = external_exports.union([
29125
- apiMarketplaceHitSchema,
29126
- serviceOfferMarketplaceHitSchema,
29127
- openRequestMarketplaceHitSchema
29128
- ]);
29129
- var marketplaceDiscoveryInputSchema = external_exports.strictObject({
29130
- q: external_exports.string().trim().max(200).optional(),
29131
- kinds: external_exports.array(marketplaceKindSchema).min(1).max(MARKETPLACE_KINDS.length).optional(),
29132
- network: external_exports.string().trim().min(1).max(160).optional(),
29133
- cursor: external_exports.string().trim().min(1).max(4096).optional(),
29134
- limit: external_exports.number().int().min(1).max(50).optional(),
29135
- includeUnverified: external_exports.boolean().optional()
29136
- }).superRefine((input2, context) => {
29137
- if (input2.kinds && new Set(input2.kinds).size !== input2.kinds.length) {
29138
- context.addIssue({
29139
- code: "custom",
29140
- path: ["kinds"],
29141
- message: "Marketplace kinds must be unique"
29142
- });
29143
- }
29144
- });
29145
- function isMirroredHit(hit) {
29146
- return hit.kind === "api" && hit.provenance === "indexed";
29147
- }
29148
- var marketplaceDiscoveryPageSchema = external_exports.looseObject({
29149
- protocol: external_exports.literal(MARKETPLACE_DISCOVERY_PROTOCOL),
29150
- items: external_exports.array(marketplaceHitSchema),
29151
- nextCursor: external_exports.string().min(1).max(4096).nullable(),
29152
- unavailableKinds: external_exports.array(marketplaceKindSchema).max(MARKETPLACE_KINDS.length),
29153
- rankingVersion: external_exports.literal(MARKETPLACE_RANKING_VERSION)
29154
- });
29155
-
29156
- // ../core/src/call-contracts-wire.ts
29157
- var CALLABLE_CATEGORIES = ["ai", "data", "crypto", "compute", "search"];
29158
- var callableCategorySchema = external_exports.enum(CALLABLE_CATEGORIES);
29159
- var DISCOVERY_CATEGORIES = [...CALLABLE_CATEGORIES, "other"];
29160
- var discoveryCategorySchema = external_exports.enum(DISCOVERY_CATEGORIES);
29161
- var CALLABLE_CATEGORY_SET = new Set(CALLABLE_CATEGORIES);
29162
- var serviceTierSchema = external_exports.enum(["listed", "verified", "partner"]);
29163
- var discoveryEndpointSchema = external_exports.looseObject({
29164
- name: external_exports.string(),
29165
- method: external_exports.string(),
29166
- url: external_exports.url(),
29167
- price: external_exports.string(),
29168
- description: external_exports.string(),
29169
- operationId: external_exports.string().trim().min(1).optional(),
29170
- requestContentType: external_exports.string().trim().min(1).optional(),
29171
- requestSchema: external_exports.json().optional(),
29172
- responseContentType: external_exports.string().trim().min(1).optional(),
29173
- pathTemplate: external_exports.string().trim().min(1).optional(),
29174
- pathParameters: external_exports.array(external_exports.string().trim().min(1)).optional(),
29175
- payment: external_exports.looseObject({
29176
- scheme: external_exports.literal("exact"),
29177
- network: external_exports.string().regex(/^eip155:\d+$/),
29178
- asset: external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/),
29179
- payTo: external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/),
29180
- checkedAt: external_exports.iso.datetime()
29181
- }).optional()
29182
- });
29183
- var serviceSummarySchema = external_exports.looseObject({
29184
- id: external_exports.string(),
29185
- name: external_exports.string(),
29186
- description: external_exports.string(),
29187
- category: discoveryCategorySchema,
29188
- tier: serviceTierSchema,
29189
- ...listingDisclosureShape,
29190
- verified: external_exports.boolean(),
29191
- wrapped: external_exports.boolean(),
29192
- price: external_exports.string(),
29193
- networks: external_exports.array(external_exports.string()),
29194
- endpoints: external_exports.array(discoveryEndpointSchema)
29195
- });
29196
- var searchServicesResponseSchema = external_exports.looseObject({
29197
- services: external_exports.array(serviceSummarySchema)
29198
- });
29199
- var discoveryResponseSchema = searchServicesResponseSchema;
29200
-
29201
- // ../core/src/call-contracts.ts
29202
- var DiscoveryCatalogError = class extends Error {
29203
- name = "DiscoveryCatalogError";
29204
- code;
29205
- serviceId;
29206
- constructor(code, message, serviceId) {
29207
- super(message);
29208
- this.code = code;
29209
- this.serviceId = serviceId;
29210
- }
29211
- };
29212
- function parseDiscovery(raw) {
29213
- const parsed = discoveryResponseSchema.safeParse(raw);
29214
- if (!parsed.success) {
29215
- const malformedUrl = parsed.error.issues.find(
29216
- (issue2) => issue2.path.at(-1) === "url" && issue2.path.includes("endpoints")
29217
- );
29218
- if (malformedUrl) {
29219
- const serviceIndex = pathIndexAfter(malformedUrl.path, "services");
29220
- const serviceId = rawServiceId(raw, serviceIndex);
29221
- throw new DiscoveryCatalogError(
29222
- "malformed_url",
29223
- `Service ${JSON.stringify(serviceId ?? "unknown")} has a malformed endpoint URL.`,
29224
- serviceId
29225
- );
29226
- }
29227
- throw new DiscoveryCatalogError("invalid_discovery", "Discovery response is malformed.");
29228
- }
29229
- for (const service of parsed.data.services) {
29230
- buildTargets(service);
29231
- }
29232
- const resolveListing = (serviceId, endpointName) => {
29233
- const service = parsed.data.services.find((candidate) => candidate.id === serviceId);
29234
- if (!service) {
29235
- throw new DiscoveryCatalogError(
29236
- "service_not_found",
29237
- `No payable endpoint found for service ${JSON.stringify(serviceId)}.`,
29238
- serviceId
29239
- );
29240
- }
29241
- return { service, endpoint: resolveTarget(service, endpointName) };
29242
- };
29243
- return {
29244
- services: parsed.data.services,
29245
- resolve: (serviceId, endpointName) => resolveListing(serviceId, endpointName).endpoint,
29246
- resolveListing
29247
- };
29248
- }
29249
- function resolveTarget(service, endpointName) {
29250
- const { targets, targetsByName } = buildTargets(service);
29251
- if (endpointName !== void 0) {
29252
- const selected = targetsByName.get(endpointName.trim());
29253
- if (!selected) {
29254
- throw new DiscoveryCatalogError(
29255
- "endpoint_not_found",
29256
- `Service ${JSON.stringify(service.id)} has no endpoint ${JSON.stringify(endpointName)}. Available endpoints: ${[...targetsByName.keys()].join(", ")}.`,
29257
- service.id
29258
- );
29259
- }
29260
- return { ...selected };
29261
- }
29262
- if (targets.size !== 1) {
29263
- throw new DiscoveryCatalogError(
29264
- "ambiguous_default",
29265
- `Service ${JSON.stringify(service.id)} has ${targets.size} distinct payable endpoints. Choose one with endpoint: ${[...targetsByName.keys()].join(", ")}.`,
29266
- service.id
29267
- );
29268
- }
29269
- return targets.values().next().value;
29270
- }
29271
- function buildTargets(service) {
29272
- if (service.endpoints.length === 0) {
29273
- throw new DiscoveryCatalogError(
29274
- "no_endpoint",
29275
- `Service ${JSON.stringify(service.id)} has no payable endpoint.`,
29276
- service.id
29277
- );
29278
- }
29279
- const namedEndpoints = [...service.endpoints].sort(
29280
- (left, right) => compareNames(left.name.trim(), right.name.trim())
29281
- );
29282
- const names = /* @__PURE__ */ new Set();
29283
- const targets = /* @__PURE__ */ new Map();
29284
- const targetsByName = /* @__PURE__ */ new Map();
29285
- for (const endpoint of namedEndpoints) {
29286
- const name = endpoint.name.trim();
29287
- if (!name) {
29288
- throw new DiscoveryCatalogError(
29289
- "invalid_endpoint_name",
29290
- `Service ${JSON.stringify(service.id)} has a blank endpoint name.`,
29291
- service.id
29292
- );
29293
- }
29294
- if (names.has(name)) {
29295
- throw new DiscoveryCatalogError(
29296
- "duplicate_endpoint_name",
29297
- `Service ${JSON.stringify(service.id)} has duplicate endpoint name ${JSON.stringify(name)}.`,
29298
- service.id
29299
- );
29300
- }
29301
- names.add(name);
29302
- const method = endpoint.method.trim().toUpperCase();
29303
- if (!method) {
29304
- throw new DiscoveryCatalogError(
29305
- "blank_method",
29306
- `Service ${JSON.stringify(service.id)} has a blank endpoint method.`,
29307
- service.id
29308
- );
29309
- }
29310
- const url2 = new URL(endpoint.url);
29311
- if (url2.protocol !== "http:" && url2.protocol !== "https:") {
29312
- throw new DiscoveryCatalogError(
29313
- "malformed_url",
29314
- `Service ${JSON.stringify(service.id)} has a non-HTTP endpoint URL.`,
29315
- service.id
29316
- );
29317
- }
29318
- const transportKey = `${method}\0${endpoint.url}`;
29319
- const normalized = { ...endpoint, name, method };
29320
- targetsByName.set(name, normalized);
29321
- if (!targets.has(transportKey)) targets.set(transportKey, normalized);
29322
- }
29323
- return { targets, targetsByName };
29324
- }
29325
- function compareNames(left, right) {
29326
- return left < right ? -1 : left > right ? 1 : 0;
29327
- }
29328
- function pathIndexAfter(path, key2) {
29329
- const keyIndex = path.indexOf(key2);
29330
- const candidate = path[keyIndex + 1];
29331
- return typeof candidate === "number" ? candidate : void 0;
29332
- }
29333
- function rawServiceId(raw, serviceIndex) {
29334
- if (serviceIndex === void 0 || typeof raw !== "object" || raw === null) {
29335
- return void 0;
29336
- }
29337
- const services = Reflect.get(raw, "services");
29338
- if (!Array.isArray(services)) {
29339
- return void 0;
29340
- }
29341
- const service = services[serviceIndex];
29342
- if (typeof service !== "object" || service === null) {
29343
- return void 0;
29344
- }
29345
- const id2 = Reflect.get(service, "id");
29346
- return typeof id2 === "string" ? id2 : void 0;
29347
- }
29348
-
29349
28990
  // ../../node_modules/.pnpm/viem@2.56.1_typescript@6.0.3_zod@4.5.4/node_modules/viem/_esm/index.js
29350
28991
  init_exports();
29351
28992
 
@@ -39622,6 +39263,7 @@ var ARC_MAINNET_CAIP2 = "eip155:5042";
39622
39263
  var ARC_TESTNET_CAIP2 = "eip155:5042002";
39623
39264
  var SOLANA_MAINNET_CAIP2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
39624
39265
  var X402_SOLANA_MAINNET_CAIP2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
39266
+ var SOLANA_DEVNET_CAIP2 = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
39625
39267
  var SOLANA_MAINNET_USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
39626
39268
  function canonicalIdentity(usdc, eip712Domain) {
39627
39269
  return Object.freeze({
@@ -39665,375 +39307,194 @@ var BROWSER_ENABLED_X402_NETWORK_CONFIG = Object.freeze({
39665
39307
  [ARC_TESTNET_CAIP2]: browserNetwork(arcTestnetUsdc)
39666
39308
  });
39667
39309
 
39668
- // ../core/src/net-guard.ts
39669
- import { lookup as dnsLookup } from "node:dns/promises";
39670
- import { request as httpRequest } from "node:http";
39671
- import { request as httpsRequest } from "node:https";
39672
- import { isIP } from "node:net";
39673
- import { Readable } from "node:stream";
39674
- var defaultLookup = async (hostname3) => {
39675
- const addresses = await dnsLookup(hostname3, { all: true });
39676
- return addresses.map(({ address: address4 }) => address4);
39310
+ // ../core/src/marketplace-contracts.ts
39311
+ var MARKETPLACE_DISCOVERY_PROTOCOL = "vapi.marketplace.discovery/1";
39312
+ var MARKETPLACE_RANKING_VERSION = "marketplace-ranking-v1";
39313
+ var MARKETPLACE_KINDS = ["api", "service_offer", "open_request"];
39314
+ var MARKETPLACE_EXECUTION_METHODS = [
39315
+ "GET",
39316
+ "HEAD",
39317
+ "POST",
39318
+ "PUT",
39319
+ "PATCH",
39320
+ "DELETE"
39321
+ ];
39322
+ var marketplaceExecutionMethodSchema = external_exports.enum(MARKETPLACE_EXECUTION_METHODS);
39323
+ var marketplaceKindSchema = external_exports.enum(MARKETPLACE_KINDS);
39324
+ var EXECUTION_MODES = ["direct", "gateway"];
39325
+ var executionModeSchema = external_exports.enum(EXECUTION_MODES);
39326
+ var PROVENANCES = ["indexed", "self_listed", "partner"];
39327
+ var provenanceSchema = external_exports.enum(PROVENANCES);
39328
+ var FIRST_PARTY_PROVENANCES = ["self_listed", "partner"];
39329
+ var firstPartyProvenanceSchema = external_exports.enum(FIRST_PARTY_PROVENANCES);
39330
+ var LISTING_GROUPS = ["vapi", "added", "partner", "external"];
39331
+ var listingGroupSchema = external_exports.enum(LISTING_GROUPS);
39332
+ var listingFeeSchema = external_exports.looseObject({
39333
+ bps: external_exports.number().int().min(0),
39334
+ label: external_exports.string()
39335
+ });
39336
+ var LISTING_VERIFICATIONS = ["none", "requested", "verified"];
39337
+ var listingVerificationSchema = external_exports.enum(LISTING_VERIFICATIONS);
39338
+ var listingVerificationFieldSchema = listingVerificationSchema.default("none").catch("none");
39339
+ var listingLivenessSchema = external_exports.looseObject({
39340
+ uptime7d: external_exports.number().min(0).max(1),
39341
+ latencyP50Ms: external_exports.number().nonnegative().nullable(),
39342
+ latencyP95Ms: external_exports.number().nonnegative().nullable(),
39343
+ checks7d: external_exports.number().int().nonnegative()
39344
+ });
39345
+ var listingConformanceSchema = external_exports.looseObject({
39346
+ declaredVersion: external_exports.union([external_exports.literal(1), external_exports.literal(2)]).nullable(),
39347
+ versionConformant: external_exports.boolean(),
39348
+ offerTransport: external_exports.enum(["body", "header", "both"]),
39349
+ issues: external_exports.array(external_exports.string())
39350
+ });
39351
+ var listingIdentitySchema = external_exports.looseObject({
39352
+ erc8004Id: external_exports.string().trim().min(1),
39353
+ reputation: external_exports.looseObject({
39354
+ score: external_exports.number().finite(),
39355
+ count: external_exports.number().int().nonnegative()
39356
+ }).optional().catch(void 0)
39357
+ });
39358
+ var listingDisclosureShape = {
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),
39363
+ verification: listingVerificationFieldSchema,
39364
+ liveness: listingLivenessSchema.optional().catch(void 0),
39365
+ conformance: listingConformanceSchema.optional().catch(void 0),
39366
+ identity: listingIdentitySchema.optional().catch(void 0)
39677
39367
  };
39678
- async function assertPublicUrl(url2, options) {
39679
- if (url2.username || url2.password) {
39680
- throw guardError(url2);
39681
- }
39682
- if (url2.protocol !== "http:" && url2.protocol !== "https:") {
39683
- throw guardError(url2);
39684
- }
39685
- if (options.allowPrivateNetwork) {
39686
- return;
39687
- }
39688
- const hostname3 = normalizeHostname(url2.hostname);
39689
- const lowercaseHostname = hostname3.toLowerCase();
39690
- if (!lowercaseHostname || lowercaseHostname === "localhost" || lowercaseHostname.endsWith(".localhost") || lowercaseHostname.endsWith(".local") || lowercaseHostname.endsWith(".internal")) {
39691
- throw guardError(url2);
39692
- }
39693
- if (isIP(hostname3)) {
39694
- if (isNonPublicAddress(hostname3)) {
39695
- throw guardError(url2);
39696
- }
39697
- return;
39698
- }
39699
- let addresses;
39700
- try {
39701
- addresses = await withTimeout2(
39702
- (options.lookup ?? defaultLookup)(hostname3),
39703
- options.timeoutMs ?? 5e3
39704
- );
39705
- } catch {
39706
- throw guardError(url2);
39707
- }
39708
- if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
39709
- throw guardError(url2);
39710
- }
39711
- }
39712
- function createPublicFetch(options) {
39713
- const lookupFn = options.lookup ?? defaultLookup;
39714
- return (async (input2, init) => {
39715
- const url2 = new URL(input2 instanceof Request ? input2.url : input2);
39716
- await assertPublicUrl(url2, {
39717
- allowPrivateNetwork: options.allowPrivateNetwork,
39718
- lookup: lookupFn,
39719
- timeoutMs: 5e3
39720
- });
39721
- const normalized = new Request(input2, init);
39722
- const bytes = normalized.body ? Buffer.from(await normalized.arrayBuffer()) : null;
39723
- return await new Promise((resolve2, reject) => {
39724
- const requestOptions2 = {
39725
- method: normalized.method,
39726
- headers: Object.fromEntries(normalized.headers),
39727
- signal: normalized.signal,
39728
- ...options.allowPrivateNetwork ? {} : { lookup: pinnedLookup(lookupFn) }
39729
- };
39730
- const onResponse = (incoming) => {
39731
- try {
39732
- const headers = new Headers();
39733
- for (const [name, value] of Object.entries(incoming.headers)) {
39734
- if (Array.isArray(value)) {
39735
- for (const item of value) headers.append(name, item);
39736
- } else if (value !== void 0) {
39737
- headers.set(name, value);
39738
- }
39739
- }
39740
- const status = incoming.statusCode ?? 500;
39741
- const bodyForbidden = normalized.method === "HEAD" || [204, 205, 304].includes(status);
39742
- if (bodyForbidden) incoming.resume();
39743
- const response = new Response(
39744
- bodyForbidden ? null : Readable.toWeb(incoming),
39745
- { status, statusText: incoming.statusMessage, headers }
39746
- );
39747
- Object.defineProperty(response, "url", { value: url2.toString() });
39748
- resolve2(response);
39749
- } catch (error61) {
39750
- incoming.destroy();
39751
- reject(error61);
39752
- }
39753
- };
39754
- const request = url2.protocol === "https:" ? httpsRequest(url2, requestOptions2, onResponse) : httpRequest(url2, requestOptions2, onResponse);
39755
- request.on("error", reject);
39756
- if (bytes) request.write(bytes);
39757
- request.end();
39758
- });
39759
- });
39760
- }
39761
- function pinnedLookup(lookup) {
39762
- return (hostname3, dnsOptions, callback) => {
39763
- void lookup(normalizeHostname(hostname3)).then((addresses) => {
39764
- if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
39765
- callback(guardError(new URL(`https://${hostname3}`)), "");
39766
- return;
39767
- }
39768
- const address4 = addresses[0];
39769
- const family = isIP(address4);
39770
- callback(
39771
- null,
39772
- dnsOptions.all ? [{ address: address4, family }] : address4,
39773
- dnsOptions.all ? void 0 : family
39774
- );
39775
- }).catch(
39776
- (error61) => callback(error61 instanceof Error ? error61 : new Error("DNS lookup failed."), "")
39777
- );
39778
- };
39779
- }
39780
- async function withTimeout2(operation, timeoutMs) {
39781
- let timeout;
39782
- try {
39783
- return await Promise.race([
39784
- operation,
39785
- new Promise((_resolve, reject) => {
39786
- timeout = setTimeout(() => reject(new Error("DNS lookup timed out.")), timeoutMs);
39787
- })
39788
- ]);
39789
- } finally {
39790
- if (timeout) clearTimeout(timeout);
39791
- }
39792
- }
39793
- function normalizeHostname(hostname3) {
39794
- const unbracketed = hostname3.startsWith("[") && hostname3.endsWith("]") ? hostname3.slice(1, -1) : hostname3;
39795
- return unbracketed.endsWith(".") ? unbracketed.slice(0, -1) : unbracketed;
39796
- }
39797
- function isNonPublicAddress(address4) {
39798
- const normalized = normalizeHostname(address4);
39799
- const version5 = isIP(normalized);
39800
- if (version5 === 4) {
39801
- return isNonPublicIpv4(parseIpv4(normalized));
39802
- }
39803
- if (version5 === 6) {
39804
- return isNonPublicIpv6(parseIpv6(normalized));
39805
- }
39806
- return true;
39807
- }
39808
- function parseIpv4(address4) {
39809
- const octets = address4.split(".").map(Number);
39810
- return [octets[0], octets[1], octets[2], octets[3]];
39811
- }
39812
- function isNonPublicIpv4([first, second, third]) {
39813
- return first === 0 || first === 10 || first === 100 && second >= 64 && second <= 127 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 0 && (third === 0 || third === 2) || first === 192 && second === 168 || first === 198 && second >= 18 && second <= 19 || first === 198 && second === 51 && third === 100 || first === 203 && second === 0 && third === 113 || first >= 224;
39814
- }
39815
- function parseIpv6(address4) {
39816
- let normalized = address4.toLowerCase();
39817
- const lastColon = normalized.lastIndexOf(":");
39818
- const dottedTail = normalized.slice(lastColon + 1);
39819
- if (dottedTail.includes(".")) {
39820
- const [first, second, third, fourth] = parseIpv4(dottedTail);
39821
- normalized = `${normalized.slice(0, lastColon + 1)}${(first << 8 | second).toString(16)}:${(third << 8 | fourth).toString(16)}`;
39822
- }
39823
- const halves = normalized.split("::");
39824
- const left = halves[0] ? halves[0].split(":").map(parseHex) : [];
39825
- const right = halves[1] ? halves[1].split(":").map(parseHex) : [];
39826
- const omittedCount = 8 - left.length - right.length;
39827
- return halves.length === 2 ? [...left, ...Array.from({ length: omittedCount }, () => 0), ...right] : left;
39828
- }
39829
- function parseHex(value) {
39830
- return Number.parseInt(value, 16);
39831
- }
39832
- function isNonPublicIpv6(hextets) {
39833
- if (hextets.slice(0, 5).every((hextet) => hextet === 0) && hextets[5] === 65535) {
39834
- const embeddedIpv4 = [
39835
- hextets[6] >> 8,
39836
- hextets[6] & 255,
39837
- hextets[7] >> 8,
39838
- hextets[7] & 255
39839
- ];
39840
- return isNonPublicIpv4(embeddedIpv4);
39841
- }
39842
- if (hextets.slice(0, 6).every((hextet) => hextet === 0)) {
39843
- const compatibleIpv4 = [
39844
- hextets[6] >> 8,
39845
- hextets[6] & 255,
39846
- hextets[7] >> 8,
39847
- hextets[7] & 255
39848
- ];
39849
- if (isNonPublicIpv4(compatibleIpv4)) return true;
39850
- }
39851
- const isUnspecified = hextets.every((hextet) => hextet === 0);
39852
- const isLoopback = hextets.slice(0, 7).every((hextet) => hextet === 0) && hextets[7] === 1;
39853
- const first = hextets[0];
39854
- const isUniqueLocal = first >= 64512 && first <= 65023;
39855
- const isLinkLocal = first >= 65152 && first <= 65215;
39856
- const isSiteLocal = first >= 65216 && first <= 65279;
39857
- const isMulticast = first >= 65280;
39858
- const isDocumentation = first === 8193 && hextets[1] === 3512;
39859
- return isUnspecified || isLoopback || isUniqueLocal || isLinkLocal || isSiteLocal || isMulticast || isDocumentation;
39860
- }
39861
- function guardError(url2) {
39862
- return new Error(
39863
- `URL hostname ${JSON.stringify(url2.hostname)} is not allowed; private or internal destinations require allowPrivateNetwork true in the vAPI config.`
39864
- );
39865
- }
39866
-
39867
- // ../core/src/networks.ts
39868
- var USDC_DECIMALS = 6;
39869
- var DEFAULT_ARC_GAS_HEADROOM_ATOMIC = 50000n;
39870
- var NETWORKS = {
39871
- [BASE_MAINNET_CAIP2]: {
39872
- family: "evm",
39873
- chainId: 8453,
39874
- name: "Base mainnet",
39875
- usdc: CANONICAL_X402_USDC_NETWORKS[BASE_MAINNET_CAIP2].usdc,
39876
- gasToken: "ETH",
39877
- rpcEnv: "BASE_RPC_URL",
39878
- publicRpcUrl: "https://mainnet.base.org",
39879
- explorerUrl: "https://basescan.org"
39880
- },
39881
- [ARC_MAINNET_CAIP2]: {
39882
- family: "evm",
39883
- chainId: 5042,
39884
- name: "Arc mainnet",
39885
- usdc: CANONICAL_X402_USDC_NETWORKS[ARC_MAINNET_CAIP2].usdc,
39886
- gasToken: "USDC",
39887
- rpcEnv: "ARC_RPC_URL",
39888
- publicRpcUrl: "https://rpc.mainnet.arc.io",
39889
- explorerUrl: "https://explorer.arc.io"
39890
- },
39891
- [ARC_TESTNET_CAIP2]: {
39892
- family: "evm",
39893
- chainId: 5042002,
39894
- name: "Arc testnet",
39895
- usdc: CANONICAL_X402_USDC_NETWORKS[ARC_TESTNET_CAIP2].usdc,
39896
- gasToken: "USDC",
39897
- rpcEnv: "ARC_TESTNET_RPC_URL"
39898
- },
39899
- [SOLANA_MAINNET_CAIP2]: {
39900
- family: "svm",
39901
- name: "Solana mainnet",
39902
- usdc: SOLANA_MAINNET_USDC,
39903
- gasToken: "SOL",
39904
- rpcEnv: "SOLANA_RPC_URL",
39905
- publicRpcUrl: "https://api.mainnet-beta.solana.com"
39906
- },
39907
- [X402_SOLANA_MAINNET_CAIP2]: {
39908
- family: "svm",
39909
- name: "Solana mainnet",
39910
- usdc: SOLANA_MAINNET_USDC,
39911
- gasToken: "SOL",
39912
- rpcEnv: "SOLANA_RPC_URL",
39913
- publicRpcUrl: "https://api.mainnet-beta.solana.com"
39914
- }
39368
+ var marketplaceBadgeCodeSchema = external_exports.enum([
39369
+ "live_x402",
39370
+ "mpp",
39371
+ "partner",
39372
+ "payout_wallet_confirmed",
39373
+ "vapi_verified",
39374
+ "external_catalog",
39375
+ "approved_vendor",
39376
+ "unverified"
39377
+ ]);
39378
+ var marketplaceBadgeSchema = external_exports.looseObject({
39379
+ code: marketplaceBadgeCodeSchema,
39380
+ label: external_exports.string().trim().min(1).max(80)
39381
+ });
39382
+ var marketplacePublicFactSchema = external_exports.looseObject({
39383
+ label: external_exports.string().trim().min(1).max(80),
39384
+ value: external_exports.string().trim().min(1).max(160)
39385
+ });
39386
+ var marketplaceHrefSchema = external_exports.union([
39387
+ external_exports.string().trim().min(1).max(2048).regex(/^\/(?!\/)/),
39388
+ external_exports.url().max(2048).regex(/^https:\/\//)
39389
+ ]);
39390
+ var marketplaceCardSchema = external_exports.looseObject({
39391
+ title: external_exports.string().trim().min(1).max(160),
39392
+ summary: external_exports.string().trim().min(1).max(1e3),
39393
+ byline: external_exports.string().trim().min(1).max(160).optional(),
39394
+ bylineHref: marketplaceHrefSchema.optional(),
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
+ ),
39402
+ facts: external_exports.array(marketplacePublicFactSchema).max(12)
39403
+ });
39404
+ var marketplaceHitBase = {
39405
+ ref: external_exports.string().trim().min(1).max(512),
39406
+ card: marketplaceCardSchema,
39407
+ ...listingDisclosureShape
39915
39408
  };
39916
- function parseEip155ChainId(network) {
39917
- const match = /^eip155:(\d+)$/.exec(network);
39918
- if (!match) {
39919
- throw new Error(`Unsupported network ${network}; expected eip155:<chainId>.`);
39920
- }
39921
- const chainId = Number(match[1]);
39922
- if (!Number.isSafeInteger(chainId) || chainId <= 0) {
39923
- throw new Error(`Invalid EVM chain ID in network ${network}.`);
39924
- }
39925
- return chainId;
39926
- }
39927
- function isSolanaNetwork(network) {
39928
- return network === SOLANA_MAINNET_CAIP2 || network === X402_SOLANA_MAINNET_CAIP2;
39929
- }
39930
- function usesUsdcGas(network) {
39931
- try {
39932
- return getNetworkDefinition(network).gasToken === "USDC";
39933
- } catch {
39934
- return false;
39935
- }
39936
- }
39937
- function explorerTransactionUrl(network, hash5) {
39938
- try {
39939
- const explorerUrl = getNetworkDefinition(network).explorerUrl;
39940
- return explorerUrl ? `${explorerUrl}/tx/${hash5}` : void 0;
39941
- } catch {
39942
- return void 0;
39943
- }
39944
- }
39945
- function explorerAddressUrl(network, address4) {
39946
- try {
39947
- const explorerUrl = getNetworkDefinition(network).explorerUrl;
39948
- return explorerUrl ? `${explorerUrl}/address/${address4}` : void 0;
39949
- } catch {
39950
- return void 0;
39951
- }
39952
- }
39953
- function areSamePaymentNetwork(left, right) {
39954
- return left === right || isSolanaNetwork(left) && isSolanaNetwork(right);
39955
- }
39956
- function isSupportedPaymentNetwork(network) {
39957
- if (isSolanaNetwork(network)) return true;
39958
- try {
39959
- parseEip155ChainId(network);
39960
- return true;
39961
- } catch {
39962
- return false;
39963
- }
39964
- }
39965
- function configuredNetworkFor(networks, network) {
39966
- const configured = networks[network];
39967
- if (configured) return configured;
39968
- if (network === X402_SOLANA_MAINNET_CAIP2) return networks[SOLANA_MAINNET_CAIP2];
39969
- if (network === SOLANA_MAINNET_CAIP2) return networks[X402_SOLANA_MAINNET_CAIP2];
39970
- return void 0;
39971
- }
39972
- function getNetworkDefinition(network) {
39973
- const known = NETWORKS[network];
39974
- if (known) {
39975
- return known;
39976
- }
39977
- const chainId = parseEip155ChainId(network);
39978
- return {
39979
- family: "evm",
39980
- chainId,
39981
- name: network,
39982
- usdc: getAddress("0x0000000000000000000000000000000000000000"),
39983
- gasToken: "ETH",
39984
- rpcEnv: ""
39985
- };
39986
- }
39987
- function requireRpcUrl(network, configured) {
39988
- const definition = getNetworkDefinition(network);
39989
- const envUrl = definition.rpcEnv ? process.env[definition.rpcEnv]?.trim() : void 0;
39990
- const rpcUrl = envUrl || configured.rpcUrl.trim();
39991
- if (rpcUrl) {
39992
- return rpcUrl;
39993
- }
39994
- if (network === ARC_TESTNET_CAIP2) {
39995
- throw new Error(
39996
- "Arc testnet RPC is required. Set ARC_TESTNET_RPC_URL or add rpcUrl for eip155:5042002 in config.json."
39997
- );
39998
- }
39999
- throw new Error(`RPC URL is required for ${network}.`);
40000
- }
40001
- function createChain(network, rpcUrl) {
40002
- const definition = getNetworkDefinition(network);
40003
- if (definition.family !== "evm" || definition.chainId === void 0) {
40004
- throw new Error(`Network ${network} is not an EVM chain.`);
39409
+ var invokeApiActionSchema = external_exports.looseObject({
39410
+ type: external_exports.literal("invoke_api"),
39411
+ href: marketplaceHrefSchema
39412
+ });
39413
+ var firstPartyApiMarketplaceHitSchema = external_exports.looseObject({
39414
+ ...marketplaceHitBase,
39415
+ kind: external_exports.literal("api"),
39416
+ provenance: firstPartyProvenanceSchema,
39417
+ execution: external_exports.looseObject({
39418
+ mode: executionModeSchema
39419
+ }),
39420
+ action: invokeApiActionSchema
39421
+ });
39422
+ var mirroredApiMarketplaceHitSchema = external_exports.looseObject({
39423
+ ...marketplaceHitBase,
39424
+ kind: external_exports.literal("api"),
39425
+ provenance: external_exports.literal("indexed"),
39426
+ execution: external_exports.looseObject({
39427
+ mode: external_exports.literal("direct"),
39428
+ url: external_exports.url().max(2048).regex(/^https:\/\/(?![^/?#]*@)/),
39429
+ method: marketplaceExecutionMethodSchema.nullable(),
39430
+ network: external_exports.string().trim().max(160).transform((network) => {
39431
+ if (network === "solana") return X402_SOLANA_MAINNET_CAIP2;
39432
+ if (network === "solana-devnet") return SOLANA_DEVNET_CAIP2;
39433
+ return network;
39434
+ }).pipe(
39435
+ external_exports.union([
39436
+ external_exports.string().regex(/^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}$/),
39437
+ // Persisted mainnet configs also use the full genesis hash.
39438
+ external_exports.literal(SOLANA_MAINNET_CAIP2)
39439
+ ])
39440
+ )
39441
+ }),
39442
+ action: invokeApiActionSchema
39443
+ });
39444
+ var apiMarketplaceHitSchema = external_exports.discriminatedUnion("provenance", [
39445
+ firstPartyApiMarketplaceHitSchema,
39446
+ mirroredApiMarketplaceHitSchema
39447
+ ]);
39448
+ var serviceOfferMarketplaceHitSchema = external_exports.looseObject({
39449
+ ...marketplaceHitBase,
39450
+ kind: external_exports.literal("service_offer"),
39451
+ action: external_exports.looseObject({
39452
+ type: external_exports.literal("start_engagement"),
39453
+ href: marketplaceHrefSchema
39454
+ })
39455
+ });
39456
+ var openRequestMarketplaceHitSchema = external_exports.looseObject({
39457
+ ...marketplaceHitBase,
39458
+ kind: external_exports.literal("open_request"),
39459
+ action: external_exports.looseObject({
39460
+ type: external_exports.literal("propose_to_request"),
39461
+ href: marketplaceHrefSchema
39462
+ })
39463
+ });
39464
+ var marketplaceHitSchema = external_exports.union([
39465
+ apiMarketplaceHitSchema,
39466
+ serviceOfferMarketplaceHitSchema,
39467
+ openRequestMarketplaceHitSchema
39468
+ ]);
39469
+ var marketplaceDiscoveryInputSchema = external_exports.strictObject({
39470
+ q: external_exports.string().trim().max(200).optional(),
39471
+ kinds: external_exports.array(marketplaceKindSchema).min(1).max(MARKETPLACE_KINDS.length).optional(),
39472
+ network: external_exports.string().trim().min(1).max(160).optional(),
39473
+ cursor: external_exports.string().trim().min(1).max(4096).optional(),
39474
+ limit: external_exports.number().int().min(1).max(50).optional(),
39475
+ includeUnverified: external_exports.boolean().optional()
39476
+ }).superRefine((input2, context) => {
39477
+ if (input2.kinds && new Set(input2.kinds).size !== input2.kinds.length) {
39478
+ context.addIssue({
39479
+ code: "custom",
39480
+ path: ["kinds"],
39481
+ message: "Marketplace kinds must be unique"
39482
+ });
40005
39483
  }
40006
- return defineChain({
40007
- id: definition.chainId,
40008
- name: definition.name,
40009
- nativeCurrency: definition.gasToken === "USDC" ? { name: "USDC", symbol: "USDC", decimals: USDC_DECIMALS } : { name: "Ether", symbol: "ETH", decimals: 18 },
40010
- rpcUrls: {
40011
- default: { http: [rpcUrl] }
40012
- },
40013
- ...definition.explorerUrl ? {
40014
- blockExplorers: {
40015
- default: { name: `${definition.name} explorer`, url: definition.explorerUrl }
40016
- }
40017
- } : {}
40018
- });
40019
- }
40020
- function createNetworkPublicClient(network, configured, options = {}) {
40021
- const rpcUrl = requireRpcUrl(network, configured);
40022
- return createPublicClient({
40023
- chain: createChain(network, rpcUrl),
40024
- transport: createNetworkHttpTransport(rpcUrl, options)
40025
- });
40026
- }
40027
- function createNetworkHttpTransport(rpcUrl, options = {}) {
40028
- const fetchFn = options.fetch ?? createPublicFetch({
40029
- allowPrivateNetwork: options.allowPrivateNetwork ?? false,
40030
- ...options.lookup ? { lookup: options.lookup } : {}
40031
- });
40032
- return http(rpcUrl, { fetchFn, fetchOptions: { redirect: "manual" } });
40033
- }
40034
- function formatUsdc(amountAtomic2) {
40035
- return formatUnits(amountAtomic2, USDC_DECIMALS);
39484
+ });
39485
+ function isMirroredHit(hit) {
39486
+ return hit.kind === "api" && hit.provenance === "indexed";
40036
39487
  }
39488
+ var marketplaceDiscoveryEnvelopeSchema = external_exports.looseObject({
39489
+ protocol: external_exports.literal(MARKETPLACE_DISCOVERY_PROTOCOL),
39490
+ items: external_exports.array(external_exports.unknown()),
39491
+ nextCursor: external_exports.string().min(1).max(4096).nullable(),
39492
+ unavailableKinds: external_exports.array(marketplaceKindSchema).max(MARKETPLACE_KINDS.length),
39493
+ rankingVersion: external_exports.literal(MARKETPLACE_RANKING_VERSION)
39494
+ });
39495
+ var marketplaceDiscoveryPageSchema = marketplaceDiscoveryEnvelopeSchema.extend({
39496
+ items: external_exports.array(marketplaceHitSchema)
39497
+ });
40037
39498
 
40038
39499
  // ../../node_modules/.pnpm/@solana+errors@5.5.1_typescript@6.0.3/node_modules/@solana/errors/dist/index.node.mjs
40039
39500
  var SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED = 1;
@@ -45015,16 +44476,16 @@ var DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;
45015
44476
  var DEFAULT_COMPUTE_UNIT_LIMIT = 2e4;
45016
44477
  var MAX_MEMO_BYTES = 256;
45017
44478
  var SOLANA_MAINNET_CAIP22 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
45018
- var SOLANA_DEVNET_CAIP2 = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
44479
+ var SOLANA_DEVNET_CAIP22 = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
45019
44480
  var SOLANA_TESTNET_CAIP2 = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
45020
44481
  var V1_TO_V2_NETWORK_MAP = {
45021
44482
  solana: SOLANA_MAINNET_CAIP22,
45022
- "solana-devnet": SOLANA_DEVNET_CAIP2,
44483
+ "solana-devnet": SOLANA_DEVNET_CAIP22,
45023
44484
  "solana-testnet": SOLANA_TESTNET_CAIP2
45024
44485
  };
45025
44486
  function normalizeNetwork(network) {
45026
44487
  if (network.includes(":")) {
45027
- const supported = [SOLANA_MAINNET_CAIP22, SOLANA_DEVNET_CAIP2, SOLANA_TESTNET_CAIP2];
44488
+ const supported = [SOLANA_MAINNET_CAIP22, SOLANA_DEVNET_CAIP22, SOLANA_TESTNET_CAIP2];
45028
44489
  if (!supported.includes(network)) {
45029
44490
  throw new Error(`Unsupported SVM network: ${network}`);
45030
44491
  }
@@ -45072,7 +44533,7 @@ var DEFAULT_ASSETS = {
45072
44533
  tokenProgram: TOKEN_2022_PROGRAM_ADDRESS2
45073
44534
  }
45074
44535
  ],
45075
- [SOLANA_DEVNET_CAIP2]: [
44536
+ [SOLANA_DEVNET_CAIP22]: [
45076
44537
  {
45077
44538
  asset: USDC_DEVNET_ADDRESS,
45078
44539
  decimals: 6,
@@ -45127,7 +44588,7 @@ var findDefaultAsset = (asset, network) => {
45127
44588
  function createRpcClient(network, customRpcUrl) {
45128
44589
  const caip2Network = normalizeNetwork(network);
45129
44590
  switch (caip2Network) {
45130
- case SOLANA_DEVNET_CAIP2: {
44591
+ case SOLANA_DEVNET_CAIP22: {
45131
44592
  const url2 = customRpcUrl || DEVNET_RPC_URL;
45132
44593
  return createSolanaRpc(devnet(url2));
45133
44594
  }
@@ -45325,6 +44786,376 @@ var ExactSvmScheme = class {
45325
44786
  var addressEncoder = getAddressEncoder();
45326
44787
  var compiledMessageDecoder = getCompiledTransactionMessageDecoder();
45327
44788
 
44789
+ // ../core/src/net-guard.ts
44790
+ import { lookup as dnsLookup } from "node:dns/promises";
44791
+ import { request as httpRequest } from "node:http";
44792
+ import { request as httpsRequest } from "node:https";
44793
+ import { isIP } from "node:net";
44794
+ import { Readable } from "node:stream";
44795
+ var defaultLookup = async (hostname3) => {
44796
+ const addresses = await dnsLookup(hostname3, { all: true });
44797
+ return addresses.map(({ address: address4 }) => address4);
44798
+ };
44799
+ async function assertPublicUrl(url2, options) {
44800
+ if (url2.username || url2.password) {
44801
+ throw guardError(url2);
44802
+ }
44803
+ if (url2.protocol !== "http:" && url2.protocol !== "https:") {
44804
+ throw guardError(url2);
44805
+ }
44806
+ if (options.allowPrivateNetwork) {
44807
+ return;
44808
+ }
44809
+ const hostname3 = normalizeHostname(url2.hostname);
44810
+ const lowercaseHostname = hostname3.toLowerCase();
44811
+ if (!lowercaseHostname || lowercaseHostname === "localhost" || lowercaseHostname.endsWith(".localhost") || lowercaseHostname.endsWith(".local") || lowercaseHostname.endsWith(".internal")) {
44812
+ throw guardError(url2);
44813
+ }
44814
+ if (isIP(hostname3)) {
44815
+ if (isNonPublicAddress(hostname3)) {
44816
+ throw guardError(url2);
44817
+ }
44818
+ return;
44819
+ }
44820
+ let addresses;
44821
+ try {
44822
+ addresses = await withTimeout2(
44823
+ (options.lookup ?? defaultLookup)(hostname3),
44824
+ options.timeoutMs ?? 5e3
44825
+ );
44826
+ } catch {
44827
+ throw guardError(url2);
44828
+ }
44829
+ if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
44830
+ throw guardError(url2);
44831
+ }
44832
+ }
44833
+ function createPublicFetch(options) {
44834
+ const lookupFn = options.lookup ?? defaultLookup;
44835
+ return (async (input2, init) => {
44836
+ const url2 = new URL(input2 instanceof Request ? input2.url : input2);
44837
+ await assertPublicUrl(url2, {
44838
+ allowPrivateNetwork: options.allowPrivateNetwork,
44839
+ lookup: lookupFn,
44840
+ timeoutMs: 5e3
44841
+ });
44842
+ const normalized = new Request(input2, init);
44843
+ const bytes = normalized.body ? Buffer.from(await normalized.arrayBuffer()) : null;
44844
+ return await new Promise((resolve2, reject) => {
44845
+ const requestOptions2 = {
44846
+ method: normalized.method,
44847
+ headers: Object.fromEntries(normalized.headers),
44848
+ signal: normalized.signal,
44849
+ ...options.allowPrivateNetwork ? {} : { lookup: pinnedLookup(lookupFn) }
44850
+ };
44851
+ const onResponse = (incoming) => {
44852
+ try {
44853
+ const headers = new Headers();
44854
+ for (const [name, value] of Object.entries(incoming.headers)) {
44855
+ if (Array.isArray(value)) {
44856
+ for (const item of value) headers.append(name, item);
44857
+ } else if (value !== void 0) {
44858
+ headers.set(name, value);
44859
+ }
44860
+ }
44861
+ const status = incoming.statusCode ?? 500;
44862
+ const bodyForbidden = normalized.method === "HEAD" || [204, 205, 304].includes(status);
44863
+ if (bodyForbidden) incoming.resume();
44864
+ const response = new Response(
44865
+ bodyForbidden ? null : Readable.toWeb(incoming),
44866
+ { status, statusText: incoming.statusMessage, headers }
44867
+ );
44868
+ Object.defineProperty(response, "url", { value: url2.toString() });
44869
+ resolve2(response);
44870
+ } catch (error61) {
44871
+ incoming.destroy();
44872
+ reject(error61);
44873
+ }
44874
+ };
44875
+ const request = url2.protocol === "https:" ? httpsRequest(url2, requestOptions2, onResponse) : httpRequest(url2, requestOptions2, onResponse);
44876
+ request.on("error", reject);
44877
+ if (bytes) request.write(bytes);
44878
+ request.end();
44879
+ });
44880
+ });
44881
+ }
44882
+ function pinnedLookup(lookup2) {
44883
+ return (hostname3, dnsOptions, callback) => {
44884
+ void lookup2(normalizeHostname(hostname3)).then((addresses) => {
44885
+ if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
44886
+ callback(guardError(new URL(`https://${hostname3}`)), "");
44887
+ return;
44888
+ }
44889
+ const address4 = addresses[0];
44890
+ const family = isIP(address4);
44891
+ callback(
44892
+ null,
44893
+ dnsOptions.all ? [{ address: address4, family }] : address4,
44894
+ dnsOptions.all ? void 0 : family
44895
+ );
44896
+ }).catch(
44897
+ (error61) => callback(error61 instanceof Error ? error61 : new Error("DNS lookup failed."), "")
44898
+ );
44899
+ };
44900
+ }
44901
+ async function withTimeout2(operation, timeoutMs) {
44902
+ let timeout;
44903
+ try {
44904
+ return await Promise.race([
44905
+ operation,
44906
+ new Promise((_resolve, reject) => {
44907
+ timeout = setTimeout(() => reject(new Error("DNS lookup timed out.")), timeoutMs);
44908
+ })
44909
+ ]);
44910
+ } finally {
44911
+ if (timeout) clearTimeout(timeout);
44912
+ }
44913
+ }
44914
+ function normalizeHostname(hostname3) {
44915
+ const unbracketed = hostname3.startsWith("[") && hostname3.endsWith("]") ? hostname3.slice(1, -1) : hostname3;
44916
+ return unbracketed.endsWith(".") ? unbracketed.slice(0, -1) : unbracketed;
44917
+ }
44918
+ function isNonPublicAddress(address4) {
44919
+ const normalized = normalizeHostname(address4);
44920
+ const version5 = isIP(normalized);
44921
+ if (version5 === 4) {
44922
+ return isNonPublicIpv4(parseIpv4(normalized));
44923
+ }
44924
+ if (version5 === 6) {
44925
+ return isNonPublicIpv6(parseIpv6(normalized));
44926
+ }
44927
+ return true;
44928
+ }
44929
+ function parseIpv4(address4) {
44930
+ const octets = address4.split(".").map(Number);
44931
+ return [octets[0], octets[1], octets[2], octets[3]];
44932
+ }
44933
+ function isNonPublicIpv4([first, second, third]) {
44934
+ return first === 0 || first === 10 || first === 100 && second >= 64 && second <= 127 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 0 && (third === 0 || third === 2) || first === 192 && second === 168 || first === 198 && second >= 18 && second <= 19 || first === 198 && second === 51 && third === 100 || first === 203 && second === 0 && third === 113 || first >= 224;
44935
+ }
44936
+ function parseIpv6(address4) {
44937
+ let normalized = address4.toLowerCase();
44938
+ const lastColon = normalized.lastIndexOf(":");
44939
+ const dottedTail = normalized.slice(lastColon + 1);
44940
+ if (dottedTail.includes(".")) {
44941
+ const [first, second, third, fourth] = parseIpv4(dottedTail);
44942
+ normalized = `${normalized.slice(0, lastColon + 1)}${(first << 8 | second).toString(16)}:${(third << 8 | fourth).toString(16)}`;
44943
+ }
44944
+ const halves = normalized.split("::");
44945
+ const left = halves[0] ? halves[0].split(":").map(parseHex) : [];
44946
+ const right = halves[1] ? halves[1].split(":").map(parseHex) : [];
44947
+ const omittedCount = 8 - left.length - right.length;
44948
+ return halves.length === 2 ? [...left, ...Array.from({ length: omittedCount }, () => 0), ...right] : left;
44949
+ }
44950
+ function parseHex(value) {
44951
+ return Number.parseInt(value, 16);
44952
+ }
44953
+ function isNonPublicIpv6(hextets) {
44954
+ if (hextets.slice(0, 5).every((hextet) => hextet === 0) && hextets[5] === 65535) {
44955
+ const embeddedIpv4 = [
44956
+ hextets[6] >> 8,
44957
+ hextets[6] & 255,
44958
+ hextets[7] >> 8,
44959
+ hextets[7] & 255
44960
+ ];
44961
+ return isNonPublicIpv4(embeddedIpv4);
44962
+ }
44963
+ if (hextets.slice(0, 6).every((hextet) => hextet === 0)) {
44964
+ const compatibleIpv4 = [
44965
+ hextets[6] >> 8,
44966
+ hextets[6] & 255,
44967
+ hextets[7] >> 8,
44968
+ hextets[7] & 255
44969
+ ];
44970
+ if (isNonPublicIpv4(compatibleIpv4)) return true;
44971
+ }
44972
+ const isUnspecified = hextets.every((hextet) => hextet === 0);
44973
+ const isLoopback = hextets.slice(0, 7).every((hextet) => hextet === 0) && hextets[7] === 1;
44974
+ const first = hextets[0];
44975
+ const isUniqueLocal = first >= 64512 && first <= 65023;
44976
+ const isLinkLocal = first >= 65152 && first <= 65215;
44977
+ const isSiteLocal = first >= 65216 && first <= 65279;
44978
+ const isMulticast = first >= 65280;
44979
+ const isDocumentation = first === 8193 && hextets[1] === 3512;
44980
+ return isUnspecified || isLoopback || isUniqueLocal || isLinkLocal || isSiteLocal || isMulticast || isDocumentation;
44981
+ }
44982
+ function guardError(url2) {
44983
+ return new Error(
44984
+ `URL hostname ${JSON.stringify(url2.hostname)} is not allowed; private or internal destinations require allowPrivateNetwork true in the vAPI config.`
44985
+ );
44986
+ }
44987
+
44988
+ // ../core/src/networks.ts
44989
+ var USDC_DECIMALS = 6;
44990
+ var DEFAULT_ARC_GAS_HEADROOM_ATOMIC = 50000n;
44991
+ var NETWORKS2 = {
44992
+ [BASE_MAINNET_CAIP2]: {
44993
+ family: "evm",
44994
+ chainId: 8453,
44995
+ name: "Base mainnet",
44996
+ usdc: CANONICAL_X402_USDC_NETWORKS[BASE_MAINNET_CAIP2].usdc,
44997
+ gasToken: "ETH",
44998
+ rpcEnv: "BASE_RPC_URL",
44999
+ publicRpcUrl: "https://mainnet.base.org",
45000
+ explorerUrl: "https://basescan.org"
45001
+ },
45002
+ [ARC_MAINNET_CAIP2]: {
45003
+ family: "evm",
45004
+ chainId: 5042,
45005
+ name: "Arc mainnet",
45006
+ usdc: CANONICAL_X402_USDC_NETWORKS[ARC_MAINNET_CAIP2].usdc,
45007
+ gasToken: "USDC",
45008
+ rpcEnv: "ARC_RPC_URL",
45009
+ publicRpcUrl: "https://rpc.mainnet.arc.io",
45010
+ explorerUrl: "https://explorer.arc.io"
45011
+ },
45012
+ [ARC_TESTNET_CAIP2]: {
45013
+ family: "evm",
45014
+ chainId: 5042002,
45015
+ name: "Arc testnet",
45016
+ usdc: CANONICAL_X402_USDC_NETWORKS[ARC_TESTNET_CAIP2].usdc,
45017
+ gasToken: "USDC",
45018
+ rpcEnv: "ARC_TESTNET_RPC_URL"
45019
+ },
45020
+ [SOLANA_MAINNET_CAIP2]: {
45021
+ family: "svm",
45022
+ name: "Solana mainnet",
45023
+ usdc: SOLANA_MAINNET_USDC,
45024
+ gasToken: "SOL",
45025
+ rpcEnv: "SOLANA_RPC_URL",
45026
+ publicRpcUrl: "https://api.mainnet-beta.solana.com"
45027
+ },
45028
+ [X402_SOLANA_MAINNET_CAIP2]: {
45029
+ family: "svm",
45030
+ name: "Solana mainnet",
45031
+ usdc: SOLANA_MAINNET_USDC,
45032
+ gasToken: "SOL",
45033
+ rpcEnv: "SOLANA_RPC_URL",
45034
+ publicRpcUrl: "https://api.mainnet-beta.solana.com"
45035
+ }
45036
+ };
45037
+ function parseEip155ChainId(network) {
45038
+ const match = /^eip155:(\d+)$/.exec(network);
45039
+ if (!match) {
45040
+ throw new Error(`Unsupported network ${network}; expected eip155:<chainId>.`);
45041
+ }
45042
+ const chainId = Number(match[1]);
45043
+ if (!Number.isSafeInteger(chainId) || chainId <= 0) {
45044
+ throw new Error(`Invalid EVM chain ID in network ${network}.`);
45045
+ }
45046
+ return chainId;
45047
+ }
45048
+ function isSolanaNetwork(network) {
45049
+ return network === SOLANA_MAINNET_CAIP2 || network === X402_SOLANA_MAINNET_CAIP2;
45050
+ }
45051
+ function usesUsdcGas(network) {
45052
+ try {
45053
+ return getNetworkDefinition(network).gasToken === "USDC";
45054
+ } catch {
45055
+ return false;
45056
+ }
45057
+ }
45058
+ function explorerTransactionUrl(network, hash5) {
45059
+ try {
45060
+ const explorerUrl = getNetworkDefinition(network).explorerUrl;
45061
+ return explorerUrl ? `${explorerUrl}/tx/${hash5}` : void 0;
45062
+ } catch {
45063
+ return void 0;
45064
+ }
45065
+ }
45066
+ function explorerAddressUrl(network, address4) {
45067
+ try {
45068
+ const explorerUrl = getNetworkDefinition(network).explorerUrl;
45069
+ return explorerUrl ? `${explorerUrl}/address/${address4}` : void 0;
45070
+ } catch {
45071
+ return void 0;
45072
+ }
45073
+ }
45074
+ function areSamePaymentNetwork(left, right) {
45075
+ return left === right || isSolanaNetwork(left) && isSolanaNetwork(right);
45076
+ }
45077
+ function isSupportedPaymentNetwork(network) {
45078
+ if (isSolanaNetwork(network)) return true;
45079
+ try {
45080
+ parseEip155ChainId(network);
45081
+ return true;
45082
+ } catch {
45083
+ return false;
45084
+ }
45085
+ }
45086
+ function configuredNetworkFor(networks, network) {
45087
+ const configured = networks[network];
45088
+ if (configured) return configured;
45089
+ if (network === X402_SOLANA_MAINNET_CAIP2) return networks[SOLANA_MAINNET_CAIP2];
45090
+ if (network === SOLANA_MAINNET_CAIP2) return networks[X402_SOLANA_MAINNET_CAIP2];
45091
+ return void 0;
45092
+ }
45093
+ function getNetworkDefinition(network) {
45094
+ const known = NETWORKS2[network];
45095
+ if (known) {
45096
+ return known;
45097
+ }
45098
+ const chainId = parseEip155ChainId(network);
45099
+ return {
45100
+ family: "evm",
45101
+ chainId,
45102
+ name: network,
45103
+ usdc: getAddress("0x0000000000000000000000000000000000000000"),
45104
+ gasToken: "ETH",
45105
+ rpcEnv: ""
45106
+ };
45107
+ }
45108
+ function requireRpcUrl(network, configured) {
45109
+ const definition = getNetworkDefinition(network);
45110
+ const envUrl = definition.rpcEnv ? process.env[definition.rpcEnv]?.trim() : void 0;
45111
+ const rpcUrl = envUrl || configured.rpcUrl.trim();
45112
+ if (rpcUrl) {
45113
+ return rpcUrl;
45114
+ }
45115
+ if (network === ARC_TESTNET_CAIP2) {
45116
+ throw new Error(
45117
+ "Arc testnet RPC is required. Set ARC_TESTNET_RPC_URL or add rpcUrl for eip155:5042002 in config.json."
45118
+ );
45119
+ }
45120
+ throw new Error(`RPC URL is required for ${network}.`);
45121
+ }
45122
+ function createChain(network, rpcUrl) {
45123
+ const definition = getNetworkDefinition(network);
45124
+ if (definition.family !== "evm" || definition.chainId === void 0) {
45125
+ throw new Error(`Network ${network} is not an EVM chain.`);
45126
+ }
45127
+ return defineChain({
45128
+ id: definition.chainId,
45129
+ name: definition.name,
45130
+ nativeCurrency: definition.gasToken === "USDC" ? { name: "USDC", symbol: "USDC", decimals: USDC_DECIMALS } : { name: "Ether", symbol: "ETH", decimals: 18 },
45131
+ rpcUrls: {
45132
+ default: { http: [rpcUrl] }
45133
+ },
45134
+ ...definition.explorerUrl ? {
45135
+ blockExplorers: {
45136
+ default: { name: `${definition.name} explorer`, url: definition.explorerUrl }
45137
+ }
45138
+ } : {}
45139
+ });
45140
+ }
45141
+ function createNetworkPublicClient(network, configured, options = {}) {
45142
+ const rpcUrl = requireRpcUrl(network, configured);
45143
+ return createPublicClient({
45144
+ chain: createChain(network, rpcUrl),
45145
+ transport: createNetworkHttpTransport(rpcUrl, options)
45146
+ });
45147
+ }
45148
+ function createNetworkHttpTransport(rpcUrl, options = {}) {
45149
+ const fetchFn = options.fetch ?? createPublicFetch({
45150
+ allowPrivateNetwork: options.allowPrivateNetwork ?? false,
45151
+ ...options.lookup ? { lookup: options.lookup } : {}
45152
+ });
45153
+ return http(rpcUrl, { fetchFn, fetchOptions: { redirect: "manual" } });
45154
+ }
45155
+ function formatUsdc(amountAtomic2) {
45156
+ return formatUnits(amountAtomic2, USDC_DECIMALS);
45157
+ }
45158
+
45328
45159
  // ../core/src/x402.ts
45329
45160
  var MAX_CHALLENGE_BYTES = 1048576;
45330
45161
  var MAX_UINT256 = (1n << 256n) - 1n;
@@ -46184,6 +46015,242 @@ function isRecord2(value) {
46184
46015
  return typeof value === "object" && value !== null && !Array.isArray(value);
46185
46016
  }
46186
46017
 
46018
+ // ../core/src/call-contracts-wire.ts
46019
+ var CALLABLE_CATEGORIES = ["ai", "data", "crypto", "compute", "search"];
46020
+ var callableCategorySchema = external_exports.enum(CALLABLE_CATEGORIES);
46021
+ var DISCOVERY_CATEGORIES = [...CALLABLE_CATEGORIES, "other"];
46022
+ var discoveryCategorySchema = external_exports.string().trim().min(1);
46023
+ var CALLABLE_CATEGORY_SET = new Set(CALLABLE_CATEGORIES);
46024
+ var serviceTierSchema = external_exports.string().trim().min(1);
46025
+ var discoveryEndpointSchema = external_exports.looseObject({
46026
+ name: external_exports.string(),
46027
+ method: external_exports.string(),
46028
+ url: external_exports.url(),
46029
+ price: external_exports.string(),
46030
+ description: external_exports.string(),
46031
+ operationId: external_exports.string().trim().min(1).optional(),
46032
+ requestContentType: external_exports.string().trim().min(1).optional(),
46033
+ requestSchema: external_exports.json().optional(),
46034
+ responseContentType: external_exports.string().trim().min(1).optional(),
46035
+ pathTemplate: external_exports.string().trim().min(1).optional(),
46036
+ pathParameters: external_exports.array(external_exports.string().trim().min(1)).optional(),
46037
+ payment: external_exports.union([
46038
+ external_exports.looseObject({
46039
+ scheme: external_exports.literal("exact"),
46040
+ network: external_exports.string().regex(/^eip155:\d+$/),
46041
+ asset: external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/),
46042
+ payTo: external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/),
46043
+ checkedAt: external_exports.iso.datetime()
46044
+ }),
46045
+ external_exports.looseObject({
46046
+ scheme: external_exports.literal("exact"),
46047
+ network: external_exports.union([
46048
+ external_exports.string().regex(/^solana:[-_a-zA-Z0-9]{1,32}$/),
46049
+ external_exports.literal(SOLANA_MAINNET_CAIP2)
46050
+ ]),
46051
+ asset: external_exports.string().refine(isSolanaAddress, "Expected a Solana base58 address."),
46052
+ payTo: external_exports.string().refine(isSolanaAddress, "Expected a Solana base58 address."),
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()
46072
+ })
46073
+ ]).optional()
46074
+ });
46075
+ var serviceSummarySchema = external_exports.looseObject({
46076
+ id: external_exports.string(),
46077
+ name: external_exports.string(),
46078
+ description: external_exports.string(),
46079
+ category: discoveryCategorySchema,
46080
+ tier: serviceTierSchema,
46081
+ ...listingDisclosureShape,
46082
+ verified: external_exports.boolean(),
46083
+ wrapped: external_exports.boolean(),
46084
+ price: external_exports.string(),
46085
+ networks: external_exports.array(external_exports.string()),
46086
+ endpoints: external_exports.array(discoveryEndpointSchema)
46087
+ });
46088
+ var searchServicesResponseSchema = external_exports.looseObject({
46089
+ services: external_exports.array(serviceSummarySchema)
46090
+ });
46091
+ var discoveryResponseSchema = searchServicesResponseSchema;
46092
+
46093
+ // ../core/src/call-contracts.ts
46094
+ var DiscoveryCatalogError = class extends Error {
46095
+ constructor(code, message, serviceId, paymentNetworks) {
46096
+ super(message);
46097
+ this.paymentNetworks = paymentNetworks;
46098
+ this.code = code;
46099
+ this.serviceId = serviceId;
46100
+ }
46101
+ paymentNetworks;
46102
+ name = "DiscoveryCatalogError";
46103
+ code;
46104
+ serviceId;
46105
+ };
46106
+ function isDiscoveryCatalogError(error61) {
46107
+ if (!(error61 instanceof Error) || error61.name !== "DiscoveryCatalogError" || !("code" in error61) || typeof error61.code !== "string") {
46108
+ return false;
46109
+ }
46110
+ const networks = Reflect.get(error61, "paymentNetworks");
46111
+ return networks === void 0 || Array.isArray(networks) && networks.every((network) => typeof network === "string");
46112
+ }
46113
+ function parseDiscovery(raw) {
46114
+ const parsed = discoveryResponseSchema.safeParse(raw);
46115
+ if (!parsed.success) {
46116
+ const malformedUrl = parsed.error.issues.find(
46117
+ (issue2) => issue2.path.at(-1) === "url" && issue2.path.includes("endpoints")
46118
+ );
46119
+ if (malformedUrl) {
46120
+ const serviceIndex = pathIndexAfter(malformedUrl.path, "services");
46121
+ const serviceId = rawServiceId(raw, serviceIndex);
46122
+ throw new DiscoveryCatalogError(
46123
+ "malformed_url",
46124
+ `Service ${JSON.stringify(serviceId ?? "unknown")} has a malformed endpoint URL.`,
46125
+ serviceId
46126
+ );
46127
+ }
46128
+ throw new DiscoveryCatalogError("invalid_discovery", "Discovery response is malformed.");
46129
+ }
46130
+ for (const service of parsed.data.services) {
46131
+ buildTargets(service);
46132
+ }
46133
+ const resolveListing = (serviceId, endpointName) => {
46134
+ const service = parsed.data.services.find((candidate) => candidate.id === serviceId);
46135
+ if (!service) {
46136
+ throw new DiscoveryCatalogError(
46137
+ "service_not_found",
46138
+ `No payable endpoint found for service ${JSON.stringify(serviceId)}.`,
46139
+ serviceId
46140
+ );
46141
+ }
46142
+ return { service, endpoint: resolveTarget(service, endpointName) };
46143
+ };
46144
+ return {
46145
+ services: parsed.data.services,
46146
+ resolve: (serviceId, endpointName) => resolveListing(serviceId, endpointName).endpoint,
46147
+ resolveListing
46148
+ };
46149
+ }
46150
+ function resolveTarget(service, endpointName) {
46151
+ const { targets, targetsByName } = buildTargets(service);
46152
+ if (endpointName !== void 0) {
46153
+ const selected = targetsByName.get(endpointName.trim());
46154
+ if (!selected) {
46155
+ throw new DiscoveryCatalogError(
46156
+ "endpoint_not_found",
46157
+ `Service ${JSON.stringify(service.id)} has no endpoint ${JSON.stringify(endpointName)}. Available endpoints: ${[...targetsByName.keys()].join(", ")}.`,
46158
+ service.id
46159
+ );
46160
+ }
46161
+ return { ...selected };
46162
+ }
46163
+ if (targets.size !== 1) {
46164
+ const paymentNetworks = service.endpoints.flatMap(
46165
+ (endpoint) => typeof endpoint.payment?.network === "string" ? [endpoint.payment.network] : []
46166
+ );
46167
+ throw new DiscoveryCatalogError(
46168
+ "ambiguous_default",
46169
+ `Service ${JSON.stringify(service.id)} has ${targets.size} distinct payable endpoints. Choose one with endpoint: ${[...targetsByName.keys()].join(", ")}.`,
46170
+ service.id,
46171
+ paymentNetworks.length === service.endpoints.length ? paymentNetworks : void 0
46172
+ );
46173
+ }
46174
+ return targets.values().next().value;
46175
+ }
46176
+ function buildTargets(service) {
46177
+ if (service.endpoints.length === 0) {
46178
+ throw new DiscoveryCatalogError(
46179
+ "no_endpoint",
46180
+ `Service ${JSON.stringify(service.id)} has no payable endpoint.`,
46181
+ service.id
46182
+ );
46183
+ }
46184
+ const namedEndpoints = [...service.endpoints].sort(
46185
+ (left, right) => compareNames(left.name.trim(), right.name.trim())
46186
+ );
46187
+ const names = /* @__PURE__ */ new Set();
46188
+ const targets = /* @__PURE__ */ new Map();
46189
+ const targetsByName = /* @__PURE__ */ new Map();
46190
+ for (const endpoint of namedEndpoints) {
46191
+ const name = endpoint.name.trim();
46192
+ if (!name) {
46193
+ throw new DiscoveryCatalogError(
46194
+ "invalid_endpoint_name",
46195
+ `Service ${JSON.stringify(service.id)} has a blank endpoint name.`,
46196
+ service.id
46197
+ );
46198
+ }
46199
+ if (names.has(name)) {
46200
+ throw new DiscoveryCatalogError(
46201
+ "duplicate_endpoint_name",
46202
+ `Service ${JSON.stringify(service.id)} has duplicate endpoint name ${JSON.stringify(name)}.`,
46203
+ service.id
46204
+ );
46205
+ }
46206
+ names.add(name);
46207
+ const method = endpoint.method.trim().toUpperCase();
46208
+ if (!method) {
46209
+ throw new DiscoveryCatalogError(
46210
+ "blank_method",
46211
+ `Service ${JSON.stringify(service.id)} has a blank endpoint method.`,
46212
+ service.id
46213
+ );
46214
+ }
46215
+ const url2 = new URL(endpoint.url);
46216
+ if (url2.protocol !== "http:" && url2.protocol !== "https:") {
46217
+ throw new DiscoveryCatalogError(
46218
+ "malformed_url",
46219
+ `Service ${JSON.stringify(service.id)} has a non-HTTP endpoint URL.`,
46220
+ service.id
46221
+ );
46222
+ }
46223
+ const transportKey = `${method}\0${endpoint.url}`;
46224
+ const normalized = { ...endpoint, name, method };
46225
+ targetsByName.set(name, normalized);
46226
+ if (!targets.has(transportKey)) targets.set(transportKey, normalized);
46227
+ }
46228
+ return { targets, targetsByName };
46229
+ }
46230
+ function compareNames(left, right) {
46231
+ return left < right ? -1 : left > right ? 1 : 0;
46232
+ }
46233
+ function pathIndexAfter(path, key2) {
46234
+ const keyIndex = path.indexOf(key2);
46235
+ const candidate = path[keyIndex + 1];
46236
+ return typeof candidate === "number" ? candidate : void 0;
46237
+ }
46238
+ function rawServiceId(raw, serviceIndex) {
46239
+ if (serviceIndex === void 0 || typeof raw !== "object" || raw === null) {
46240
+ return void 0;
46241
+ }
46242
+ const services = Reflect.get(raw, "services");
46243
+ if (!Array.isArray(services)) {
46244
+ return void 0;
46245
+ }
46246
+ const service = services[serviceIndex];
46247
+ if (typeof service !== "object" || service === null) {
46248
+ return void 0;
46249
+ }
46250
+ const id2 = Reflect.get(service, "id");
46251
+ return typeof id2 === "string" ? id2 : void 0;
46252
+ }
46253
+
46187
46254
  // ../core/src/sweep.ts
46188
46255
  var ERC20_ABI = [
46189
46256
  {
@@ -47032,7 +47099,7 @@ var configSchema = external_exports.object({
47032
47099
  }
47033
47100
  for (const [network, configured] of Object.entries(config2.networks)) {
47034
47101
  if (isSolanaNetwork(network)) {
47035
- if (configured.usdc !== NETWORKS[SOLANA_MAINNET_CAIP2].usdc) {
47102
+ if (configured.usdc !== NETWORKS2[SOLANA_MAINNET_CAIP2].usdc) {
47036
47103
  context.addIssue({
47037
47104
  code: "custom",
47038
47105
  path: ["networks", network, "usdc"],
@@ -47043,7 +47110,7 @@ var configSchema = external_exports.object({
47043
47110
  }
47044
47111
  try {
47045
47112
  const usdc = getAddress(configured.usdc);
47046
- if ((network === ARC_MAINNET_CAIP2 || network === ARC_TESTNET_CAIP2) && usdc !== getAddress(NETWORKS[network].usdc)) {
47113
+ if ((network === ARC_MAINNET_CAIP2 || network === ARC_TESTNET_CAIP2) && usdc !== getAddress(NETWORKS2[network].usdc)) {
47047
47114
  context.addIssue({
47048
47115
  code: "custom",
47049
47116
  path: ["networks", network, "usdc"],
@@ -47070,7 +47137,8 @@ function getVapiPaths(directory = process.env.VAPI_HOME?.trim() || join2(homedir
47070
47137
  keystore: join2(directory, "keystore.json"),
47071
47138
  receipts: join2(directory, "receipts.jsonl"),
47072
47139
  searches: join2(directory, "searches.jsonl"),
47073
- ledger: join2(directory, "spend-ledger.json")
47140
+ ledger: join2(directory, "spend-ledger.json"),
47141
+ updateCheck: join2(directory, "update-check.json")
47074
47142
  };
47075
47143
  }
47076
47144
  var getAgentCashPaths = getVapiPaths;
@@ -47195,15 +47263,15 @@ function getDefaultConfig(source = process.env, options = {}) {
47195
47263
  const tasksEscrowFactoryOverrides = tasksFactoryOverridesFromEnv(source);
47196
47264
  if (requested.has("base") || requested.has(BASE_MAINNET_CAIP2)) {
47197
47265
  networks[BASE_MAINNET_CAIP2] = {
47198
- rpcUrl: source.BASE_RPC_URL?.trim() || NETWORKS[BASE_MAINNET_CAIP2].publicRpcUrl,
47199
- usdc: NETWORKS[BASE_MAINNET_CAIP2].usdc
47266
+ rpcUrl: source.BASE_RPC_URL?.trim() || NETWORKS2[BASE_MAINNET_CAIP2].publicRpcUrl,
47267
+ usdc: NETWORKS2[BASE_MAINNET_CAIP2].usdc
47200
47268
  };
47201
47269
  }
47202
47270
  const arcMainnetRpcUrl = source.ARC_RPC_URL?.trim();
47203
47271
  if (arcMainnetRpcUrl || requested.has("arc") || requested.has(ARC_MAINNET_CAIP2)) {
47204
47272
  networks[ARC_MAINNET_CAIP2] = {
47205
- rpcUrl: arcMainnetRpcUrl || NETWORKS[ARC_MAINNET_CAIP2].publicRpcUrl,
47206
- usdc: NETWORKS[ARC_MAINNET_CAIP2].usdc
47273
+ rpcUrl: arcMainnetRpcUrl || NETWORKS2[ARC_MAINNET_CAIP2].publicRpcUrl,
47274
+ usdc: NETWORKS2[ARC_MAINNET_CAIP2].usdc
47207
47275
  };
47208
47276
  }
47209
47277
  const arcTestnetRpcUrl = source.ARC_TESTNET_RPC_URL?.trim();
@@ -47215,14 +47283,14 @@ function getDefaultConfig(source = process.env, options = {}) {
47215
47283
  }
47216
47284
  networks[ARC_TESTNET_CAIP2] = {
47217
47285
  rpcUrl: arcTestnetRpcUrl,
47218
- usdc: NETWORKS[ARC_TESTNET_CAIP2].usdc
47286
+ usdc: NETWORKS2[ARC_TESTNET_CAIP2].usdc
47219
47287
  };
47220
47288
  }
47221
47289
  const solanaRpcUrl = source.SOLANA_RPC_URL?.trim();
47222
47290
  if (solanaRpcUrl || requested.has("solana") || requested.has(SOLANA_MAINNET_CAIP2)) {
47223
47291
  networks[SOLANA_MAINNET_CAIP2] = {
47224
- rpcUrl: solanaRpcUrl || NETWORKS[SOLANA_MAINNET_CAIP2].publicRpcUrl,
47225
- usdc: NETWORKS[SOLANA_MAINNET_CAIP2].usdc
47292
+ rpcUrl: solanaRpcUrl || NETWORKS2[SOLANA_MAINNET_CAIP2].publicRpcUrl,
47293
+ usdc: NETWORKS2[SOLANA_MAINNET_CAIP2].usdc
47226
47294
  };
47227
47295
  }
47228
47296
  return {
@@ -47280,21 +47348,21 @@ Run vapi init to write the new URLs to ${path}.`
47280
47348
  if (arcMainnetRpcUrl) {
47281
47349
  const existing = config2.networks[ARC_MAINNET_CAIP2];
47282
47350
  config2.networks[ARC_MAINNET_CAIP2] = {
47283
- ...existing ?? { usdc: NETWORKS[ARC_MAINNET_CAIP2].usdc },
47351
+ ...existing ?? { usdc: NETWORKS2[ARC_MAINNET_CAIP2].usdc },
47284
47352
  rpcUrl: arcMainnetRpcUrl
47285
47353
  };
47286
47354
  }
47287
47355
  if (arcTestnetRpcUrl) {
47288
47356
  const existing = config2.networks[ARC_TESTNET_CAIP2];
47289
47357
  config2.networks[ARC_TESTNET_CAIP2] = {
47290
- ...existing ?? { usdc: NETWORKS[ARC_TESTNET_CAIP2].usdc },
47358
+ ...existing ?? { usdc: NETWORKS2[ARC_TESTNET_CAIP2].usdc },
47291
47359
  rpcUrl: arcTestnetRpcUrl
47292
47360
  };
47293
47361
  }
47294
47362
  if (solanaRpcUrl) {
47295
47363
  config2.networks[SOLANA_MAINNET_CAIP2] = {
47296
47364
  rpcUrl: solanaRpcUrl,
47297
- usdc: config2.networks[SOLANA_MAINNET_CAIP2]?.usdc ?? NETWORKS[SOLANA_MAINNET_CAIP2].usdc
47365
+ usdc: config2.networks[SOLANA_MAINNET_CAIP2]?.usdc ?? NETWORKS2[SOLANA_MAINNET_CAIP2].usdc
47298
47366
  };
47299
47367
  }
47300
47368
  if (registryUrl) {
@@ -47307,7 +47375,7 @@ Run vapi init to write the new URLs to ${path}.`
47307
47375
  for (const [network, configured] of Object.entries(config2.networks)) {
47308
47376
  configured.rpcUrl = configured.rpcUrl.trim();
47309
47377
  configured.usdc = configured.usdc.trim();
47310
- if (isSolanaNetwork(network) && configured.usdc !== NETWORKS[SOLANA_MAINNET_CAIP2].usdc) {
47378
+ if (isSolanaNetwork(network) && configured.usdc !== NETWORKS2[SOLANA_MAINNET_CAIP2].usdc) {
47311
47379
  throw new Error(`Network ${network} must use canonical Solana mainnet USDC.`);
47312
47380
  }
47313
47381
  if (!configured.rpcUrl) delete config2.networks[network];
@@ -47363,14 +47431,14 @@ async function enableDefaultNetwork(network, path = getVapiPaths().config, sourc
47363
47431
  const config2 = await loadConfig(path, source);
47364
47432
  if (network === "solana") {
47365
47433
  config2.networks[SOLANA_MAINNET_CAIP2] = {
47366
- rpcUrl: source.SOLANA_RPC_URL?.trim() || NETWORKS[SOLANA_MAINNET_CAIP2].publicRpcUrl,
47367
- usdc: NETWORKS[SOLANA_MAINNET_CAIP2].usdc
47434
+ rpcUrl: source.SOLANA_RPC_URL?.trim() || NETWORKS2[SOLANA_MAINNET_CAIP2].publicRpcUrl,
47435
+ usdc: NETWORKS2[SOLANA_MAINNET_CAIP2].usdc
47368
47436
  };
47369
47437
  } else {
47370
47438
  const existing = config2.networks[ARC_MAINNET_CAIP2];
47371
47439
  config2.networks[ARC_MAINNET_CAIP2] = {
47372
- ...existing ?? { usdc: NETWORKS[ARC_MAINNET_CAIP2].usdc },
47373
- rpcUrl: source.ARC_RPC_URL?.trim() || NETWORKS[ARC_MAINNET_CAIP2].publicRpcUrl
47440
+ ...existing ?? { usdc: NETWORKS2[ARC_MAINNET_CAIP2].usdc },
47441
+ rpcUrl: source.ARC_RPC_URL?.trim() || NETWORKS2[ARC_MAINNET_CAIP2].publicRpcUrl
47374
47442
  };
47375
47443
  }
47376
47444
  await writeConfigFile(path, config2);
@@ -70334,7 +70402,7 @@ function windowsDataProtectionStore(platform2, run, env, installed) {
70334
70402
  };
70335
70403
  }
70336
70404
  function libsecretStore(platform2, run, installed) {
70337
- const lookup = async (name) => {
70405
+ const lookup2 = async (name) => {
70338
70406
  const result = await run(SECRET_TOOL_BINARY, [
70339
70407
  "lookup",
70340
70408
  "service",
@@ -70353,9 +70421,9 @@ function libsecretStore(platform2, run, installed) {
70353
70421
  available: installed(SECRET_TOOL_BINARY),
70354
70422
  platform: platform2,
70355
70423
  description: "the libsecret keyring",
70356
- get: lookup,
70424
+ get: lookup2,
70357
70425
  async has(name) {
70358
- return await lookup(name) !== void 0;
70426
+ return await lookup2(name) !== void 0;
70359
70427
  },
70360
70428
  async set(name, passphrase) {
70361
70429
  requirePassphrase(passphrase);
@@ -70377,7 +70445,7 @@ function libsecretStore(platform2, run, installed) {
70377
70445
  requireSuccess(result, `store the passphrase of ${name} in the secret service`);
70378
70446
  },
70379
70447
  async remove(name) {
70380
- const existed = await lookup(name) !== void 0;
70448
+ const existed = await lookup2(name) !== void 0;
70381
70449
  const result = await run(SECRET_TOOL_BINARY, [
70382
70450
  "clear",
70383
70451
  "service",
@@ -71440,6 +71508,8 @@ var VAULT_KEY_ACCOUNT = "vault-key";
71440
71508
  var VAULT_SESSION_ACCOUNT = "vault-session";
71441
71509
  var DEVICE_KEY_LENGTH = 32;
71442
71510
  var DEFAULT_SESSION_HOURS = 8;
71511
+ var RESTORE_GAP_LIMIT = 5;
71512
+ var MAX_RESTORE_ACCOUNTS = 1e4;
71443
71513
  var BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
71444
71514
  var deviceKeyOperations = Promise.resolve();
71445
71515
  var sessionSchema = external_exports.object({
@@ -71589,26 +71659,41 @@ async function restoreVault(args) {
71589
71659
  throw new VaultError("corrupt", "That recovery phrase is not valid.", { cause: error61 });
71590
71660
  }
71591
71661
  let seed;
71592
- 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;
71593
71670
  try {
71594
71671
  seed = phraseToSeed(phrase);
71595
71672
  } catch (error61) {
71596
71673
  throw asVaultError2(error61, "Unable to derive an account while restoring the vault.");
71597
71674
  }
71598
71675
  try {
71599
- for (let index2 = 0; ; index2 += 1) {
71676
+ for (let index2 = 0, emptyRun = 0; args.accountCount === void 0; index2 += 1) {
71600
71677
  let address4;
71601
71678
  try {
71602
71679
  address4 = privateKeyToAccount(deriveEvmPrivateKey(seed, `m/44'/60'/0'/0/${index2}`)).address;
71603
71680
  } catch (error61) {
71604
71681
  throw asVaultError2(error61, "Unable to derive an account while restoring the vault.");
71605
71682
  }
71606
- if (!await args.probe(address4)) break;
71607
- 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
+ }
71608
71692
  }
71609
71693
  } finally {
71610
71694
  seed.fill(0);
71611
71695
  }
71696
+ args.onScanComplete?.(scannedAddresses);
71612
71697
  let vault;
71613
71698
  try {
71614
71699
  vault = await createVault({ path: args.path, key: args.key, phrase, now: args.now });
@@ -72097,6 +72182,26 @@ var WalletStore = class _WalletStore {
72097
72182
  }
72098
72183
  );
72099
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
+ }
72100
72205
  /** Returns one wallet's vault signer, migrating its legacy keystore if needed. */
72101
72206
  async unlock(name, passphrase) {
72102
72207
  const wallet = this.resolve({ name });
@@ -77483,7 +77588,7 @@ function createRunBudget(args) {
77483
77588
  import { mkdir as mkdir15, writeFile as writeFile8 } from "node:fs/promises";
77484
77589
  import { arch, platform, release } from "node:os";
77485
77590
  import { join as join13 } from "node:path";
77486
- var VAPI_CLIENT_VERSION = "0.9.0";
77591
+ var VAPI_CLIENT_VERSION = "0.9.4";
77487
77592
  async function createSupportReport(options) {
77488
77593
  const message = options.message.trim();
77489
77594
  if (!message) throw new Error("Support report message must not be empty.");
@@ -77756,7 +77861,7 @@ async function completeX402Payment(args) {
77756
77861
  let paidAttempt;
77757
77862
  const requestStarted = nowMs();
77758
77863
  try {
77759
- paidAttempt = await args.send(paidRequest);
77864
+ paidAttempt = await args.send(paidRequest, quote);
77760
77865
  } catch (error61) {
77761
77866
  if (trace) trace.phases.requestMs = elapsed(nowMs, requestStarted);
77762
77867
  throw settlementUnknown(
@@ -77774,7 +77879,7 @@ async function completeX402Payment(args) {
77774
77879
  const settleStarted = nowMs();
77775
77880
  const settlement = parseSettlementResponse(paidResponse.headers);
77776
77881
  const settlementOutcome = classifySettlement(settlement);
77777
- const receiptSettlement = sanitizeReceiptValue(settlement, receiptSecrets);
77882
+ const receiptSettlement = sanitizeReturnedValue(settlement, receiptSecrets);
77778
77883
  if (trace) {
77779
77884
  const transaction2 = settlementTransaction(receiptSettlement);
77780
77885
  const explorerUrl = transaction2 ? explorerTransactionUrl(quote.accepted.network, transaction2) : void 0;
@@ -77851,6 +77956,7 @@ async function completeX402Payment(args) {
77851
77956
  trace.phases.requestMs = (trace.phases.requestMs ?? 0) + elapsed(nowMs, bodyStarted);
77852
77957
  }
77853
77958
  }
77959
+ body = sanitizeReturnedValue(body, receiptSecrets);
77854
77960
  }
77855
77961
  const result = {
77856
77962
  response: paidResponse,
@@ -77859,7 +77965,11 @@ async function completeX402Payment(args) {
77859
77965
  quote,
77860
77966
  payer,
77861
77967
  ...payment.paymentId ? { paymentId: payment.paymentId } : {},
77862
- settlement,
77968
+ paymentProof: sanitizeReturnedValue(
77969
+ paidResponse.headers.get("x-vapi-payment-proof"),
77970
+ receiptSecrets
77971
+ ),
77972
+ settlement: receiptSettlement,
77863
77973
  settlementOutcome
77864
77974
  };
77865
77975
  if (settlementOutcome === "succeeded" && args.ceilingSweep) {
@@ -77996,19 +78106,70 @@ function sanitizeThrownError(error61, secrets) {
77996
78106
  }
77997
78107
  return new Error(message, cause === void 0 ? void 0 : { cause });
77998
78108
  }
77999
- function sanitizeReceiptValue(value, secrets, depth = 0) {
78109
+ function sanitizeReturnedValue(value, secrets) {
78000
78110
  if (typeof value === "string") return redactKnownSecrets(value, secrets);
78001
- if (value === null || typeof value !== "object") return value;
78002
- if (depth >= 16) return "[redacted nested settlement value]";
78003
- if (Array.isArray(value)) {
78004
- 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
+ }
78005
78141
  }
78006
- return Object.fromEntries(
78007
- Object.entries(value).map(([key2, item]) => [
78008
- redactKnownSecrets(key2, secrets),
78009
- sanitizeReceiptValue(item, secrets, depth + 1)
78010
- ])
78011
- );
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;
78012
78173
  }
78013
78174
  function redactKnownSecrets(value, secrets) {
78014
78175
  let redacted = value;
@@ -78043,9 +78204,7 @@ function possibleSettlement(quote, payment, payer, receipt) {
78043
78204
  payTo: quote.accepted.payTo,
78044
78205
  payer,
78045
78206
  ...payment.paymentId ? { paymentId: payment.paymentId } : {},
78046
- ...isSvmPaymentRequirements(quote.accepted) ? {
78047
- authorizationTransaction: "transaction" in payment.payload.payload ? payment.payload.payload.transaction : ""
78048
- } : "authorization" in payment.payload.payload ? {
78207
+ ...isSvmPaymentRequirements(quote.accepted) ? {} : "authorization" in payment.payload.payload ? {
78049
78208
  authorizationNonce: payment.payload.payload.authorization.nonce,
78050
78209
  authorizationExpiresAt: payment.payload.payload.authorization.validBefore
78051
78210
  } : {},
@@ -78423,13 +78582,22 @@ async function sendRouterChat(deps, routerBaseUrl, routerKey, request, keyUsed)
78423
78582
  }
78424
78583
  const body = await responseText(response);
78425
78584
  if (!response.ok) {
78426
- if (response.status === 429 || body.includes("Budget has been exceeded") || body.includes("ExceededBudget")) {
78585
+ if (/budget (?:has been )?exceeded|exceededbudget/iu.test(body)) {
78427
78586
  throw new RouterClientError(
78428
78587
  "budget_exhausted",
78429
78588
  "The Router key has no remaining budget.",
78430
78589
  response.status
78431
78590
  );
78432
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
+ }
78433
78601
  if (response.status === 401) {
78434
78602
  throw new RouterClientError(
78435
78603
  "no_router_key",
@@ -78996,6 +79164,7 @@ var missingTasksChain = {
78996
79164
 
78997
79165
  // ../core/src/tasks/types.ts
78998
79166
  var uuidSchema = external_exports.uuid();
79167
+ var profileIdSchema = external_exports.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
78999
79168
  var isoDateTimeSchema = external_exports.iso.datetime();
79000
79169
  var addressSchema5 = external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/).transform((value) => value.toLowerCase());
79001
79170
  var bytes32Schema = external_exports.string().regex(/^0x[0-9a-fA-F]{64}$/).transform((value) => value.toLowerCase());
@@ -79333,7 +79502,7 @@ var deliveryResponseSchema = external_exports.looseObject({
79333
79502
  version: external_exports.number().int().positive(),
79334
79503
  manifest: manifestResponseSchema,
79335
79504
  manifestHash: bytes32Schema,
79336
- submittedByProfileId: uuidSchema,
79505
+ submittedByProfileId: profileIdSchema,
79337
79506
  createdAt: isoDateTimeSchema
79338
79507
  });
79339
79508
  var orderDeliveryResponseSchema = external_exports.looseObject({
@@ -79439,7 +79608,7 @@ var reviewResponseSchema = external_exports.looseObject({
79439
79608
  id: uuidSchema,
79440
79609
  workOrderId: uuidSchema,
79441
79610
  clientAddress: addressSchema5,
79442
- vendorProfileId: uuidSchema,
79611
+ vendorProfileId: profileIdSchema,
79443
79612
  rating: external_exports.number().int().min(1).max(5),
79444
79613
  body: external_exports.string(),
79445
79614
  subRatings: external_exports.json().nullable(),
@@ -79982,12 +80151,15 @@ function createTasksClient(options) {
79982
80151
  const parsed2 = serverErrorSchema.safeParse(errorBody);
79983
80152
  const server = parsed2.success ? parsed2.data : void 0;
79984
80153
  const nested = typeof server?.error === "object" ? server.error : void 0;
79985
- const message = (typeof server?.error === "string" ? server.error : nested?.message) || server?.message || response.statusText || `HTTP ${response.status}`;
80154
+ const serverCode = nested?.code ?? server?.code;
80155
+ const serverMessage = (typeof server?.error === "string" ? server.error : nested?.message) || server?.message;
80156
+ const fallback = response.statusText || `HTTP ${response.status}`;
80157
+ const message = response.status === 401 || response.status === 403 ? serverCode ?? fallback : serverMessage || (errorBody === void 0 && raw.trim() ? raw.replace(/\s+/gu, " ").trim().slice(0, 300) : fallback);
79986
80158
  throw new TasksClientError(
79987
80159
  "http",
79988
80160
  message,
79989
80161
  response.status,
79990
- nested?.code ?? server?.code,
80162
+ serverCode,
79991
80163
  response.headers.get("Retry-After") ?? void 0
79992
80164
  );
79993
80165
  }
@@ -80390,9 +80562,10 @@ function safeTasksChainError(cause, broadcast, authorizationExposed, txHash) {
80390
80562
  let message = "Task chain operation failed.";
80391
80563
  if (cause instanceof TasksValidationError || cause instanceof TasksChainError)
80392
80564
  message = cause.message;
80393
- else if (cause instanceof TasksClientError)
80394
- message = `Tasks service request failed${cause.status === void 0 ? "" : ` (status ${cause.status})`}.`;
80395
- else if (cause instanceof Error) {
80565
+ else if (cause instanceof TasksClientError) {
80566
+ const code = cause.serverCode ?? (cause.status ? `http_${cause.status}` : cause.code);
80567
+ message = cause.status === 401 || cause.status === 403 ? `${code} (status ${cause.status})` : `${code}: ${cause.message}`;
80568
+ } else if (cause instanceof Error) {
80396
80569
  const short = "shortMessage" in cause && typeof cause.shortMessage === "string" ? cause.shortMessage : void 0;
80397
80570
  let statusCode;
80398
80571
  const seen = /* @__PURE__ */ new Set();
@@ -81200,6 +81373,44 @@ function createTasksChain(options) {
81200
81373
  return idempotencyKey;
81201
81374
  });
81202
81375
  }
81376
+ async function prepareOrResume(prepare, expected, idempotencyKey, kind, steps, authorizationExposed = false, beforeSign) {
81377
+ let prepared;
81378
+ let resumedFromServer = false;
81379
+ try {
81380
+ prepared = await prepare();
81381
+ } catch (error61) {
81382
+ if (!uncertainPreparation(error61)) throw error61;
81383
+ const fresh = await order(expected.milestone.workOrderId);
81384
+ const matches = fresh.milestones.filter((item) => item.id === expected.milestone.id);
81385
+ if (matches.length !== 1 || matches[0].workOrderId !== fresh.id)
81386
+ throw new TasksValidationError("The task milestone does not match its parent order.");
81387
+ const selected = matches[0];
81388
+ const operation = selected.chainOperation;
81389
+ if (expected.verb === "deliver" && selected.delivery && !operation)
81390
+ throw new TasksValidationError(
81391
+ "The server recorded this delivery but has no chain operation for it; open the task in the console to continue."
81392
+ );
81393
+ if (!operation || operation.kind !== kind || !(typeof steps === "string" ? [steps] : steps).includes(operation.step) || !["prepared", "submitted", "confirmed"].includes(operation.state))
81394
+ throw error61;
81395
+ if (expected.verb === "deliver" && selected.delivery && selected.delivery.manifestHash !== expected.manifestHash)
81396
+ throw new TasksValidationError(
81397
+ "The server recorded a different delivery manifest; refusing to continue."
81398
+ );
81399
+ prepared = {
81400
+ operation,
81401
+ milestone: { id: selected.id, workOrderId: selected.workOrderId }
81402
+ };
81403
+ resumedFromServer = true;
81404
+ }
81405
+ const result = await execute(
81406
+ prepared,
81407
+ expected,
81408
+ idempotencyKey,
81409
+ authorizationExposed,
81410
+ beforeSign
81411
+ );
81412
+ return resumedFromServer ? { ...result, resumedFromServer: true } : result;
81413
+ }
81203
81414
  async function verifyReceipt(operation, expected, hash5) {
81204
81415
  const rpc = rpcFor(expected.deployment.chainId);
81205
81416
  const receipt = await rpc.waitForTransactionReceipt({ hash: hash5, confirmations });
@@ -81241,6 +81452,7 @@ function createTasksChain(options) {
81241
81452
  throw new TasksValidationError(
81242
81453
  "The RPC transaction input does not match the verified task plan."
81243
81454
  );
81455
+ return receipt.blockNumber.toString();
81244
81456
  }
81245
81457
  async function retryConflict(call2) {
81246
81458
  let waited = 0;
@@ -81268,6 +81480,7 @@ function createTasksChain(options) {
81268
81480
  current = { ...initial, operation: live };
81269
81481
  let broadcast = current.operation.state === "submitted";
81270
81482
  let txHash = current.operation.transactionHash ?? void 0;
81483
+ let blockNumber;
81271
81484
  const operationId = initial.operation.id;
81272
81485
  function checkTransition(previous, next) {
81273
81486
  if (previous !== next && !(previous === "approve-usdc" && next === afterApproval))
@@ -81303,7 +81516,7 @@ function createTasksChain(options) {
81303
81516
  if (!operation.transactionHash)
81304
81517
  throw new TasksValidationError("The confirmed task operation has no transaction hash.");
81305
81518
  if (!checkpoint) {
81306
- await verifyReceipt(operation, expected, operation.transactionHash);
81519
+ blockNumber = await verifyReceipt(operation, expected, operation.transactionHash);
81307
81520
  await pending.complete(operation.id, operation.step, current);
81308
81521
  }
81309
81522
  const fresh = await order(expected.milestone.workOrderId);
@@ -81312,7 +81525,12 @@ function createTasksChain(options) {
81312
81525
  );
81313
81526
  if (!resultMilestone)
81314
81527
  throw new TasksValidationError("The reconciled task milestone is unavailable.");
81315
- return { txHash: operation.transactionHash, operation, milestone: resultMilestone };
81528
+ return {
81529
+ txHash: operation.transactionHash,
81530
+ operation,
81531
+ milestone: resultMilestone,
81532
+ blockNumber
81533
+ };
81316
81534
  }
81317
81535
  const rpc = rpcFor(expected.deployment.chainId);
81318
81536
  if (operation.state === "prepared") {
@@ -81508,7 +81726,7 @@ function createTasksChain(options) {
81508
81726
  }
81509
81727
  if (operation.state !== "submitted" || !operation.transactionHash)
81510
81728
  throw new TasksValidationError("The task operation has no submitted transaction.");
81511
- await verifyReceipt(operation, expected, operation.transactionHash);
81729
+ blockNumber = await verifyReceipt(operation, expected, operation.transactionHash);
81512
81730
  const reconciled = await retryConflict(
81513
81731
  () => client.reconcileOperation(
81514
81732
  operation.id,
@@ -81531,6 +81749,7 @@ function createTasksChain(options) {
81531
81749
  if (reconciled.operation.state !== "confirmed" && !(operation.step === "approve-usdc" && reconciled.operation.state === "prepared" && reconciled.operation.step === afterApproval))
81532
81750
  throw new TasksValidationError("The task transaction was not reconciled.");
81533
81751
  await pending.complete(operation.id, operation.step, reconciled);
81752
+ if (reconciled.operation.step !== operation.step) blockNumber = void 0;
81534
81753
  current = reconciled;
81535
81754
  }
81536
81755
  throw new TasksValidationError("The task operation exceeded its allowed step transitions.");
@@ -81565,14 +81784,16 @@ function createTasksChain(options) {
81565
81784
  );
81566
81785
  const prepareKey = await preparation(input2, verb, { evidenceHash: input2.evidenceHash });
81567
81786
  const call2 = verb === "dispute" ? client.disputeEscrow.bind(client) : client.counterEvidenceEscrow.bind(client);
81568
- return await execute(
81569
- await call2(
81787
+ return await prepareOrResume(
81788
+ () => call2(
81570
81789
  input2.escrowId,
81571
81790
  { evidenceHash: input2.evidenceHash },
81572
81791
  { idempotencyKey: prepareKey }
81573
81792
  ),
81574
81793
  { ...expected, evidenceHash: input2.evidenceHash },
81575
81794
  prepareKey,
81795
+ verb === "dispute" ? "escrow-dispute" : "escrow-counter-evidence",
81796
+ expected.steps,
81576
81797
  exposed,
81577
81798
  input2.beforeSign
81578
81799
  );
@@ -81592,11 +81813,34 @@ function createTasksChain(options) {
81592
81813
  await options.bindings.put(binding);
81593
81814
  },
81594
81815
  createEscrow: (input2) => safe(async () => {
81595
- const workOrder = await order(input2.orderId);
81816
+ let workOrder = await order(input2.orderId);
81596
81817
  const ready = await deployment();
81597
- const prepared = await client.createEscrow(input2.orderId, {
81598
- idempotencyKey: input2.idempotencyKey
81599
- });
81818
+ let prepared;
81819
+ let resumedFromServer = false;
81820
+ try {
81821
+ prepared = await client.createEscrow(input2.orderId, {
81822
+ idempotencyKey: input2.idempotencyKey
81823
+ });
81824
+ } catch (error61) {
81825
+ if (!uncertainPreparation(error61)) throw error61;
81826
+ const fresh = await order(input2.orderId);
81827
+ const candidates = fresh.milestones.filter((item) => {
81828
+ const previous = workOrder.milestones.find((prior) => prior.id === item.id);
81829
+ const operation = item.chainOperation;
81830
+ return item.workOrderId === input2.orderId && previous && operation && operation.kind === "escrow-create" && operation.step === "create-escrow" && (previous.escrowState === null || previous.chainOperation?.id === operation.id);
81831
+ });
81832
+ if (candidates.length !== 1) throw error61;
81833
+ const selected2 = candidates[0];
81834
+ prepared = {
81835
+ operation: selected2.chainOperation,
81836
+ milestone: {
81837
+ id: selected2.id,
81838
+ workOrderId: selected2.workOrderId
81839
+ }
81840
+ };
81841
+ workOrder = fresh;
81842
+ resumedFromServer = true;
81843
+ }
81600
81844
  const selected = workOrder.milestones.find((item) => item.id === prepared.milestone.id);
81601
81845
  if (!selected || selected.workOrderId !== input2.orderId)
81602
81846
  throw new TasksValidationError(
@@ -81606,11 +81850,12 @@ function createTasksChain(options) {
81606
81850
  { escrowId: selected.id, idempotencyKey: input2.idempotencyKey },
81607
81851
  "createEscrow"
81608
81852
  );
81609
- return await execute(
81853
+ const result = await execute(
81610
81854
  prepared,
81611
81855
  await expectation(selected, ready, "createEscrow", ["create-escrow"], input2.counterparty),
81612
81856
  prepareKey
81613
81857
  );
81858
+ return resumedFromServer ? { ...result, resumedFromServer: true } : result;
81614
81859
  }),
81615
81860
  async fund(input2) {
81616
81861
  let exposed = true;
@@ -81698,10 +81943,14 @@ function createTasksChain(options) {
81698
81943
  }
81699
81944
  exposed = true;
81700
81945
  await pending.markExposure(selected.id);
81701
- const prepared = await client.fundEscrow(input2.escrowId, body, {
81702
- idempotencyKey: prepareKey
81703
- });
81704
- return await execute(prepared, expected, prepareKey, exposed);
81946
+ return await prepareOrResume(
81947
+ () => client.fundEscrow(input2.escrowId, body, { idempotencyKey: prepareKey }),
81948
+ expected,
81949
+ prepareKey,
81950
+ "escrow-funding",
81951
+ expected.steps,
81952
+ exposed
81953
+ );
81705
81954
  } catch (cause) {
81706
81955
  throw chainError(cause, false, exposed);
81707
81956
  }
@@ -81726,22 +81975,26 @@ function createTasksChain(options) {
81726
81975
  manifest: frozen.manifest,
81727
81976
  note: input2.note
81728
81977
  });
81729
- const prepared = await client.deliverEscrow(
81730
- input2.escrowId,
81731
- { fileIds: frozen.manifest.files.map((file2) => file2.fileId), note: input2.note },
81732
- { idempotencyKey: prepareKey }
81733
- );
81734
- if (prepared.delivery.manifestHash !== frozen.manifestHash)
81735
- throw new TasksValidationError(
81736
- "The server task delivery manifest hash does not match the local manifest."
81737
- );
81738
- return await execute(
81739
- prepared,
81978
+ return await prepareOrResume(
81979
+ async () => {
81980
+ const prepared = await client.deliverEscrow(
81981
+ input2.escrowId,
81982
+ { fileIds: frozen.manifest.files.map((file2) => file2.fileId), note: input2.note },
81983
+ { idempotencyKey: prepareKey }
81984
+ );
81985
+ if (prepared.delivery.manifestHash !== frozen.manifestHash)
81986
+ throw new TasksValidationError(
81987
+ "The server task delivery manifest hash does not match the local manifest."
81988
+ );
81989
+ return prepared;
81990
+ },
81740
81991
  {
81741
81992
  ...expected,
81742
81993
  manifestHash: frozen.manifestHash
81743
81994
  },
81744
- prepareKey
81995
+ prepareKey,
81996
+ "escrow-delivery",
81997
+ "submit-delivery"
81745
81998
  );
81746
81999
  }),
81747
82000
  release: (input2) => safe(async () => {
@@ -81755,10 +82008,12 @@ function createTasksChain(options) {
81755
82008
  input2.counterparty
81756
82009
  );
81757
82010
  const prepareKey = await preparation(input2, "release");
81758
- return await execute(
81759
- await client.releaseEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
82011
+ return await prepareOrResume(
82012
+ () => client.releaseEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
81760
82013
  expected,
81761
- prepareKey
82014
+ prepareKey,
82015
+ "escrow-release",
82016
+ "release-funds"
81762
82017
  );
81763
82018
  }),
81764
82019
  refund: (input2) => safe(async () => {
@@ -81772,10 +82027,12 @@ function createTasksChain(options) {
81772
82027
  input2.counterparty
81773
82028
  );
81774
82029
  const prepareKey = await preparation(input2, "refund");
81775
- return await execute(
81776
- await client.refundEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
82030
+ return await prepareOrResume(
82031
+ () => client.refundEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
81777
82032
  expected,
81778
- prepareKey
82033
+ prepareKey,
82034
+ "escrow-release",
82035
+ "refund-buyer"
81779
82036
  );
81780
82037
  }),
81781
82038
  disputeFee: (input2) => safe(async () => {
@@ -81803,16 +82060,21 @@ function createTasksChain(options) {
81803
82060
  input2.counterparty
81804
82061
  );
81805
82062
  const prepareKey = await preparation(input2, "resolve-unmatched");
81806
- return execute(
81807
- await client.resolveUnmatchedEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
82063
+ return prepareOrResume(
82064
+ () => client.resolveUnmatchedEscrow(input2.escrowId, { idempotencyKey: prepareKey }),
81808
82065
  expected,
81809
- prepareKey
82066
+ prepareKey,
82067
+ "escrow-unmatched-resolution",
82068
+ "resolve-unmatched-dispute"
81810
82069
  );
81811
82070
  }),
81812
82071
  signScopeMessage: (message) => safe(() => account.signMessage({ message }))
81813
82072
  };
81814
82073
  }
81815
82074
  var chainError = safeTasksChainError;
82075
+ function uncertainPreparation(error61) {
82076
+ return error61 instanceof TasksClientError && ((error61.status ?? 0) >= 400 || error61.code === "network" || error61.code === "timeout");
82077
+ }
81816
82078
  function retryDelay(header, now) {
81817
82079
  if (/^\d+(?:\.\d+)?$/u.test(header.trim())) return Math.max(1, Math.ceil(Number(header) * 1e3));
81818
82080
  const date5 = Date.parse(header);
@@ -81829,6 +82091,60 @@ function alreadySent(error61) {
81829
82091
  return error61 instanceof Error && /already known|known transaction|nonce (?:is )?too low/iu.test(error61.message);
81830
82092
  }
81831
82093
 
82094
+ // ../core/src/tasks/wait.ts
82095
+ async function waitForMilestone(client, input2) {
82096
+ const timeoutMs = input2.timeoutMs ?? 12e4;
82097
+ const intervalMs = input2.intervalMs ?? 3e3;
82098
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0)
82099
+ throw new RangeError("The milestone wait timeout must be non-negative and finite.");
82100
+ if (!Number.isFinite(intervalMs) || intervalMs <= 0)
82101
+ throw new RangeError("The milestone wait interval must be positive and finite.");
82102
+ const sleep = input2.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
82103
+ const now = input2.now ?? (() => /* @__PURE__ */ new Date());
82104
+ const started = now().getTime();
82105
+ const deadline = started + timeoutMs;
82106
+ let polls = 0;
82107
+ let milestone;
82108
+ function result(reached) {
82109
+ return { reached, milestone, polls, elapsedMs: now().getTime() - started };
82110
+ }
82111
+ for (; ; ) {
82112
+ const remaining = deadline - now().getTime();
82113
+ if (remaining <= 0) return result(false);
82114
+ const controller = new AbortController();
82115
+ const timer = setTimeout(() => controller.abort(), remaining);
82116
+ let response;
82117
+ polls++;
82118
+ try {
82119
+ response = await client.getOrder(input2.orderId, { signal: controller.signal });
82120
+ } catch (error61) {
82121
+ if (controller.signal.aborted) return result(false);
82122
+ throw error61;
82123
+ } finally {
82124
+ clearTimeout(timer);
82125
+ }
82126
+ if (controller.signal.aborted || now().getTime() >= deadline) return result(false);
82127
+ const { workOrder } = response;
82128
+ milestone = workOrder.id === input2.orderId && workOrder.version === "work-order-view-v1" ? workOrder.milestones.find(
82129
+ (item) => item.id === input2.milestoneId && item.workOrderId === input2.orderId
82130
+ ) : void 0;
82131
+ if (milestone && reachedTarget(milestone, input2.target)) return result(true);
82132
+ await sleep(Math.min(intervalMs, deadline - now().getTime()));
82133
+ }
82134
+ }
82135
+ function reachedTarget(milestone, target) {
82136
+ switch (target) {
82137
+ case "created":
82138
+ return milestone.escrowState !== null;
82139
+ case "locked":
82140
+ return ["locked", "submitted", "disputed", "resolved"].includes(milestone.escrowState ?? "");
82141
+ case "delivered":
82142
+ return ["submitted", "disputed", "resolved"].includes(milestone.escrowState ?? "");
82143
+ case "released":
82144
+ return milestone.escrowState === "resolved";
82145
+ }
82146
+ }
82147
+
81832
82148
  // ../core/src/tasks/rpc.ts
81833
82149
  function createTasksRpcFor(config2, options = {}) {
81834
82150
  const clients = /* @__PURE__ */ new Map();
@@ -82945,7 +83261,10 @@ async function taskRequest(verb, route, operation, options) {
82945
83261
  "not_signed_in",
82946
83262
  `${verb} needs sign-in. ${options.signInHint}`
82947
83263
  );
82948
- throw new TaskOperationError(error61.serverCode ?? error61.code, error61.message);
83264
+ throw new TaskOperationError(
83265
+ error61.serverCode ?? (error61.status ? `http_${error61.status}` : error61.code),
83266
+ error61.message
83267
+ );
82949
83268
  }
82950
83269
  throw error61;
82951
83270
  }
@@ -83066,7 +83385,8 @@ function proposalTerms(id2, address4, deployment, terms) {
83066
83385
  return {
83067
83386
  version: "work-proposal-v1",
83068
83387
  workOrderId: id2,
83069
- providerAddress: address4,
83388
+ // The server lowercases addresses before canonicalizing the signed payload.
83389
+ providerAddress: address4.toLowerCase(),
83070
83390
  pricingModel: "fixed",
83071
83391
  milestones: [
83072
83392
  {
@@ -83453,6 +83773,55 @@ async function showTask(context, input2) {
83453
83773
  };
83454
83774
  }
83455
83775
  async function taskStatus(context, input2) {
83776
+ if (input2.signedIn) {
83777
+ const chainState = await taskRequest(
83778
+ "status",
83779
+ "chainState",
83780
+ async () => {
83781
+ try {
83782
+ return await context.client.chainState(input2.id);
83783
+ } catch (error61) {
83784
+ if (error61 instanceof TasksClientError && error61.status === 404) {
83785
+ if (isMissingTaskEntity(error61.serverCode, error61.message))
83786
+ throw new TaskOperationError("not_found", error61.message);
83787
+ throw new TaskOperationError(
83788
+ "not_available",
83789
+ "GET /v1/work-orders/:id/chain-state is not available on this server."
83790
+ );
83791
+ }
83792
+ throw error61;
83793
+ }
83794
+ },
83795
+ context
83796
+ );
83797
+ if (chainState.workOrderId !== input2.id)
83798
+ throw new TaskOperationError("invalid_response", "The response belongs to a different task.");
83799
+ const page = await taskRequest(
83800
+ "status",
83801
+ "events",
83802
+ async () => {
83803
+ try {
83804
+ return await context.client.events(input2.id, { wait: 0 });
83805
+ } catch (error61) {
83806
+ if (error61 instanceof TasksClientError && error61.status === 404) {
83807
+ if (isMissingTaskEntity(error61.serverCode, error61.message)) return null;
83808
+ throw new TaskOperationError(
83809
+ "not_available",
83810
+ "GET /v1/work-orders/:id/events is not available on this server."
83811
+ );
83812
+ }
83813
+ throw error61;
83814
+ }
83815
+ },
83816
+ context
83817
+ );
83818
+ return {
83819
+ task: { id: input2.id },
83820
+ chainState,
83821
+ events: page ? [...page.events].sort((a, b) => a.sequence - b.sequence) : null,
83822
+ nextAfter: page?.nextAfter ?? null
83823
+ };
83824
+ }
83456
83825
  const task = await taskRequest(
83457
83826
  "status",
83458
83827
  "publicTask",
@@ -83808,6 +84177,7 @@ var searchEventSchema = external_exports.strictObject({
83808
84177
  source: external_exports.string().min(1),
83809
84178
  latencyMs: external_exports.number().nonnegative().finite(),
83810
84179
  count: external_exports.number().int().nonnegative(),
84180
+ dropped: external_exports.number().int().nonnegative().optional(),
83811
84181
  error: external_exports.string().optional()
83812
84182
  })
83813
84183
  ),
@@ -86879,7 +87249,7 @@ var memberBundleConfigSchema = external_exports.unknown().refine((value) => !has
86879
87249
  external_exports.strictObject({ usdc: external_exports.string() })
86880
87250
  ).refine(
86881
87251
  (networks) => Object.entries(networks).every(
86882
- ([id2, network]) => isMemberBundleNetwork(id2) && network.usdc === NETWORKS[id2].usdc
87252
+ ([id2, network]) => isMemberBundleNetwork(id2) && network.usdc === NETWORKS2[id2].usdc
86883
87253
  ),
86884
87254
  { message: "Expected the canonical USDC token of each network." }
86885
87255
  ).refine((networks) => Object.keys(networks).length === 1, {
@@ -86918,14 +87288,14 @@ function memberBundleConfig(owner, network) {
86918
87288
  return {
86919
87289
  discoveryUrl,
86920
87290
  marketplaceDiscoveryUrl,
86921
- networks: { [network]: { usdc: NETWORKS[network].usdc } }
87291
+ networks: { [network]: { usdc: NETWORKS2[network].usdc } }
86922
87292
  };
86923
87293
  }
86924
87294
  function headlessConfigFromBundle(config2) {
86925
87295
  const networks = {};
86926
87296
  for (const [id2, network] of Object.entries(config2.networks)) {
86927
87297
  if (!isMemberBundleNetwork(id2) || network === void 0) continue;
86928
- networks[id2] = { rpcUrl: NETWORKS[id2].publicRpcUrl, usdc: network.usdc };
87298
+ networks[id2] = { rpcUrl: NETWORKS2[id2].publicRpcUrl, usdc: network.usdc };
86929
87299
  }
86930
87300
  return configSchema.parse({
86931
87301
  discoveryUrl: config2.discoveryUrl,
@@ -87018,7 +87388,7 @@ function parseStoredTokens(value) {
87018
87388
  }
87019
87389
  }
87020
87390
  function isMemberBundleNetwork(id2) {
87021
- return Object.hasOwn(NETWORKS, id2) && typeof NETWORKS[id2].publicRpcUrl === "string";
87391
+ return Object.hasOwn(NETWORKS2, id2) && typeof NETWORKS2[id2].publicRpcUrl === "string";
87022
87392
  }
87023
87393
  function hasForbiddenConfigKey(value) {
87024
87394
  if (Array.isArray(value)) return value.some(hasForbiddenConfigKey);
@@ -87320,11 +87690,28 @@ async function searchMarketplace(input2, config2, fetchImpl, options = {}) {
87320
87690
  }
87321
87691
  }
87322
87692
  });
87323
- const page = marketplaceDiscoveryPageSchema.parse(await response.json());
87324
- mergedCount = page.items.length;
87693
+ const envelope = marketplaceDiscoveryEnvelopeSchema.parse(await response.json());
87694
+ const items = [];
87695
+ let dropped = 0;
87696
+ for (const [index2, rawItem] of envelope.items.entries()) {
87697
+ const parsed = marketplaceHitSchema.safeParse(rawItem);
87698
+ if (parsed.success) {
87699
+ items.push(parsed.data);
87700
+ continue;
87701
+ }
87702
+ dropped += 1;
87703
+ try {
87704
+ options.debug?.(`vAPI marketplace discovery dropped invalid row at index ${index2}.`);
87705
+ } catch {
87706
+ }
87707
+ }
87708
+ mergedCount = items.length;
87325
87709
  const attempt = attempts.at(-1);
87326
- if (attempt) attempt.count = mergedCount;
87327
- return page;
87710
+ if (attempt) {
87711
+ attempt.count = mergedCount;
87712
+ if (dropped > 0) attempt.dropped = dropped;
87713
+ }
87714
+ return { ...envelope, items };
87328
87715
  } finally {
87329
87716
  if (options.searchesPath) {
87330
87717
  await appendSearchEvent(
@@ -87450,6 +87837,34 @@ var VapiCallError = class extends Error {
87450
87837
  paymentRejection;
87451
87838
  confirmedSettlement;
87452
87839
  };
87840
+ var SOLANA_PAYMENTS_UNSUPPORTED_MESSAGE = "Solana payments are not supported in this version of vAPI yet; they arrive in a later release.";
87841
+ function isSolanaCaip2(network) {
87842
+ return network.startsWith("solana:");
87843
+ }
87844
+ function listingPaymentNetwork(endpointNetwork, serviceNetworks) {
87845
+ if (endpointNetwork !== void 0) return endpointNetwork;
87846
+ return serviceNetworks?.length && serviceNetworks.every(isSolanaCaip2) ? serviceNetworks[0] : void 0;
87847
+ }
87848
+ function assertSupportedListingNetwork(network) {
87849
+ if (network !== void 0 && isSolanaCaip2(network)) {
87850
+ throw new VapiCallError(
87851
+ "unsupported_network",
87852
+ `${SOLANA_PAYMENTS_UNSUPPORTED_MESSAGE} This listing pays on ${network}.`
87853
+ );
87854
+ }
87855
+ }
87856
+ function assertSupportedListingResolution(error61) {
87857
+ if (isDiscoveryCatalogError(error61) && error61.code === "ambiguous_default" && error61.paymentNetworks?.length && error61.paymentNetworks.every(isSolanaCaip2)) {
87858
+ assertSupportedListingNetwork(error61.paymentNetworks[0]);
87859
+ }
87860
+ }
87861
+ function payableConfig(config2, account) {
87862
+ if (account.solana !== void 0) return config2;
87863
+ const networks = Object.fromEntries(
87864
+ Object.entries(config2.networks).filter(([network]) => !isSolanaCaip2(network))
87865
+ );
87866
+ return { ...config2, networks };
87867
+ }
87453
87868
  var MAX_RESPONSE_BYTES = 1048576;
87454
87869
  var BODY_HEADER_NAMES = [
87455
87870
  "content-encoding",
@@ -87459,12 +87874,15 @@ var BODY_HEADER_NAMES = [
87459
87874
  "content-type"
87460
87875
  ];
87461
87876
  async function callService(args) {
87877
+ validateTimeoutSeconds(args.input.timeoutSeconds);
87462
87878
  const trace = createCallTrace(args);
87463
87879
  let execution;
87464
87880
  try {
87465
87881
  execution = await executeCallService(args, trace);
87466
87882
  } catch (error61) {
87467
- await recordCallError(args, error61, trace).catch(() => void 0);
87883
+ if (!(error61 instanceof VapiCallError && (error61.code === "unsupported_network" || error61.code === "unsupported_payment"))) {
87884
+ await recordCallError(args, error61, trace).catch(() => void 0);
87885
+ }
87468
87886
  throw error61;
87469
87887
  }
87470
87888
  try {
@@ -87512,10 +87930,16 @@ async function executeCallService(args, trace) {
87512
87930
  config2,
87513
87931
  fetchImpl
87514
87932
  );
87933
+ } catch (error61) {
87934
+ assertSupportedListingResolution(error61);
87935
+ throw error61;
87515
87936
  } finally {
87516
87937
  trace.phases.discoverMs = elapsed2(trace, discoverStarted);
87517
87938
  }
87518
87939
  }
87940
+ assertSupportedListingNetwork(
87941
+ listingPaymentNetwork(endpoint?.payment?.network, endpoint?.serviceNetworks)
87942
+ );
87519
87943
  const requestedNetwork = normalizeRequiredNetwork(input2.network);
87520
87944
  const listingNetwork = endpoint?.payment?.network;
87521
87945
  if (requestedNetwork && listingNetwork && !areSamePaymentNetwork(requestedNetwork, listingNetwork)) {
@@ -87570,6 +87994,8 @@ async function executeCallService(args, trace) {
87570
87994
  body: method === "GET" || method === "HEAD" ? void 0 : requestBody
87571
87995
  });
87572
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;
87573
87999
  const fetchWithGuardedRedirects = async (candidateRequest, followRedirects = true) => {
87574
88000
  let currentRequest = candidateRequest;
87575
88001
  let followedRedirects = 0;
@@ -87577,7 +88003,7 @@ async function executeCallService(args, trace) {
87577
88003
  const attempt = await fetchAttempt(
87578
88004
  fetchImpl,
87579
88005
  new Request(currentRequest.clone(), { redirect: "manual" }),
87580
- args.timeoutMs ?? 3e4
88006
+ requestTimeoutMs
87581
88007
  );
87582
88008
  const response = attempt.response;
87583
88009
  if (!isRedirectStatus2(response.status)) {
@@ -87731,8 +88157,13 @@ async function executeCallService(args, trace) {
87731
88157
  challenge: challengeAttempt,
87732
88158
  account,
87733
88159
  caps: args.spendCaps ?? config2.spendCaps,
87734
- config: config2,
87735
- send: async (paidRequest) => {
88160
+ config: payableConfig(config2, account),
88161
+ send: async (paidRequest, quote) => {
88162
+ requestTimeoutMs = paidRequestTimeoutMs(
88163
+ input2.timeoutSeconds,
88164
+ args.timeoutMs,
88165
+ quote.accepted.maxTimeoutSeconds
88166
+ );
87736
88167
  paidAttempt = await fetchWithGuardedRedirects(paidRequest, false);
87737
88168
  return paidAttempt;
87738
88169
  },
@@ -87771,7 +88202,7 @@ async function executeCallService(args, trace) {
87771
88202
  asset: completed.quote.accepted.asset,
87772
88203
  payTo: completed.quote.accepted.payTo,
87773
88204
  settlement: settlementWithExplorer2(completed.settlement, completed.quote.accepted.network),
87774
- proof: completed.response.headers.get("x-vapi-payment-proof")
88205
+ proof: completed.paymentProof
87775
88206
  },
87776
88207
  ...verificationFor(endpoint),
87777
88208
  ...expectedRequestFor(endpoint, completed.response.status)
@@ -87981,7 +88412,7 @@ async function resolveCallEndpoint(id2, endpointName, marketplaceHit, config2, f
87981
88412
  try {
87982
88413
  return registeredEndpoint(await resolveServiceListing(id2, config2, fetchImpl, endpointName));
87983
88414
  } catch (error61) {
87984
- if (!(error61 instanceof DiscoveryCatalogError) || error61.code !== "service_not_found") {
88415
+ if (!isDiscoveryCatalogError(error61) || error61.code !== "service_not_found") {
87985
88416
  throw error61;
87986
88417
  }
87987
88418
  const discovered = await findMarketplaceApiByRef(id2, config2, fetchImpl);
@@ -88018,9 +88449,18 @@ async function resolveCallEndpoint(id2, endpointName, marketplaceHit, config2, f
88018
88449
  );
88019
88450
  }
88020
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
+ }
88021
88459
  return {
88022
- ...listing.endpoint,
88460
+ ...endpoint,
88461
+ ...payment ? { payment: { network: payment.network, payTo: payment.payTo } } : {},
88023
88462
  verification: verification ?? listing.service.verification,
88463
+ serviceNetworks: listing.service.networks,
88024
88464
  registered: true,
88025
88465
  resolvedListing: true
88026
88466
  };
@@ -88180,7 +88620,7 @@ async function readResponseBody2(response) {
88180
88620
  async function fetchAttempt(fetchImpl, request, timeoutMs) {
88181
88621
  const controller = new AbortController();
88182
88622
  let rejectTimeout = null;
88183
- const timeoutError = new Error(`API request timed out after ${timeoutMs}ms.`);
88623
+ const timeoutError = new Error(`API request timed out after ${timeoutMs / 1e3} seconds.`);
88184
88624
  const timedOut = new Promise((_resolve, reject) => {
88185
88625
  rejectTimeout = reject;
88186
88626
  });
@@ -88220,6 +88660,19 @@ async function fetchAttempt(fetchImpl, request, timeoutMs) {
88220
88660
  throw error61;
88221
88661
  }
88222
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
+ }
88223
88676
  function mapX402PaymentError(error61, resumeId) {
88224
88677
  if (!(error61 instanceof X402PaymentError)) return error61;
88225
88678
  if (error61.code === "payment_rejected") {
@@ -88235,9 +88688,10 @@ function mapX402PaymentError(error61, resumeId) {
88235
88688
  });
88236
88689
  }
88237
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} ` : "";
88238
88692
  return new VapiCallError(
88239
88693
  "settlement_unknown",
88240
- `${error61.message}${resume}`,
88694
+ `${timeoutDetail}${error61.message}${resume}`,
88241
88695
  error61.possibleSettlement,
88242
88696
  { cause: error61.cause }
88243
88697
  );
@@ -88259,14 +88713,17 @@ async function inspectService(input2, config2, fetchImpl) {
88259
88713
  try {
88260
88714
  listing = await resolveServiceListing(input2.id, config2, fetchImpl, input2.endpoint);
88261
88715
  } catch (error61) {
88262
- if (input2.endpoint || !(error61 instanceof DiscoveryCatalogError) || error61.code !== "service_not_found") {
88716
+ assertSupportedListingResolution(error61);
88717
+ if (input2.endpoint || !isDiscoveryCatalogError(error61) || error61.code !== "service_not_found") {
88263
88718
  throw error61;
88264
88719
  }
88265
88720
  const hit = await findMarketplaceApiByRef(input2.id, config2, fetchImpl);
88266
88721
  if (!hit || hit.kind !== "api" || hit.provenance !== "indexed") throw error61;
88722
+ assertSupportedListingNetwork(hit.execution.network);
88267
88723
  return inspectIndexedHit(hit);
88268
88724
  }
88269
88725
  const { endpoint, service } = listing;
88726
+ assertSupportedListingNetwork(listingPaymentNetwork(endpoint.payment?.network, service.networks));
88270
88727
  return {
88271
88728
  name: endpoint.name,
88272
88729
  method: endpoint.method,
@@ -88366,13 +88823,7 @@ var inspectToolResultSchema = external_exports.object({
88366
88823
  liveness: listingLivenessSchema.optional(),
88367
88824
  conformance: listingConformanceSchema.optional(),
88368
88825
  identity: listingIdentitySchema.optional(),
88369
- payment: external_exports.object({
88370
- scheme: external_exports.literal("exact"),
88371
- network: external_exports.string(),
88372
- asset: external_exports.string(),
88373
- payTo: external_exports.string(),
88374
- checkedAt: external_exports.string()
88375
- }).nullable()
88826
+ payment: discoveryEndpointSchema.shape.payment.unwrap().nullable()
88376
88827
  });
88377
88828
  var callSearchInputSchema = external_exports.object({
88378
88829
  query: external_exports.string().trim().max(200).optional().describe("Capability, API, service, or request."),
@@ -88401,7 +88852,10 @@ var callPayInputSchema = external_exports.object({
88401
88852
  (value) => /^0x[0-9a-fA-F]{40}$/.test(value) || isSolanaAddress(value),
88402
88853
  "Expected an EVM or Solana address."
88403
88854
  ).optional(),
88404
- 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
+ )
88405
88859
  });
88406
88860
  var callSearch = defineAction({
88407
88861
  name: "call.search",
@@ -88664,7 +89118,7 @@ async function readResult(response, signal, secrets = []) {
88664
89118
  return {
88665
89119
  status: response.status,
88666
89120
  contentType: contentType === null ? null : redactKnownSecrets2(contentType, secrets),
88667
- body: sanitizeReturnedValue(await readResponseBody3(response, contentType, signal), secrets)
89121
+ body: sanitizeReturnedValue2(await readResponseBody3(response, contentType, signal), secrets)
88668
89122
  };
88669
89123
  }
88670
89124
  async function readResponseBody3(response, contentType, signal) {
@@ -88709,17 +89163,17 @@ function isJsonContentType2(value) {
88709
89163
  const mediaType = value?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
88710
89164
  return mediaType === "application/json" || mediaType.endsWith("+json");
88711
89165
  }
88712
- function sanitizeReturnedValue(value, secrets, depth = 0) {
89166
+ function sanitizeReturnedValue2(value, secrets, depth = 0) {
88713
89167
  if (typeof value === "string") return redactKnownSecrets2(value, secrets);
88714
89168
  if (value === null || typeof value !== "object") return value;
88715
89169
  if (depth >= 16) return "[redacted nested response value]";
88716
89170
  if (Array.isArray(value)) {
88717
- return value.map((item) => sanitizeReturnedValue(item, secrets, depth + 1));
89171
+ return value.map((item) => sanitizeReturnedValue2(item, secrets, depth + 1));
88718
89172
  }
88719
89173
  return Object.fromEntries(
88720
89174
  Object.entries(value).map(([key2, item]) => [
88721
89175
  redactKnownSecrets2(key2, secrets),
88722
- sanitizeReturnedValue(item, secrets, depth + 1)
89176
+ sanitizeReturnedValue2(item, secrets, depth + 1)
88723
89177
  ])
88724
89178
  );
88725
89179
  }
@@ -92036,6 +92490,7 @@ var moneyParticipant = {
92036
92490
  "Checksummed 0x address of the other party, taken from tasks.show (the poster's clientAddress when you are the worker; the accepted proposal's providerAddress when you are the poster). The human must supply it; it is compared with the signed scope and stored as local consent. Without it tasks.sign refuses and no local party binding is created, so tasks.fund/deliver/release cannot run from this machine."
92037
92491
  ).optional()
92038
92492
  };
92493
+ var waitForIndexer = external_exports.boolean().default(true).describe("Wait up to 60 seconds for vAPI to index the chain result before returning.");
92039
92494
  var cursor = external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
92040
92495
  function usdWithinEscrow(value, positive = false) {
92041
92496
  try {
@@ -92082,7 +92537,10 @@ var tasksPostTool = descriptor(
92082
92537
  deadline: external_exports.string(),
92083
92538
  intake: external_exports.enum(["proposals", "submissions"]).optional(),
92084
92539
  maxAwards: external_exports.number().int().min(TASK_LIMITS.maxAwardsMin).max(TASK_LIMITS.maxAwardsMax).optional(),
92085
- webhookUrl: httpsUrl.optional()
92540
+ webhookUrl: httpsUrl.optional(),
92541
+ vendor: external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/u).describe(
92542
+ "Optional 0x address of a vendor to invite directly; the task is addressed to that wallet and shows up for them. Anyone may still propose."
92543
+ ).optional()
92086
92544
  }
92087
92545
  );
92088
92546
  var tasksProposeTool = descriptor(
@@ -92107,42 +92565,43 @@ var tasksAwardTool = descriptor(
92107
92565
  { ...participant, proposalId: id }
92108
92566
  );
92109
92567
  var tasksSignTool = descriptor(
92110
- "Does not move money. Sign the current counterparty scope locally after the human confirms the money direction via counterparty; a worker may also create the unfunded escrow with the local vault wallet.",
92111
- moneyParticipant
92568
+ "Signs the user's own task scope locally with the user's vault wallet after the human confirms the money direction via counterparty; a worker may also create the unfunded escrow; nothing is custodial. Does not move money. Waits up to 60 seconds for vAPI to index a created escrow by default.",
92569
+ { ...moneyParticipant, wait: waitForIndexer }
92112
92570
  );
92113
92571
  var tasksFundTool = descriptor(
92114
- "Moves money: locks the task amount in USDC escrow subject to the acting wallet's policy and daily cap. MCP cannot grant human approval; amounts above the approval threshold are refused with approval:true.",
92115
- moneyParticipant
92572
+ "Executes the user's own funding of this task from the user's vault wallet, within the spend policy the user configured; nothing is custodial. MCP cannot grant human approval; amounts above the approval threshold are refused with approval:true. Waits up to 60 seconds for vAPI to index the locked escrow by default.",
92573
+ { ...moneyParticipant, wait: waitForIndexer }
92116
92574
  );
92117
92575
  var tasksDeliverTool = descriptor(
92118
- "Does not move money. Upload local delivery files, freeze the manifest and record delivery with the local vault wallet.",
92576
+ "Does not move money. Upload local delivery files, freeze the manifest and record delivery with the local vault wallet. Waits up to 60 seconds for vAPI to index the delivery by default.",
92119
92577
  {
92120
92578
  ...moneyParticipant,
92579
+ wait: waitForIndexer,
92121
92580
  files: external_exports.array(localPath).min(TASK_LIMITS.deliveryFilesMin).max(TASK_LIMITS.deliveryFilesMax),
92122
92581
  note: external_exports.string().max(TASK_LIMITS.deliveryNoteMax).refine((value) => value.trim().length > 0)
92123
92582
  }
92124
92583
  );
92125
92584
  var tasksReleaseTool = descriptor(
92126
- "Moves money: pays the worker from escrow with the local vault wallet. Returns gross \xB7 fee \xB7 net using the deployed fee.",
92127
- moneyParticipant
92585
+ "Executes the user's own payment to the worker from task escrow with the user's vault wallet; nothing is custodial. Returns gross \xB7 fee \xB7 net using the deployed fee. Waits up to 60 seconds for vAPI to index the release by default.",
92586
+ { ...moneyParticipant, wait: waitForIndexer }
92128
92587
  );
92129
92588
  var tasksRefundTool = descriptor(
92130
- "Moves money: returns escrowed USDC to the poster with the local vault wallet. Returns gross \xB7 fee \xB7 net using the deployed fee.",
92589
+ "Executes the user's own refund of escrowed USDC to the poster with the user's vault wallet; nothing is custodial. Returns gross \xB7 fee \xB7 net using the deployed fee.",
92131
92590
  moneyParticipant
92132
92591
  );
92133
92592
  var tasksDisputeTool = descriptor(
92134
- "Moves money: approves the verified dispute fee and raises a dispute with the local vault wallet. Applies task and daily caps; MCP refuses human approval with approval:true. Accepts a precomputed evidence hash.",
92593
+ "Executes the user's own approval of the verified dispute fee and raises a dispute with the user's vault wallet; nothing is custodial. Applies task and daily caps; MCP refuses human approval with approval:true. Accepts a precomputed evidence hash.",
92135
92594
  {
92136
92595
  ...moneyParticipant,
92137
92596
  evidenceHash: external_exports.string().regex(TASK_LIMITS.disputeEvidenceHash)
92138
92597
  }
92139
92598
  );
92140
92599
  var tasksCounterEvidenceTool = descriptor(
92141
- "Moves money: approves the verified dispute fee and submits counter-evidence as the non-opener before the onchain deadline. Applies task and daily caps; MCP refuses human approval with approval:true.",
92600
+ "Executes the user's own counter-evidence submission and approval of the verified dispute fee with the user's vault wallet as the non-opener before the onchain deadline; nothing is custodial. Applies task and daily caps; MCP refuses human approval with approval:true.",
92142
92601
  { ...moneyParticipant, evidenceHash: external_exports.string().regex(TASK_LIMITS.disputeEvidenceHash) }
92143
92602
  );
92144
92603
  var tasksResolveUnmatchedTool = descriptor(
92145
- "Moves money: resolves an unmatched dispute after the onchain counter-evidence deadline when no counter-evidence was submitted.",
92604
+ "Executes the user's own resolution of an unmatched dispute with the user's vault wallet after the onchain counter-evidence deadline when no counter-evidence was submitted; nothing is custodial.",
92146
92605
  moneyParticipant
92147
92606
  );
92148
92607
  var tasksMessageTool = descriptor(
@@ -92166,8 +92625,8 @@ var tasksWatchTool = descriptor(
92166
92625
  }
92167
92626
  );
92168
92627
  var tasksStatusTool = descriptor(
92169
- "Does not move money. Read the public task card and receipt URL when settled; sign-in is not required.",
92170
- { id }
92628
+ "Does not move money. Read signed-in chain state and participant events, or the public task card without sign-in.",
92629
+ participant
92171
92630
  );
92172
92631
  var signInHint = "Call auth.link for the acting wallet.";
92173
92632
  function lazyTasksChain(factory, pending) {
@@ -92307,6 +92766,22 @@ function createTasksTools(options) {
92307
92766
  };
92308
92767
  };
92309
92768
  }
92769
+ async function waitAfterChain(ctx, orderId, milestoneId, target) {
92770
+ return await taskRequest(
92771
+ target,
92772
+ "getOrder",
92773
+ () => waitForMilestone(ctx.client, {
92774
+ orderId,
92775
+ milestoneId,
92776
+ target,
92777
+ timeoutMs: 6e4,
92778
+ intervalMs: 3e3,
92779
+ ...options.sleep === void 0 ? {} : { sleep: options.sleep },
92780
+ now
92781
+ }),
92782
+ ctx
92783
+ );
92784
+ }
92310
92785
  async function feeAction(verb, input2) {
92311
92786
  const ctx = await acting(input2.wallet);
92312
92787
  const policy = await taskPolicyForWallet({
@@ -92349,7 +92824,12 @@ function createTasksTools(options) {
92349
92824
  throw new TaskInputError("deadline must be at least 10 minutes from now.");
92350
92825
  const ctx = await acting(input2.wallet);
92351
92826
  const outcome = await postTask(ctx, {
92352
- order: { title: input2.title, description: input2.brief, policyFamily: "general-digital" },
92827
+ order: {
92828
+ title: input2.title,
92829
+ description: input2.brief,
92830
+ policyFamily: "general-digital",
92831
+ ...input2.vendor === void 0 ? {} : { invitedProviderAddress: input2.vendor }
92832
+ },
92353
92833
  amount: parseUsdToBaseUnits(input2.amountUsd),
92354
92834
  deadlineAt: new Date(postedAt.getTime() + deadlineDuration).toISOString(),
92355
92835
  ...input2.intake === void 0 ? {} : { intake: input2.intake },
@@ -92407,15 +92887,15 @@ function createTasksTools(options) {
92407
92887
  const ctx = await acting(input2.wallet);
92408
92888
  const signerAddress = (await options.session.addressesFor(ctx.selected.name)).address;
92409
92889
  try {
92410
- return taskResult(
92411
- await signTaskScope(ctx, {
92412
- id: input2.id,
92413
- counterparty: input2.counterparty,
92414
- signerAddress,
92415
- bindings: createScopeBindings(home),
92416
- signMessage: async (message) => (await unlock(ctx.selected.name)()).signMessage(message)
92417
- })
92418
- );
92890
+ const outcome = await signTaskScope(ctx, {
92891
+ id: input2.id,
92892
+ counterparty: input2.counterparty,
92893
+ signerAddress,
92894
+ bindings: createScopeBindings(home),
92895
+ signMessage: async (message) => (await unlock(ctx.selected.name)()).signMessage(message)
92896
+ });
92897
+ const wait2 = input2.wait && outcome.escrowCreation ? await waitAfterChain(ctx, input2.id, outcome.escrowCreation.milestone.id, "created") : null;
92898
+ return taskResult({ ...outcome, wait: wait2 });
92419
92899
  } catch (error61) {
92420
92900
  if (!(error61 instanceof TasksScopeCreationError)) throw error61;
92421
92901
  try {
@@ -92451,28 +92931,31 @@ function createTasksTools(options) {
92451
92931
  // Stdio has no human approval channel. Model arguments cannot grant approval.
92452
92932
  approval: { granted: false }
92453
92933
  });
92454
- return taskResult(outcome, !outcome.ok);
92934
+ const wait2 = input2.wait && outcome.ok ? await waitAfterChain(ctx, input2.id, outcome.result.milestone.id, "locked") : null;
92935
+ return taskResult({ ...outcome, wait: wait2 }, !outcome.ok);
92455
92936
  },
92456
92937
  async deliver(input2) {
92457
92938
  const files = (await Promise.all(input2.files.map(readTaskFile))).map(
92458
92939
  ({ fileName: name, bytes, contentType }) => ({ name, bytes, contentType })
92459
92940
  );
92460
- return taskResult(
92461
- await deliverTaskOperation(await acting(input2.wallet), {
92462
- id: input2.id,
92463
- ...input2.counterparty === void 0 ? {} : { counterparty: input2.counterparty },
92464
- files,
92465
- note: input2.note
92466
- })
92467
- );
92941
+ const ctx = await acting(input2.wallet);
92942
+ const outcome = await deliverTaskOperation(ctx, {
92943
+ id: input2.id,
92944
+ ...input2.counterparty === void 0 ? {} : { counterparty: input2.counterparty },
92945
+ files,
92946
+ note: input2.note
92947
+ });
92948
+ const wait2 = input2.wait ? await waitAfterChain(ctx, input2.id, outcome.result.milestone.id, "delivered") : null;
92949
+ return taskResult({ ...outcome, wait: wait2 });
92468
92950
  },
92469
92951
  async release(input2) {
92470
- return taskResult(
92471
- await releaseTaskOperation(await acting(input2.wallet), {
92472
- id: input2.id,
92473
- ...input2.counterparty === void 0 ? {} : { counterparty: input2.counterparty }
92474
- })
92475
- );
92952
+ const ctx = await acting(input2.wallet);
92953
+ const outcome = await releaseTaskOperation(ctx, {
92954
+ id: input2.id,
92955
+ ...input2.counterparty === void 0 ? {} : { counterparty: input2.counterparty }
92956
+ });
92957
+ const wait2 = input2.wait ? await waitAfterChain(ctx, input2.id, outcome.result.milestone.id, "released") : null;
92958
+ return taskResult({ ...outcome, wait: wait2 });
92476
92959
  },
92477
92960
  async refund(input2) {
92478
92961
  return taskResult(
@@ -92539,7 +93022,11 @@ function createTasksTools(options) {
92539
93022
  }
92540
93023
  },
92541
93024
  async status(input2) {
92542
- return taskResult(await taskStatus(await context(void 0, true), { id: input2.id }));
93025
+ await options.wallets?.reload();
93026
+ const publicOnly = input2.wallet === void 0 && options.session.activeName === void 0 && options.wallets !== void 0 && options.wallets.names().length === 0;
93027
+ const candidate = await context(input2.wallet, publicOnly);
93028
+ const ctx = candidate.token || publicOnly ? candidate : await context(void 0, true);
93029
+ return taskResult(await taskStatus(ctx, { id: input2.id, signedIn: Boolean(ctx.token) }));
92543
93030
  }
92544
93031
  };
92545
93032
  }
@@ -93296,6 +93783,11 @@ var statsToolResultSchema = external_exports.object({
93296
93783
  )
93297
93784
  })
93298
93785
  });
93786
+ function objectOutputSchema(schema) {
93787
+ if (!schema) return {};
93788
+ const json2 = external_exports.toJSONSchema(schema);
93789
+ return json2.type === "object" ? { outputSchema: json2 } : {};
93790
+ }
93299
93791
  var VapiMcpServer = class {
93300
93792
  #tools = /* @__PURE__ */ new Map();
93301
93793
  #onClose;
@@ -93319,7 +93811,7 @@ var VapiMcpServer = class {
93319
93811
  name,
93320
93812
  ...tool.description ? { description: tool.description } : {},
93321
93813
  inputSchema: external_exports.toJSONSchema(tool.inputSchema),
93322
- ...tool.outputSchema ? { outputSchema: external_exports.toJSONSchema(tool.outputSchema) } : {}
93814
+ ...objectOutputSchema(tool.outputSchema)
93323
93815
  }))
93324
93816
  };
93325
93817
  }
@@ -94187,7 +94679,13 @@ function toolError(error61) {
94187
94679
  {
94188
94680
  error: error61.message,
94189
94681
  code: error61.code,
94190
- ...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
+ } : {},
94191
94689
  ...error61.paymentRejection ? { paymentRejection: error61.paymentRejection } : {},
94192
94690
  ...error61.confirmedSettlement ? { confirmedSettlement: error61.confirmedSettlement } : {}
94193
94691
  },
@@ -97681,7 +98179,7 @@ async function readProcessStdin() {
97681
98179
  }
97682
98180
 
97683
98181
  // src/version.ts
97684
- var CLI_VERSION = "0.9.0";
98182
+ var CLI_VERSION = "0.9.4";
97685
98183
 
97686
98184
  // src/status.ts
97687
98185
  async function statusCommand(argv, json2, io, dependencies) {
@@ -101183,7 +101681,7 @@ function createLocalRuntime(options) {
101183
101681
  const processCommand = options.processCommand ?? defaultProcessCommand;
101184
101682
  const ownsProcess = (handle, pid) => processCommand(pid)?.includes(runResultPath(home, handle.runId)) === true;
101185
101683
  const closeFd = options.closeFd ?? closeSync2;
101186
- const readFile29 = options.readFile ?? nodeReadFile;
101684
+ const readFile30 = options.readFile ?? nodeReadFile;
101187
101685
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
101188
101686
  const openLog = options.openLog ?? ((path) => {
101189
101687
  mkdirSync2(runsDirectory(home), { recursive: true, mode: 448 });
@@ -101238,7 +101736,7 @@ function createLocalRuntime(options) {
101238
101736
  return handle;
101239
101737
  },
101240
101738
  async status(handle) {
101241
- const result = await readResultFile(readFile29, runResultPath(home, handle.runId));
101739
+ const result = await readResultFile(readFile30, runResultPath(home, handle.runId));
101242
101740
  if (result !== void 0) return result;
101243
101741
  const pid = localPid(handle);
101244
101742
  if (pid === void 0 || handle.kind !== "local") {
@@ -101341,10 +101839,10 @@ function childArguments(member, run) {
101341
101839
  ...run.drawUsd ? ["--draw", run.drawUsd] : []
101342
101840
  ];
101343
101841
  }
101344
- async function readResultFile(readFile29, path) {
101842
+ async function readResultFile(readFile30, path) {
101345
101843
  let text;
101346
101844
  try {
101347
- text = await readFile29(path, "utf8");
101845
+ text = await readFile30(path, "utf8");
101348
101846
  } catch (error61) {
101349
101847
  if (hasCode3(error61, "ENOENT")) return void 0;
101350
101848
  return { state: "failed", detail: "unreadable result file" };
@@ -102194,7 +102692,7 @@ function isMcpInstallApp(value) {
102194
102692
  function serverEntry(home, registry2) {
102195
102693
  return {
102196
102694
  command: "npx",
102197
- args: ["-y", "vapi-network", "mcp"],
102695
+ args: ["-y", "vapi-network@latest", "mcp"],
102198
102696
  env: { VAPI_HOME: home, VAPI_REGISTRY_URL: registry2 }
102199
102697
  };
102200
102698
  }
@@ -102243,7 +102741,7 @@ function tomlConfig(existing, entry) {
102243
102741
  const block = [
102244
102742
  "[mcp_servers.vapi]",
102245
102743
  'command = "npx"',
102246
- 'args = ["-y", "vapi-network", "mcp"]',
102744
+ 'args = ["-y", "vapi-network@latest", "mcp"]',
102247
102745
  `env = { VAPI_HOME = "${escapeToml(entry.env.VAPI_HOME)}", VAPI_REGISTRY_URL = "${escapeToml(entry.env.VAPI_REGISTRY_URL)}" }`,
102248
102746
  ""
102249
102747
  ].join("\n");
@@ -102410,13 +102908,13 @@ async function sendConfig(dependencies) {
102410
102908
  // src/setup.ts
102411
102909
  import { rm as rm5 } from "node:fs/promises";
102412
102910
  import { join as join26 } from "node:path";
102413
- 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.`;
102414
102912
  var VAULT_CHOICE = "Create a new vault, or restore one from a recovery phrase? [new/restore] ";
102415
102913
  async function setupCommand(argv, json2, io, dependencies) {
102416
102914
  let parsed;
102417
102915
  try {
102418
102916
  parsed = parseArguments(argv, {
102419
- valueOptions: /* @__PURE__ */ new Set(),
102917
+ valueOptions: /* @__PURE__ */ new Set(["--accounts"]),
102420
102918
  booleanOptions: /* @__PURE__ */ new Set(["--no-cloud-backup"]),
102421
102919
  maximumPositionals: 0
102422
102920
  });
@@ -102427,6 +102925,7 @@ async function setupCommand(argv, json2, io, dependencies) {
102427
102925
  const paths = getVapiPaths();
102428
102926
  const steps = [];
102429
102927
  const humanIo = json2 ? stderrIo(io) : io;
102928
+ const accountCount = parseAccountCount(parsed.one("--accounts"));
102430
102929
  if (!await fileExists2(paths.config)) {
102431
102930
  await writeDefaultConfig(paths.config, process.env, { networks: ["base"] });
102432
102931
  steps.push("config");
@@ -102437,6 +102936,7 @@ async function setupCommand(argv, json2, io, dependencies) {
102437
102936
  let changedVault = false;
102438
102937
  let changedAccount = false;
102439
102938
  let changedLink = false;
102939
+ let scannedAddresses;
102440
102940
  if (!await fileExists2(join26(paths.directory, "vault.json"))) {
102441
102941
  const choice = await vaultChoice(dependencies);
102442
102942
  if (choice === "restore") {
@@ -102444,12 +102944,14 @@ async function setupCommand(argv, json2, io, dependencies) {
102444
102944
  throw new Error("Restoring needs a terminal to type the phrase.");
102445
102945
  }
102446
102946
  const readSecret = dependencies.prompts?.secret ?? promptForSecret;
102447
- await restoreVaultFromPhrase(
102947
+ const restored = await restoreVaultFromPhrase(
102448
102948
  await readSecret("Recovery phrase: "),
102449
102949
  config2,
102450
102950
  humanIo,
102451
- dependencies
102951
+ dependencies,
102952
+ accountCount
102452
102953
  );
102954
+ scannedAddresses = restored.scannedAddresses;
102453
102955
  store = await WalletStore.open(paths.directory, {
102454
102956
  secrets: getSecretStore(dependencies),
102455
102957
  env: dependencies.env ?? process.env,
@@ -102502,22 +103004,35 @@ async function setupCommand(argv, json2, io, dependencies) {
102502
103004
  }
102503
103005
  if (json2) {
102504
103006
  io.stdout(
102505
- 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
+ })
102506
103016
  );
102507
103017
  }
102508
103018
  }
102509
- async function restoreVaultFromPhrase(phrase, config2, io, dependencies) {
103019
+ async function restoreVaultFromPhrase(phrase, config2, io, dependencies, accountCount) {
102510
103020
  const paths = getVapiPaths();
102511
103021
  const validatedPhrase = validateRecoveryPhrase(phrase);
102512
103022
  const readBalance3 = baseUsdcBalanceReader(config2, dependencies);
102513
103023
  const key2 = await loadOrCreateDeviceKey({ secrets: getSecretStore(dependencies) });
102514
103024
  let names;
103025
+ let scannedAddresses = 0;
102515
103026
  try {
102516
103027
  const restored = await restoreVault({
102517
103028
  path: join26(paths.directory, "vault.json"),
102518
103029
  key: key2,
102519
103030
  phrase: validatedPhrase,
102520
103031
  probe: async (address4) => await readBalance3(address4) > 0n,
103032
+ ...accountCount === void 0 ? {} : { accountCount },
103033
+ onScanComplete: (count) => {
103034
+ scannedAddresses = count;
103035
+ },
102521
103036
  ...dependencies.now === void 0 ? {} : { now: dependencies.now }
102522
103037
  });
102523
103038
  names = restored.accounts().map((account) => account.name);
@@ -102529,8 +103044,25 @@ async function restoreVaultFromPhrase(phrase, config2, io, dependencies) {
102529
103044
  ...names[0] === void 0 ? {} : { wallet: names[0] },
102530
103045
  detail: `${names.length} account(s)`
102531
103046
  });
102532
- io.stdout(`Vault restored with ${names.length} account(s): ${names.join(", ")}`);
102533
- 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;
102534
103066
  }
102535
103067
  async function vaultChoice(dependencies) {
102536
103068
  const answer = dependencies.prompts?.line === void 0 ? isInteractive(dependencies) ? await promptForLine(VAULT_CHOICE) : "" : await dependencies.prompts.line(VAULT_CHOICE);
@@ -102630,10 +103162,10 @@ var TASK_HELP = `Usage:
102630
103162
  vapi task propose <id> --price <usd> --duration <duration> --note <text> [--account <name>] [--json]
102631
103163
  vapi task submit <id> --proof <https-url> [--proof <https-url>...] [--file <path>...] [--account <name>] [--json]
102632
103164
  vapi task award <id> <proposalId> [--account <name>] [--json]
102633
- vapi task sign <id> [--yes] [--counterparty <0x\u2026>] [--account <name>] [--json]
102634
- vapi task fund <id> [--yes] [--counterparty <0x\u2026>] [--account <name>] [--json]
102635
- vapi task deliver <id> --files <path...> --note <text> [--counterparty <0x\u2026>] [--account <name>] [--json]
102636
- vapi task release <id> [--counterparty <0x\u2026>] [--account <name>] [--json]
103165
+ vapi task sign <id> [--yes] [--no-wait] [--timeout 120s] [--counterparty <0x\u2026>] [--account <name>] [--json]
103166
+ vapi task fund <id> [--yes] [--no-wait] [--timeout 120s] [--counterparty <0x\u2026>] [--account <name>] [--json]
103167
+ vapi task deliver <id> --files <path...> --note <text> [--no-wait] [--timeout 120s] [--counterparty <0x\u2026>] [--account <name>] [--json]
103168
+ vapi task release <id> [--no-wait] [--timeout 120s] [--counterparty <0x\u2026>] [--account <name>] [--json]
102637
103169
  vapi task refund <id> [--counterparty <0x\u2026>] [--account <name>] [--json]
102638
103170
  vapi task dispute <id> --evidence-hash <0x + 64 hex> [--yes] [--counterparty <0x\u2026>] [--account <name>] [--json]
102639
103171
  vapi task counter-evidence <id> --evidence-hash <0x + 64 hex> [--yes] [--counterparty <0x\u2026>] [--account <name>] [--json]
@@ -102656,23 +103188,25 @@ Exit codes:
102656
103188
  2 policy refusal only (JSON ok:false with reason policy.perTask or policy.perDay)
102657
103189
  3 approval needed in non-interactive mode
102658
103190
 
102659
- Fund, deliver, release, refund, dispute, counter-evidence, resolve-unmatched and watch auto-release sign with the local vault wallet. The CLI waits for two confirmations and records pending transactions for recovery. It never retries a chain mutation automatically.`;
103191
+ Fund, deliver, release, refund, dispute, counter-evidence, resolve-unmatched and watch auto-release sign with the local vault wallet. The CLI waits for two confirmations and records pending transactions for recovery. It never retries a chain mutation automatically. Sign, fund, deliver and release wait up to 120s for vAPI to index a confirmed transaction unless --no-wait is set; an indexing timeout keeps exit code 0.`;
102660
103192
  var IMPLEMENTED_VERBS = TASKS_CLIENT_VERBS;
102661
103193
  var USAGE = `Usage: vapi task <${IMPLEMENTED_VERBS.join("|")}>. Run vapi task --help.`;
102662
103194
  var TaskCommandError = class extends Error {
102663
- constructor(code, message, manifestHash) {
103195
+ constructor(code, message, manifestHash, prefixCode = false) {
102664
103196
  super(message);
102665
103197
  this.code = code;
102666
103198
  this.manifestHash = manifestHash;
103199
+ this.prefixCode = prefixCode;
102667
103200
  this.name = "TaskCommandError";
102668
103201
  }
102669
103202
  code;
102670
103203
  manifestHash;
103204
+ prefixCode;
102671
103205
  };
102672
103206
  function mapTaskError(error61) {
102673
103207
  if (error61 instanceof TaskInputError) return new UsageError(error61.message);
102674
103208
  if (error61 instanceof TaskOperationError)
102675
- return new TaskCommandError(error61.code, error61.message, error61.manifestHash);
103209
+ return new TaskCommandError(error61.code, error61.message, error61.manifestHash, true);
102676
103210
  return error61;
102677
103211
  }
102678
103212
  async function mapped(operation) {
@@ -102891,11 +103425,13 @@ async function taskCommandInner(argv, json2, io, dependencies) {
102891
103425
  "--intake",
102892
103426
  "--max-awards",
102893
103427
  "--webhook"
102894
- ] : verb === "propose" ? ["--price", "--duration", "--note"] : verb === "submit" ? ["--proof", "--file"] : verb === "thread" ? ["--after"] : verb === "deliver" ? ["--files", "--note"] : ["dispute", "counter-evidence"].includes(verb) ? ["--evidence-hash"] : verb === "watch" ? ["--until", "--timeout", "--interval"] : []
103428
+ ] : verb === "propose" ? ["--price", "--duration", "--note"] : verb === "submit" ? ["--proof", "--file"] : verb === "thread" ? ["--after"] : verb === "deliver" ? ["--files", "--note"] : ["dispute", "counter-evidence"].includes(verb) ? ["--evidence-hash"] : verb === "watch" ? ["--until", "--timeout", "--interval"] : [],
103429
+ ...["sign", "fund", "deliver", "release"].includes(verb) ? ["--timeout"] : []
102895
103430
  ]),
102896
103431
  booleanOptions: /* @__PURE__ */ new Set([
102897
103432
  ...verb === "search" ? ["--open"] : [],
102898
103433
  ...["sign", "fund", "dispute", "counter-evidence"].includes(verb) ? ["--yes"] : [],
103434
+ ...["sign", "fund", "deliver", "release"].includes(verb) ? ["--no-wait"] : [],
102899
103435
  ...verb === "watch" ? ["--auto-release"] : []
102900
103436
  ]),
102901
103437
  repeatableOptions: /* @__PURE__ */ new Set([
@@ -103051,7 +103587,7 @@ async function taskCommandInner(argv, json2, io, dependencies) {
103051
103587
  throw new UsageError("message needs text between 1 and 10000 characters.");
103052
103588
  }
103053
103589
  if (verb === "thread") cursor2 = optionalInteger(parsed.one("--after"), "--after");
103054
- const context = await taskContext(parsed, io, dependencies, verb === "status");
103590
+ const context = await taskContext(parsed, io, dependencies);
103055
103591
  if (verb === "show" || verb === "status") {
103056
103592
  if (verb === "show" && context.token) {
103057
103593
  const result = await showTask(context, { id: id2, signedIn: true });
@@ -103061,7 +103597,21 @@ async function taskCommandInner(argv, json2, io, dependencies) {
103061
103597
  ...receipts.map((receipt) => `Receipt (from escrow): ${receipt.receiptUrl}`)
103062
103598
  ]);
103063
103599
  } else {
103064
- const result = verb === "status" ? await taskStatus(context, { id: id2 }) : await showTask(context, { id: id2, signedIn: false });
103600
+ const result = verb === "status" ? await taskStatus(context, { id: id2, signedIn: Boolean(context.token) }) : await showTask(context, { id: id2, signedIn: false });
103601
+ if ("chainState" in result) {
103602
+ const milestoneLines = result.chainState.milestones.map((milestone) => {
103603
+ const ordinal = "ordinal" in milestone && typeof milestone.ordinal === "number" && Number.isFinite(milestone.ordinal) ? milestone.ordinal : milestone.milestoneId;
103604
+ const state = "state" in milestone.read ? ` ${milestone.read.state}` : "";
103605
+ const explorer = milestone.explorerUrl ? ` ${milestone.explorerUrl}` : "";
103606
+ return `milestone ${ordinal}: ${milestone.read.status}${state}${explorer}`;
103607
+ });
103608
+ const eventLines = (result.events ?? []).slice(-10).map((event) => {
103609
+ const createdAt = "createdAt" in event && typeof event.createdAt === "string" ? event.createdAt : event.at;
103610
+ return `${event.sequence} ${event.type} ${createdAt}`;
103611
+ });
103612
+ taskOutput(io, json2, context, verb, result, [...milestoneLines, ...eventLines]);
103613
+ return;
103614
+ }
103065
103615
  const task = result.task;
103066
103616
  taskOutput(
103067
103617
  io,
@@ -103105,6 +103655,11 @@ async function taskCommandInner(argv, json2, io, dependencies) {
103105
103655
  async function escrowTaskCommand(verb, id2, parsed, json2, io, dependencies, now) {
103106
103656
  taskCounterparty(parsed);
103107
103657
  if (verb === "watch") return await watchTask(id2, parsed, json2, io, dependencies, now);
103658
+ const waitsForIndex = ["sign", "fund", "deliver", "release"].includes(verb);
103659
+ const waitTimeoutText = parsed.one("--timeout") ?? "120s";
103660
+ const waitTimeoutMs = waitsForIndex ? parseTaskDuration2(waitTimeoutText, now) : void 0;
103661
+ if (waitTimeoutMs !== void 0 && waitTimeoutMs <= 0)
103662
+ throw new UsageError("--timeout must be positive.");
103108
103663
  const disputeEvidenceHash = ["dispute", "counter-evidence"].includes(verb) ? required3(parsed, "--evidence-hash") : void 0;
103109
103664
  const counterparty = taskCounterparty(parsed);
103110
103665
  if (disputeEvidenceHash !== void 0 && !TASK_LIMITS.disputeEvidenceHash.test(disputeEvidenceHash))
@@ -103154,9 +103709,24 @@ async function escrowTaskCommand(verb, id2, parsed, json2, io, dependencies, now
103154
103709
  return await account.signMessage({ message });
103155
103710
  }
103156
103711
  });
103157
- taskOutput(io, json2, displayContext, verb, result2, [
103712
+ if (!json2 && result2.escrowCreation?.resumedFromServer)
103713
+ io.stdout("The server had already prepared escrow creation; resumed from it.");
103714
+ const wait3 = result2.escrowCreation ? await waitForTaskIndex(
103715
+ context,
103716
+ dependencies,
103717
+ parsed,
103718
+ json2,
103719
+ io,
103720
+ id2,
103721
+ result2.escrowCreation,
103722
+ "created",
103723
+ "escrow creation",
103724
+ waitTimeoutText,
103725
+ waitTimeoutMs
103726
+ ) : null;
103727
+ taskOutput(io, json2, displayContext, verb, { ...result2, wait: wait3 }, [
103158
103728
  `Accepted scope for task ${id2}.`,
103159
- ...result2.escrowCreation ? ["Created the task escrow."] : []
103729
+ ...result2.escrowCreation && (wait3 === null || wait3.reached) ? ["escrow created"] : []
103160
103730
  ]);
103161
103731
  return;
103162
103732
  } catch (error61) {
@@ -103190,7 +103760,23 @@ async function escrowTaskCommand(verb, id2, parsed, json2, io, dependencies, now
103190
103760
  taskOutput(io, false, context, verb, {}, [`Prepared delivery manifest ${manifestHash}.`]);
103191
103761
  }
103192
103762
  });
103193
- taskOutput(io, json2, context, verb, outcome, [`Delivered task ${id2}.`]);
103763
+ const wait3 = await waitForTaskIndex(
103764
+ context,
103765
+ dependencies,
103766
+ parsed,
103767
+ json2,
103768
+ io,
103769
+ id2,
103770
+ outcome.result,
103771
+ "delivered",
103772
+ "delivery",
103773
+ waitTimeoutText,
103774
+ waitTimeoutMs
103775
+ );
103776
+ taskOutput(io, json2, context, verb, { ...outcome, wait: wait3 }, [
103777
+ ...wait3 === null || wait3.reached ? ["delivery recorded"] : [],
103778
+ ...outcome.result.resumedFromServer === true ? ["The server had already recorded this delivery; resumed from it."] : []
103779
+ ]);
103194
103780
  return;
103195
103781
  }
103196
103782
  const snapshot = await taskMoneySnapshot(context.client, id2, void 0, {
@@ -103253,15 +103839,82 @@ async function escrowTaskCommand(verb, id2, parsed, json2, io, dependencies, now
103253
103839
  }
103254
103840
  if (!outcome.ok && "declined" in outcome)
103255
103841
  throw new TaskCommandError("not_approved", "Not approved; nothing was signed.");
103256
- taskOutput(io, json2, context, verb, outcome, [
103257
- verb === "fund" ? `Funded task ${id2}.` : `Completed task ${verb} for ${id2}.`
103258
- ]);
103842
+ if (!json2 && outcome.result.resumedFromServer)
103843
+ io.stdout("The server had already prepared this task operation; resumed from it.");
103844
+ const wait3 = verb === "fund" ? await waitForTaskIndex(
103845
+ context,
103846
+ dependencies,
103847
+ parsed,
103848
+ json2,
103849
+ io,
103850
+ id2,
103851
+ outcome.result,
103852
+ "locked",
103853
+ "funding",
103854
+ waitTimeoutText,
103855
+ waitTimeoutMs
103856
+ ) : void 0;
103857
+ taskOutput(
103858
+ io,
103859
+ json2,
103860
+ context,
103861
+ verb,
103862
+ wait3 === void 0 ? outcome : { ...outcome, wait: wait3 },
103863
+ verb === "fund" ? wait3 === null || wait3?.reached ? ["escrow funded"] : [] : [`Completed task ${verb} for ${id2}.`]
103864
+ );
103259
103865
  return;
103260
103866
  }
103261
103867
  if (!json2) io.stdout("Policy: explicit user instruction.");
103262
103868
  const settlementInput = { id: id2, snapshot, ...counterparty === void 0 ? {} : { counterparty } };
103263
103869
  const result = verb === "release" ? await releaseTaskOperation(context, settlementInput) : verb === "refund" ? await refundTaskOperation(context, settlementInput) : await resolveUnmatchedTaskOperation(context, settlementInput);
103264
- taskOutput(io, json2, context, verb, result, [`Completed task ${verb} for ${id2}.`]);
103870
+ if (!json2 && result.result.resumedFromServer)
103871
+ io.stdout("The server had already prepared this task operation; resumed from it.");
103872
+ const wait2 = verb === "release" ? await waitForTaskIndex(
103873
+ context,
103874
+ dependencies,
103875
+ parsed,
103876
+ json2,
103877
+ io,
103878
+ id2,
103879
+ result.result,
103880
+ "released",
103881
+ "release",
103882
+ waitTimeoutText,
103883
+ waitTimeoutMs
103884
+ ) : void 0;
103885
+ taskOutput(
103886
+ io,
103887
+ json2,
103888
+ context,
103889
+ verb,
103890
+ wait2 === void 0 ? result : { ...result, wait: wait2 },
103891
+ verb === "release" ? wait2 === null || wait2?.reached ? ["funds released"] : [] : [`Completed task ${verb} for ${id2}.`]
103892
+ );
103893
+ }
103894
+ async function waitForTaskIndex(context, dependencies, parsed, json2, io, orderId, result, target, description, timeoutText, timeoutMs) {
103895
+ if (parsed.has("--no-wait")) return null;
103896
+ if (!json2)
103897
+ io.stdout(
103898
+ `confirmed on chain${result.blockNumber === void 0 ? "" : ` in block ${result.blockNumber}`}, waiting for vAPI to index\u2026`
103899
+ );
103900
+ const wait2 = await taskRequest2(
103901
+ description,
103902
+ "getOrder",
103903
+ () => waitForMilestone(context.client, {
103904
+ orderId,
103905
+ milestoneId: result.milestone.id,
103906
+ target,
103907
+ timeoutMs,
103908
+ intervalMs: 3e3,
103909
+ sleep: context.sleep,
103910
+ now: dependencies.now ?? (() => /* @__PURE__ */ new Date())
103911
+ })
103912
+ );
103913
+ if (!wait2.reached)
103914
+ io.stderr(
103915
+ `vAPI has not indexed the ${description} yet after ${timeoutText}; run vapi task status ${orderId} later.`
103916
+ );
103917
+ return wait2;
103265
103918
  }
103266
103919
  var ScopeApprovalNeeded = class extends Error {
103267
103920
  constructor(terms) {
@@ -104517,6 +105170,7 @@ async function referencedSleep(milliseconds, signal) {
104517
105170
  // src/vault.ts
104518
105171
  import { join as join27 } from "node:path";
104519
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]";
104520
105174
  var LEGACY_PASSWORD_NOTICE = "VAPI_KEYSTORE_PASSWORD is deprecated for vault passwords; use VAPI_VAULT_PASSWORD instead.";
104521
105175
  async function vaultCommand(argv, json2, io, dependencies) {
104522
105176
  const subcommand = argv[0];
@@ -104546,9 +105200,17 @@ async function restoreCommand(argv, json2, io, dependencies) {
104546
105200
  await restoreFromOwnerCommand(argv, json2, io, dependencies);
104547
105201
  return;
104548
105202
  }
104549
- if (argv.length > 0) {
104550
- 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;
104551
105212
  }
105213
+ const accountCount = parseRestoreAccountCount(parsed.one("--accounts"));
104552
105214
  const paths = getVapiPaths();
104553
105215
  const path = join27(paths.directory, "vault.json");
104554
105216
  if (await fileExists2(path)) {
@@ -104562,13 +105224,39 @@ async function restoreCommand(argv, json2, io, dependencies) {
104562
105224
  const config2 = await readConfig(paths.config, json2 ? quietIo(io) : io);
104563
105225
  const phrase = isStdinInteractive(dependencies) ? await getPrompts(dependencies).secret("Recovery phrase: ") : await (dependencies.readStdin ?? readProcessStdin3)();
104564
105226
  const restoreIo = json2 ? quietIo(io) : io;
104565
- 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
+ );
104566
105234
  if (json2) {
104567
- 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
+ );
104568
105241
  return;
104569
105242
  }
104570
105243
  io.stdout(`Run vapi setup to link ${names[0]}.`);
104571
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
+ }
104572
105260
  async function protectCommand(argv, json2, io, dependencies) {
104573
105261
  requireNoArguments(argv);
104574
105262
  const env = getEnvironment(dependencies);
@@ -104698,8 +105386,8 @@ var HELP_HEADING = "vAPI Network";
104698
105386
  var HELP = `${HELP_HEADING}
104699
105387
 
104700
105388
  Usage:
104701
- vapi init [--networks <base,arc,solana>] [--json]
104702
- vapi setup [--no-cloud-backup] [--json]
105389
+ vapi init [--networks <base,arc>] [--json]
105390
+ vapi setup [--no-cloud-backup] [--accounts <n>] [--json]
104703
105391
  vapi accounts [--all] [--json]
104704
105392
  vapi accounts add <name> [--label <text>] [--no-link] [--json]
104705
105393
  vapi accounts import <name> [--keystore <path> | --key-file <path>] [--label <text>] [--json]
@@ -104729,7 +105417,7 @@ Usage:
104729
105417
  vapi docs read <url-or-path> [--json]
104730
105418
  vapi search [query] [--kind <kind>] [--network <caip2>] [--limit <n>] [--cursor <cursor>] [--include-unverified] [--json]
104731
105419
  vapi inspect <id> [--endpoint <name>] [--json]
104732
- 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]
104733
105421
  vapi pay --resume <receipt-id> [--json]
104734
105422
  vapi check <url> [--method <method>] [--json]
104735
105423
  vapi balance [--account <name>] [--json]
@@ -104775,8 +105463,8 @@ Usage:
104775
105463
  vapi task status <id> [--account <name>] [--json]
104776
105464
  vapi export-key [--network <caip2>] [--account <name>] [--json]
104777
105465
  vapi backup [--account <name>] [--cloud [off]] [--json]
104778
- vapi restore [--from-owner [--owner <0x\u2026>]] [--json]
104779
- 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]
104780
105468
  vapi passphrase [--account <name>] [--json]
104781
105469
  vapi vault protect [--json]
104782
105470
  vapi vault unprotect [--json]
@@ -104804,6 +105492,8 @@ Every command that touches a wallet takes \`--account <name>\`, falls back to \`
104804
105492
 
104805
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]\`.
104806
105494
 
105495
+ Solana listings remain searchable; inspect and pay return \`unsupported_network\`. Solana keys are not part of the device vault yet.
105496
+
104807
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.
104808
105498
 
104809
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.
@@ -104816,7 +105506,7 @@ Every command that touches a wallet takes \`--account <name>\`, falls back to \`
104816
105506
 
104817
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.
104818
105508
 
104819
- \`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.
104820
105510
 
104821
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.
104822
105512
 
@@ -105193,6 +105883,7 @@ async function runCli(argv = process.argv.slice(2), io = processIo, dependencies
105193
105883
  error: message,
105194
105884
  exitCode: code,
105195
105885
  ...error61 instanceof RuntimeError ? { code: error61.code } : {},
105886
+ ...error61 instanceof VapiCallError ? { code: error61.code } : {},
105196
105887
  ...error61 instanceof DocsError ? { code: error61.code } : {},
105197
105888
  ...error61 instanceof RemoteKeyRefusedError ? { code: error61.code } : {},
105198
105889
  ...error61 instanceof TransferError ? { code: error61.code, moneyMoved: error61.moneyMoved } : {}
@@ -105200,7 +105891,10 @@ async function runCli(argv = process.argv.slice(2), io = processIo, dependencies
105200
105891
  );
105201
105892
  }
105202
105893
  } else {
105203
- runIo.stderr(message);
105894
+ const errorCode2 = taskInvocation && error61 instanceof TaskCommandError && error61.prefixCode ? errorCodeOf(error61) : void 0;
105895
+ runIo.stderr(
105896
+ errorCode2 !== void 0 && !message.startsWith(`${errorCode2}: `) ? `${errorCode2}: ${message}` : message
105897
+ );
105204
105898
  }
105205
105899
  if (shouldAutoUploadAfterFailure(argv.filter((argument) => argument !== "--json"))) {
105206
105900
  await autoUploadBackup(io, json2, dependencies);
@@ -105601,7 +106295,7 @@ async function inspectCommand(argv, json2, io, dependencies) {
105601
106295
  );
105602
106296
  output3(io, json2, result, formatInspect(result));
105603
106297
  }
105604
- 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]";
105605
106299
  async function payCommand(argv, json2, io, dependencies) {
105606
106300
  if (argv.includes(RESUME_OPTION)) {
105607
106301
  await payResumeCommand(argv, json2, io, dependencies);
@@ -105617,11 +106311,13 @@ async function payCommand(argv, json2, io, dependencies) {
105617
106311
  "--expected-pay-to",
105618
106312
  "--max",
105619
106313
  "--max-price-usd",
106314
+ "--timeout",
105620
106315
  WALLET_OPTION5
105621
106316
  ]),
105622
106317
  maximumPositionals: 1
105623
106318
  });
105624
106319
  const target = requiredPositional(parsed.positionals[0], "<id-or-url>", PAY_USAGE);
106320
+ const timeoutSeconds = optionalBoundedInteger(parsed.one("--timeout"), "--timeout", 1, 300);
105625
106321
  const paths = getVapiPaths();
105626
106322
  const config2 = await readConfig(paths.config, io);
105627
106323
  const wallet = await targetWallet(parsed, dependencies);
@@ -105637,7 +106333,8 @@ async function payCommand(argv, json2, io, dependencies) {
105637
106333
  ...parsed.one("--content-type") ? { contentType: parsed.one("--content-type") } : {},
105638
106334
  ...parsed.one("--network") ? { network: parsed.one("--network") } : {},
105639
106335
  ...parsed.one("--expected-pay-to") ? { expectedPayTo: parsed.one("--expected-pay-to") } : {},
105640
- ...maxPriceUsd ? { maxPriceUsd } : {}
106336
+ ...maxPriceUsd ? { maxPriceUsd } : {},
106337
+ ...timeoutSeconds === void 0 ? {} : { timeoutSeconds }
105641
106338
  };
105642
106339
  const call2 = createCallPort({
105643
106340
  config: config2,
@@ -107312,7 +108009,7 @@ function buildNextSteps(address4) {
107312
108009
  formatNextStep("Pay", "vapi pay <ref> --max 0.02"),
107313
108010
  formatNextStep(
107314
108011
  "Agent",
107315
- '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'
107316
108013
  )
107317
108014
  ];
107318
108015
  }
@@ -107493,6 +108190,17 @@ function optionalPositiveInteger(value, option) {
107493
108190
  if (result === 0) throw new UsageError(`${option} must be a positive integer.`);
107494
108191
  return result;
107495
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
+ }
107496
108204
  function optionalUsdAmount(value, option) {
107497
108205
  if (value === void 0) return void 0;
107498
108206
  if (!/^\d+(?:\.\d{1,2})?$/.test(value)) {
@@ -107553,17 +108261,144 @@ function parseInitNetworks(value) {
107553
108261
  }
107554
108262
  for (const network of networks) {
107555
108263
  if (network !== "base" && network !== "arc" && network !== "solana") {
107556
- throw new UsageError("--networks supports base, arc and solana.");
108264
+ throw new UsageError("--networks supports base and arc; Solana vault setup is unavailable.");
107557
108265
  }
107558
108266
  }
107559
108267
  return networks;
107560
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
+ }
107561
108395
  export {
107562
108396
  HELP,
107563
108397
  createLocalRuntime,
107564
108398
  parseRuntimeKind,
107565
108399
  resolveRuntime,
107566
108400
  runCli,
108401
+ runCliWithUpdateCheck,
107567
108402
  runtimeForKind
107568
108403
  };
107569
108404
  //# sourceMappingURL=index.js.map