@vapi-network/core 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/account-add.d.ts +8 -1
  2. package/dist/account-add.d.ts.map +1 -1
  3. package/dist/account-movement-lock.d.ts +10 -0
  4. package/dist/account-movement-lock.d.ts.map +1 -0
  5. package/dist/agent-link.d.ts +1 -0
  6. package/dist/agent-link.d.ts.map +1 -1
  7. package/dist/agent-link.js +21 -10
  8. package/dist/agent-link.js.map +1 -1
  9. package/dist/agent-profile.d.ts +14 -2
  10. package/dist/agent-profile.d.ts.map +1 -1
  11. package/dist/agent-run.d.ts +12 -0
  12. package/dist/agent-run.d.ts.map +1 -0
  13. package/dist/allocation.d.ts +35 -4
  14. package/dist/allocation.d.ts.map +1 -1
  15. package/dist/api-key.js.map +1 -1
  16. package/dist/atomic-file.d.ts +23 -0
  17. package/dist/atomic-file.d.ts.map +1 -0
  18. package/dist/audit.d.ts +4 -1
  19. package/dist/audit.d.ts.map +1 -1
  20. package/dist/backup.d.ts +153 -32
  21. package/dist/backup.d.ts.map +1 -1
  22. package/dist/backup.js +2535 -139
  23. package/dist/backup.js.map +3 -3
  24. package/dist/call-contracts-wire.d.ts +12 -12
  25. package/dist/ceiling.d.ts +8 -0
  26. package/dist/ceiling.d.ts.map +1 -1
  27. package/dist/cloud-backup.d.ts +8 -10
  28. package/dist/cloud-backup.d.ts.map +1 -1
  29. package/dist/cloud-backup.js +2806 -381
  30. package/dist/cloud-backup.js.map +3 -3
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/distribute.d.ts +9 -1
  33. package/dist/distribute.d.ts.map +1 -1
  34. package/dist/index.d.ts +8 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +5206 -1270
  37. package/dist/index.js.map +3 -3
  38. package/dist/marketplace-contracts.d.ts +14 -14
  39. package/dist/member-bundle.d.ts +110 -0
  40. package/dist/member-bundle.d.ts.map +1 -0
  41. package/dist/movement-open.d.ts +10 -0
  42. package/dist/movement-open.d.ts.map +1 -0
  43. package/dist/movement.d.ts +77 -7
  44. package/dist/movement.d.ts.map +1 -1
  45. package/dist/receipts.d.ts +9 -0
  46. package/dist/receipts.d.ts.map +1 -1
  47. package/dist/router-client.d.ts +9 -1
  48. package/dist/router-client.d.ts.map +1 -1
  49. package/dist/router-client.js +2073 -607
  50. package/dist/router-client.js.map +3 -3
  51. package/dist/run-budget.d.ts +17 -0
  52. package/dist/run-budget.d.ts.map +1 -0
  53. package/dist/secret-store.d.ts +6 -0
  54. package/dist/secret-store.d.ts.map +1 -1
  55. package/dist/secrets.d.ts +2 -1
  56. package/dist/secrets.d.ts.map +1 -1
  57. package/dist/secrets.js +884 -48
  58. package/dist/secrets.js.map +3 -3
  59. package/dist/support-report.d.ts +1 -1
  60. package/dist/swarm-capital.d.ts +147 -0
  61. package/dist/swarm-capital.d.ts.map +1 -0
  62. package/dist/swarm.d.ts +224 -0
  63. package/dist/swarm.d.ts.map +1 -0
  64. package/dist/transfer-journal.d.ts +11 -0
  65. package/dist/transfer-journal.d.ts.map +1 -0
  66. package/dist/transfer.d.ts +4 -1
  67. package/dist/transfer.d.ts.map +1 -1
  68. package/dist/vault.d.ts +11 -0
  69. package/dist/vault.d.ts.map +1 -1
  70. package/dist/wallet-store.d.ts +19 -8
  71. package/dist/wallet-store.d.ts.map +1 -1
  72. package/dist/x402-pay.d.ts +7 -0
  73. package/dist/x402-pay.d.ts.map +1 -1
  74. package/dist/x402.d.ts +3 -0
  75. package/dist/x402.d.ts.map +1 -1
  76. package/package.json +1 -1
package/dist/secrets.js CHANGED
@@ -2212,7 +2212,7 @@ function weierstrass(curveDef) {
2212
2212
  function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
2213
2213
  if (["recovered", "canonical"].some((k) => k in opts))
2214
2214
  throw new Error("sign() legacy options not supported");
2215
- const { hash: hash2, randomBytes: randomBytes4 } = CURVE;
2215
+ const { hash: hash2, randomBytes: randomBytes5 } = CURVE;
2216
2216
  let { lowS, prehash, extraEntropy: ent } = opts;
2217
2217
  if (lowS == null)
2218
2218
  lowS = true;
@@ -2224,7 +2224,7 @@ function weierstrass(curveDef) {
2224
2224
  const d = normPrivateKeyToScalar(privateKey);
2225
2225
  const seedArgs = [int2octets(d), int2octets(h1int)];
2226
2226
  if (ent != null && ent !== false) {
2227
- const e2 = ent === true ? randomBytes4(Fp.BYTES) : ent;
2227
+ const e2 = ent === true ? randomBytes5(Fp.BYTES) : ent;
2228
2228
  seedArgs.push(ensureBytes("extraEntropy", e2));
2229
2229
  }
2230
2230
  const seed = concatBytes2(...seedArgs);
@@ -2793,16 +2793,16 @@ function hexToBytes3(hex_, opts = {}) {
2793
2793
  assertSize(hex3, { size: opts.size });
2794
2794
  hex3 = pad(hex3, { dir: "right", size: opts.size });
2795
2795
  }
2796
- let hexString = hex3.slice(2);
2797
- if (hexString.length % 2)
2798
- hexString = `0${hexString}`;
2799
- const length = hexString.length / 2;
2796
+ let hexString2 = hex3.slice(2);
2797
+ if (hexString2.length % 2)
2798
+ hexString2 = `0${hexString2}`;
2799
+ const length = hexString2.length / 2;
2800
2800
  const bytes = new Uint8Array(length);
2801
2801
  for (let index = 0, j = 0; index < length; index++) {
2802
- const nibbleLeft = charCodeToBase16(hexString.charCodeAt(j++));
2803
- const nibbleRight = charCodeToBase16(hexString.charCodeAt(j++));
2802
+ const nibbleLeft = charCodeToBase16(hexString2.charCodeAt(j++));
2803
+ const nibbleRight = charCodeToBase16(hexString2.charCodeAt(j++));
2804
2804
  if (nibbleLeft === void 0 || nibbleRight === void 0) {
2805
- throw new BaseError(`Invalid byte sequence ("${hexString[j - 2]}${hexString[j - 1]}" in "${hexString}").`);
2805
+ throw new BaseError(`Invalid byte sequence ("${hexString2[j - 2]}${hexString2[j - 1]}" in "${hexString2}").`);
2806
2806
  }
2807
2807
  bytes[index] = nibbleLeft * 16 + nibbleRight;
2808
2808
  }
@@ -4273,9 +4273,9 @@ var init_stringify = __esm({
4273
4273
  });
4274
4274
 
4275
4275
  // src/keystore.ts
4276
- import { createCipheriv, createDecipheriv, randomBytes as randomBytes2, scrypt } from "node:crypto";
4277
- import { mkdir as mkdir2, readFile as readFile2, rename as rename2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
4278
- import { dirname as dirname2 } from "node:path";
4276
+ import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, scrypt } from "node:crypto";
4277
+ import { mkdir as mkdir3, readFile as readFile3, rename as rename3, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
4278
+ import { dirname as dirname3 } from "node:path";
4279
4279
 
4280
4280
  // ../../node_modules/.pnpm/@solana+errors@5.5.1_typescript@6.0.3/node_modules/@solana/errors/dist/index.node.mjs
4281
4281
  var SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED = 1;
@@ -46542,13 +46542,232 @@ function date4(params) {
46542
46542
 
46543
46543
  // src/config.ts
46544
46544
  import { constants } from "node:fs";
46545
- import { copyFile, mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
46545
+ import { copyFile, mkdir as mkdir2, readFile as readFile2, rename as rename2, stat as stat2, writeFile } from "node:fs/promises";
46546
46546
  import { homedir } from "node:os";
46547
- import { dirname, join as join2 } from "node:path";
46547
+ import { dirname as dirname2, join as join3 } from "node:path";
46548
46548
 
46549
46549
  // ../../node_modules/.pnpm/viem@2.56.1_typescript@6.0.3_zod@4.5.4/node_modules/viem/_esm/index.js
46550
46550
  init_getAddress();
46551
46551
 
46552
+ // src/atomic-file.ts
46553
+ import { randomBytes as randomBytes2 } from "node:crypto";
46554
+ import { link, mkdir, open as open2, readdir, readFile, rename, stat, unlink } from "node:fs/promises";
46555
+ import { basename, dirname, join as join2 } from "node:path";
46556
+ var DEFAULT_LOCK_TIMEOUT_MS = 2e3;
46557
+ var LOCK_RETRY_MS = 20;
46558
+ var LOCK_STALE_AFTER_MS = 12e4;
46559
+ var LOCK_HEARTBEAT_MS = 3e4;
46560
+ var atomicFileTestHooks;
46561
+ var FileLockedError = class extends Error {
46562
+ constructor(message = "Timed out waiting for the file lock.") {
46563
+ super(message);
46564
+ this.name = "FileLockedError";
46565
+ }
46566
+ };
46567
+ async function withFileLock(lockPath, fn, options = {}) {
46568
+ await mkdir(dirname(lockPath), { recursive: true, mode: 448 });
46569
+ const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS);
46570
+ const ownerRecord = {
46571
+ pid: process.pid,
46572
+ token: randomBytes2(16).toString("hex")
46573
+ };
46574
+ const owner = JSON.stringify(ownerRecord);
46575
+ const releasedOwner = JSON.stringify({ ...ownerRecord, released: true });
46576
+ let handle;
46577
+ while (handle === void 0) {
46578
+ await atomicFileTestHooks?.beforeLockAttempt?.(lockPath);
46579
+ try {
46580
+ const candidate = await open2(lockPath, "wx", 384);
46581
+ try {
46582
+ await candidate.writeFile(owner, "utf8");
46583
+ await candidate.sync();
46584
+ await atomicFileTestHooks?.afterLockCreate?.(lockPath);
46585
+ if (await lockTakeoverInProgress(lockPath)) {
46586
+ await candidate.close();
46587
+ await removeOwnedLock(lockPath, [owner]);
46588
+ await removeAbandonedLockTombs(lockPath);
46589
+ if (Date.now() >= deadline) {
46590
+ throw new FileLockedError(options.lockedMessage);
46591
+ }
46592
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
46593
+ continue;
46594
+ }
46595
+ handle = candidate;
46596
+ } catch (error61) {
46597
+ await candidate.close().catch(() => void 0);
46598
+ await removeOwnedLock(lockPath, [owner]).catch(() => void 0);
46599
+ throw error61;
46600
+ }
46601
+ } catch (error61) {
46602
+ if (!hasCode(error61, "EEXIST")) throw error61;
46603
+ await removeStaleLock(lockPath);
46604
+ if (Date.now() >= deadline) {
46605
+ throw new FileLockedError(options.lockedMessage);
46606
+ }
46607
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
46608
+ }
46609
+ }
46610
+ const ownedHandle = handle;
46611
+ const heartbeat = setInterval(() => {
46612
+ const time3 = /* @__PURE__ */ new Date();
46613
+ void ownedHandle.utimes(time3, time3).catch(() => void 0);
46614
+ }, LOCK_HEARTBEAT_MS);
46615
+ heartbeat.unref();
46616
+ try {
46617
+ return await fn();
46618
+ } finally {
46619
+ clearInterval(heartbeat);
46620
+ try {
46621
+ await markLockReleased(ownedHandle, releasedOwner);
46622
+ } finally {
46623
+ try {
46624
+ await ownedHandle.close();
46625
+ } finally {
46626
+ await removeOwnedLock(lockPath, [owner, releasedOwner]);
46627
+ }
46628
+ }
46629
+ }
46630
+ }
46631
+ async function removeStaleLock(path) {
46632
+ try {
46633
+ const owner = await readFile(path, "utf8");
46634
+ if (lockOwnerReleased(owner)) {
46635
+ await removeOwnedLock(path, [owner]);
46636
+ return;
46637
+ }
46638
+ const metadata = await stat(path);
46639
+ if (Date.now() - metadata.mtimeMs <= LOCK_STALE_AFTER_MS) return;
46640
+ const pid = lockOwnerPid(owner);
46641
+ if (pid !== void 0 && processIsAlive(pid)) return;
46642
+ await atomicFileTestHooks?.beforeStaleLockBreak?.(path);
46643
+ await removeOwnedLock(path, [owner]);
46644
+ } catch (error61) {
46645
+ if (!hasCode(error61, "ENOENT")) throw error61;
46646
+ }
46647
+ }
46648
+ async function removeOwnedLock(path, owners) {
46649
+ const tombPath = `${path}.stale.${randomBytes2(16).toString("hex")}`;
46650
+ try {
46651
+ await rename(path, tombPath);
46652
+ } catch (error61) {
46653
+ if (hasCode(error61, "ENOENT")) {
46654
+ await removeOwnedTombs(path, owners);
46655
+ const currentOwner = await readFile(path, "utf8").catch(() => void 0);
46656
+ if (currentOwner !== void 0 && owners.includes(currentOwner)) {
46657
+ await removeOwnedLock(path, owners);
46658
+ }
46659
+ return;
46660
+ }
46661
+ throw error61;
46662
+ }
46663
+ let pendingError;
46664
+ try {
46665
+ const renamedOwner = await readFile(tombPath, "utf8");
46666
+ if (!owners.includes(renamedOwner) && !lockOwnerReleased(renamedOwner)) {
46667
+ await atomicFileTestHooks?.afterMismatchedLockRename?.(path);
46668
+ const currentOwner = await readFile(tombPath, "utf8");
46669
+ if (!lockOwnerReleased(currentOwner)) await restoreRenamedLock(path, tombPath);
46670
+ await atomicFileTestHooks?.afterMismatchedLockRestore?.(path);
46671
+ }
46672
+ } catch (error61) {
46673
+ pendingError = error61;
46674
+ }
46675
+ try {
46676
+ await unlink(tombPath);
46677
+ } catch (error61) {
46678
+ if (!hasCode(error61, "ENOENT") && pendingError === void 0) {
46679
+ pendingError = error61;
46680
+ }
46681
+ }
46682
+ if (pendingError !== void 0) throw pendingError;
46683
+ }
46684
+ async function lockTakeoverInProgress(path) {
46685
+ const prefix = `${basename(path)}.stale.`;
46686
+ return (await readdir(dirname(path))).some((entry) => entry.startsWith(prefix));
46687
+ }
46688
+ async function removeAbandonedLockTombs(path) {
46689
+ const directory = dirname(path);
46690
+ const prefix = `${basename(path)}.stale.`;
46691
+ for (const entry of await readdir(directory)) {
46692
+ if (!entry.startsWith(prefix)) continue;
46693
+ const tombPath = join2(directory, entry);
46694
+ const [metadata, owner] = await Promise.all([
46695
+ stat(tombPath).catch(() => void 0),
46696
+ readFile(tombPath, "utf8").catch(() => void 0)
46697
+ ]);
46698
+ if (metadata === void 0 || owner === void 0) continue;
46699
+ const pid = lockOwnerPid(owner);
46700
+ const abandoned = lockOwnerReleased(owner) || Date.now() - metadata.mtimeMs > LOCK_STALE_AFTER_MS && (pid === void 0 || !processIsAlive(pid));
46701
+ if (!abandoned) continue;
46702
+ await unlink(tombPath).catch((error61) => {
46703
+ if (!hasCode(error61, "ENOENT")) throw error61;
46704
+ });
46705
+ }
46706
+ }
46707
+ async function removeOwnedTombs(path, owners) {
46708
+ const directory = dirname(path);
46709
+ const prefix = `${basename(path)}.stale.`;
46710
+ for (const entry of await readdir(directory)) {
46711
+ if (!entry.startsWith(prefix)) continue;
46712
+ const tombPath = join2(directory, entry);
46713
+ const owner = await readFile(tombPath, "utf8").catch(() => void 0);
46714
+ if (owner === void 0 || !owners.includes(owner)) continue;
46715
+ await unlink(tombPath).catch((error61) => {
46716
+ if (!hasCode(error61, "ENOENT")) throw error61;
46717
+ });
46718
+ }
46719
+ }
46720
+ async function restoreRenamedLock(path, tombPath) {
46721
+ while (true) {
46722
+ try {
46723
+ await link(tombPath, path);
46724
+ return;
46725
+ } catch (error61) {
46726
+ if (hasCode(error61, "ENOENT")) return;
46727
+ if (!hasCode(error61, "EEXIST")) throw error61;
46728
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
46729
+ }
46730
+ }
46731
+ }
46732
+ async function markLockReleased(handle, owner) {
46733
+ const contents = Buffer.from(owner, "utf8");
46734
+ await handle.write(contents, 0, contents.length, 0);
46735
+ await handle.truncate(contents.length);
46736
+ await handle.sync();
46737
+ }
46738
+ function lockOwnerPid(owner) {
46739
+ try {
46740
+ const value = JSON.parse(owner);
46741
+ if (typeof value !== "object" || value === null) return void 0;
46742
+ const pid = Reflect.get(value, "pid");
46743
+ return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
46744
+ } catch {
46745
+ return void 0;
46746
+ }
46747
+ }
46748
+ function lockOwnerReleased(owner) {
46749
+ try {
46750
+ const value = JSON.parse(owner);
46751
+ return typeof value === "object" && value !== null && Reflect.get(value, "released") === true;
46752
+ } catch {
46753
+ return false;
46754
+ }
46755
+ }
46756
+ function processIsAlive(pid) {
46757
+ if (atomicFileTestHooks?.isProcessAlive !== void 0) {
46758
+ return atomicFileTestHooks.isProcessAlive(pid);
46759
+ }
46760
+ try {
46761
+ process.kill(pid, 0);
46762
+ return true;
46763
+ } catch (error61) {
46764
+ return hasCode(error61, "EPERM");
46765
+ }
46766
+ }
46767
+ function hasCode(error61, code) {
46768
+ return error61 instanceof Error && "code" in error61 && error61.code === code;
46769
+ }
46770
+
46552
46771
  // src/x402-networks.ts
46553
46772
  var BASE_MAINNET_CAIP2 = "eip155:8453";
46554
46773
  var ARC_MAINNET_CAIP2 = "eip155:5042";
@@ -46592,6 +46811,205 @@ var BROWSER_ENABLED_X402_NETWORK_CONFIG = Object.freeze({
46592
46811
  [ARC_TESTNET_CAIP2]: browserNetwork(arcTestnetUsdc)
46593
46812
  });
46594
46813
 
46814
+ // src/net-guard.ts
46815
+ import { lookup as dnsLookup } from "node:dns/promises";
46816
+ import { request as httpRequest } from "node:http";
46817
+ import { request as httpsRequest } from "node:https";
46818
+ import { isIP } from "node:net";
46819
+ import { Readable } from "node:stream";
46820
+ var defaultLookup = async (hostname3) => {
46821
+ const addresses = await dnsLookup(hostname3, { all: true });
46822
+ return addresses.map(({ address }) => address);
46823
+ };
46824
+ async function assertPublicUrl(url2, options) {
46825
+ if (url2.username || url2.password) {
46826
+ throw guardError(url2);
46827
+ }
46828
+ if (url2.protocol !== "http:" && url2.protocol !== "https:") {
46829
+ throw guardError(url2);
46830
+ }
46831
+ if (options.allowPrivateNetwork) {
46832
+ return;
46833
+ }
46834
+ const hostname3 = normalizeHostname(url2.hostname);
46835
+ const lowercaseHostname = hostname3.toLowerCase();
46836
+ if (!lowercaseHostname || lowercaseHostname === "localhost" || lowercaseHostname.endsWith(".localhost") || lowercaseHostname.endsWith(".local") || lowercaseHostname.endsWith(".internal")) {
46837
+ throw guardError(url2);
46838
+ }
46839
+ if (isIP(hostname3)) {
46840
+ if (isNonPublicAddress(hostname3)) {
46841
+ throw guardError(url2);
46842
+ }
46843
+ return;
46844
+ }
46845
+ let addresses;
46846
+ try {
46847
+ addresses = await withTimeout(
46848
+ (options.lookup ?? defaultLookup)(hostname3),
46849
+ options.timeoutMs ?? 5e3
46850
+ );
46851
+ } catch {
46852
+ throw guardError(url2);
46853
+ }
46854
+ if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
46855
+ throw guardError(url2);
46856
+ }
46857
+ }
46858
+ function createPublicFetch(options) {
46859
+ const lookupFn = options.lookup ?? defaultLookup;
46860
+ return (async (input2, init) => {
46861
+ const url2 = new URL(input2 instanceof Request ? input2.url : input2);
46862
+ await assertPublicUrl(url2, {
46863
+ allowPrivateNetwork: options.allowPrivateNetwork,
46864
+ lookup: lookupFn,
46865
+ timeoutMs: 5e3
46866
+ });
46867
+ const normalized = new Request(input2, init);
46868
+ const bytes = normalized.body ? Buffer.from(await normalized.arrayBuffer()) : null;
46869
+ return await new Promise((resolve, reject) => {
46870
+ const requestOptions = {
46871
+ method: normalized.method,
46872
+ headers: Object.fromEntries(normalized.headers),
46873
+ signal: normalized.signal,
46874
+ ...options.allowPrivateNetwork ? {} : { lookup: pinnedLookup(lookupFn) }
46875
+ };
46876
+ const onResponse = (incoming) => {
46877
+ try {
46878
+ const headers = new Headers();
46879
+ for (const [name, value] of Object.entries(incoming.headers)) {
46880
+ if (Array.isArray(value)) {
46881
+ for (const item of value) headers.append(name, item);
46882
+ } else if (value !== void 0) {
46883
+ headers.set(name, value);
46884
+ }
46885
+ }
46886
+ const status = incoming.statusCode ?? 500;
46887
+ const bodyForbidden = normalized.method === "HEAD" || [204, 205, 304].includes(status);
46888
+ if (bodyForbidden) incoming.resume();
46889
+ const response = new Response(
46890
+ bodyForbidden ? null : Readable.toWeb(incoming),
46891
+ { status, statusText: incoming.statusMessage, headers }
46892
+ );
46893
+ Object.defineProperty(response, "url", { value: url2.toString() });
46894
+ resolve(response);
46895
+ } catch (error61) {
46896
+ incoming.destroy();
46897
+ reject(error61);
46898
+ }
46899
+ };
46900
+ const request = url2.protocol === "https:" ? httpsRequest(url2, requestOptions, onResponse) : httpRequest(url2, requestOptions, onResponse);
46901
+ request.on("error", reject);
46902
+ if (bytes) request.write(bytes);
46903
+ request.end();
46904
+ });
46905
+ });
46906
+ }
46907
+ function pinnedLookup(lookup) {
46908
+ return (hostname3, dnsOptions, callback) => {
46909
+ void lookup(normalizeHostname(hostname3)).then((addresses) => {
46910
+ if (addresses.length === 0 || addresses.some(isNonPublicAddress)) {
46911
+ callback(guardError(new URL(`https://${hostname3}`)), "");
46912
+ return;
46913
+ }
46914
+ const address = addresses[0];
46915
+ const family = isIP(address);
46916
+ callback(
46917
+ null,
46918
+ dnsOptions.all ? [{ address, family }] : address,
46919
+ dnsOptions.all ? void 0 : family
46920
+ );
46921
+ }).catch(
46922
+ (error61) => callback(error61 instanceof Error ? error61 : new Error("DNS lookup failed."), "")
46923
+ );
46924
+ };
46925
+ }
46926
+ async function withTimeout(operation, timeoutMs) {
46927
+ let timeout;
46928
+ try {
46929
+ return await Promise.race([
46930
+ operation,
46931
+ new Promise((_resolve, reject) => {
46932
+ timeout = setTimeout(() => reject(new Error("DNS lookup timed out.")), timeoutMs);
46933
+ })
46934
+ ]);
46935
+ } finally {
46936
+ if (timeout) clearTimeout(timeout);
46937
+ }
46938
+ }
46939
+ function normalizeHostname(hostname3) {
46940
+ const unbracketed = hostname3.startsWith("[") && hostname3.endsWith("]") ? hostname3.slice(1, -1) : hostname3;
46941
+ return unbracketed.endsWith(".") ? unbracketed.slice(0, -1) : unbracketed;
46942
+ }
46943
+ function isNonPublicAddress(address) {
46944
+ const normalized = normalizeHostname(address);
46945
+ const version3 = isIP(normalized);
46946
+ if (version3 === 4) {
46947
+ return isNonPublicIpv4(parseIpv4(normalized));
46948
+ }
46949
+ if (version3 === 6) {
46950
+ return isNonPublicIpv6(parseIpv6(normalized));
46951
+ }
46952
+ return true;
46953
+ }
46954
+ function parseIpv4(address) {
46955
+ const octets = address.split(".").map(Number);
46956
+ return [octets[0], octets[1], octets[2], octets[3]];
46957
+ }
46958
+ function isNonPublicIpv4([first, second, third]) {
46959
+ 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;
46960
+ }
46961
+ function parseIpv6(address) {
46962
+ let normalized = address.toLowerCase();
46963
+ const lastColon = normalized.lastIndexOf(":");
46964
+ const dottedTail = normalized.slice(lastColon + 1);
46965
+ if (dottedTail.includes(".")) {
46966
+ const [first, second, third, fourth] = parseIpv4(dottedTail);
46967
+ normalized = `${normalized.slice(0, lastColon + 1)}${(first << 8 | second).toString(16)}:${(third << 8 | fourth).toString(16)}`;
46968
+ }
46969
+ const halves = normalized.split("::");
46970
+ const left = halves[0] ? halves[0].split(":").map(parseHex) : [];
46971
+ const right = halves[1] ? halves[1].split(":").map(parseHex) : [];
46972
+ const omittedCount = 8 - left.length - right.length;
46973
+ return halves.length === 2 ? [...left, ...Array.from({ length: omittedCount }, () => 0), ...right] : left;
46974
+ }
46975
+ function parseHex(value) {
46976
+ return Number.parseInt(value, 16);
46977
+ }
46978
+ function isNonPublicIpv6(hextets) {
46979
+ if (hextets.slice(0, 5).every((hextet) => hextet === 0) && hextets[5] === 65535) {
46980
+ const embeddedIpv4 = [
46981
+ hextets[6] >> 8,
46982
+ hextets[6] & 255,
46983
+ hextets[7] >> 8,
46984
+ hextets[7] & 255
46985
+ ];
46986
+ return isNonPublicIpv4(embeddedIpv4);
46987
+ }
46988
+ if (hextets.slice(0, 6).every((hextet) => hextet === 0)) {
46989
+ const compatibleIpv4 = [
46990
+ hextets[6] >> 8,
46991
+ hextets[6] & 255,
46992
+ hextets[7] >> 8,
46993
+ hextets[7] & 255
46994
+ ];
46995
+ if (isNonPublicIpv4(compatibleIpv4)) return true;
46996
+ }
46997
+ const isUnspecified = hextets.every((hextet) => hextet === 0);
46998
+ const isLoopback = hextets.slice(0, 7).every((hextet) => hextet === 0) && hextets[7] === 1;
46999
+ const first = hextets[0];
47000
+ const isUniqueLocal = first >= 64512 && first <= 65023;
47001
+ const isLinkLocal = first >= 65152 && first <= 65215;
47002
+ const isSiteLocal = first >= 65216 && first <= 65279;
47003
+ const isMulticast = first >= 65280;
47004
+ const isDocumentation = first === 8193 && hextets[1] === 3512;
47005
+ return isUnspecified || isLoopback || isUniqueLocal || isLinkLocal || isSiteLocal || isMulticast || isDocumentation;
47006
+ }
47007
+ function guardError(url2) {
47008
+ return new Error(
47009
+ `URL hostname ${JSON.stringify(url2.hostname)} is not allowed; private or internal destinations require allowPrivateNetwork true in the vAPI config.`
47010
+ );
47011
+ }
47012
+
46595
47013
  // src/networks.ts
46596
47014
  var NETWORKS = {
46597
47015
  [BASE_MAINNET_CAIP2]: {
@@ -46667,6 +47085,10 @@ function isSupportedPaymentNetwork(network) {
46667
47085
  var DEFAULT_REGISTRY_URL = "https://api.vapinetwork.ai";
46668
47086
  var DEFAULT_DISCOVERY_URL = `${DEFAULT_REGISTRY_URL}/api/call/services`;
46669
47087
  var DEFAULT_MARKETPLACE_DISCOVERY_URL = `${DEFAULT_REGISTRY_URL}/api/call/discovery`;
47088
+ var DEFAULT_SPEND_CAPS = {
47089
+ perCallAtomic: "100000",
47090
+ perDayAtomic: "1000000"
47091
+ };
46670
47092
  var atomicString = external_exports.string().regex(/^\d+$/, "Expected non-negative atomic units.");
46671
47093
  var spendCapsSchema = external_exports.object({
46672
47094
  perCallAtomic: atomicString,
@@ -46729,22 +47151,22 @@ var configSchema = external_exports.object({
46729
47151
  }
46730
47152
  }
46731
47153
  });
46732
- function getVapiPaths(directory = process.env.VAPI_HOME?.trim() || join2(homedir(), ".vapi")) {
47154
+ function getVapiPaths(directory = process.env.VAPI_HOME?.trim() || join3(homedir(), ".vapi")) {
46733
47155
  return {
46734
47156
  directory,
46735
- agentsDir: join2(directory, "agents"),
46736
- config: join2(directory, "config.json"),
46737
- keystore: join2(directory, "keystore.json"),
46738
- receipts: join2(directory, "receipts.jsonl"),
46739
- searches: join2(directory, "searches.jsonl"),
46740
- ledger: join2(directory, "spend-ledger.json")
47157
+ agentsDir: join3(directory, "agents"),
47158
+ config: join3(directory, "config.json"),
47159
+ keystore: join3(directory, "keystore.json"),
47160
+ receipts: join3(directory, "receipts.jsonl"),
47161
+ searches: join3(directory, "searches.jsonl"),
47162
+ ledger: join3(directory, "spend-ledger.json")
46741
47163
  };
46742
47164
  }
46743
47165
  async function migrateLegacyVapiHome(options = {}) {
46744
47166
  const target = getVapiPaths(options.targetDirectory);
46745
- const legacyDirectory = options.legacyDirectory ?? join2(homedir(), ".vapi", "agent-cash");
47167
+ const legacyDirectory = options.legacyDirectory ?? join3(homedir(), ".vapi", "agent-cash");
46746
47168
  if (legacyDirectory === target.directory || !await pathExists(legacyDirectory)) return [];
46747
- await mkdir(target.directory, { recursive: true, mode: 448 });
47169
+ await mkdir2(target.directory, { recursive: true, mode: 448 });
46748
47170
  const copied = [];
46749
47171
  for (const filename of [
46750
47172
  "config.json",
@@ -46753,10 +47175,17 @@ async function migrateLegacyVapiHome(options = {}) {
46753
47175
  "searches.jsonl",
46754
47176
  "spend-ledger.json"
46755
47177
  ]) {
46756
- const source = join2(legacyDirectory, filename);
46757
- const destination = join2(target.directory, filename);
47178
+ const source = join3(legacyDirectory, filename);
47179
+ const destination = join3(target.directory, filename);
46758
47180
  try {
46759
- await copyFile(source, destination, constants.COPYFILE_EXCL);
47181
+ const copy = async () => await copyFile(source, destination, constants.COPYFILE_EXCL);
47182
+ if (filename === "receipts.jsonl") {
47183
+ await withFileLock(`${destination}.lock`, copy, {
47184
+ lockedMessage: "The receipt journal is busy. Wait for the other vapi command to finish, then retry."
47185
+ });
47186
+ } else {
47187
+ await copy();
47188
+ }
46760
47189
  copied.push(destination);
46761
47190
  } catch (error61) {
46762
47191
  if (isMissingFile(error61) || isAlreadyExists(error61)) continue;
@@ -46772,7 +47201,7 @@ async function migrateLegacyVapiHome(options = {}) {
46772
47201
  }
46773
47202
  async function pathExists(path) {
46774
47203
  try {
46775
- await stat(path);
47204
+ await stat2(path);
46776
47205
  return true;
46777
47206
  } catch (error61) {
46778
47207
  if (isMissingFile(error61)) return false;
@@ -46943,7 +47372,7 @@ function encryptWithKey(key, plaintext) {
46943
47372
  if (key.byteLength !== KEY_LENGTH) {
46944
47373
  throw new Error(`Expected a ${KEY_LENGTH}-byte AES-256-GCM key.`);
46945
47374
  }
46946
- const nonce = randomBytes2(12);
47375
+ const nonce = randomBytes3(12);
46947
47376
  const cipher = createCipheriv("aes-256-gcm", key, nonce, {
46948
47377
  authTagLength: AUTH_TAG_LENGTH
46949
47378
  });
@@ -47027,7 +47456,7 @@ async function sealPlaintext(plaintext, passphrase) {
47027
47456
  if (passphrase.length === 0) {
47028
47457
  throw new KeystoreError("Keystore passphrase cannot be empty.");
47029
47458
  }
47030
- const salt = randomBytes2(32);
47459
+ const salt = randomBytes3(32);
47031
47460
  const key = await deriveScryptKey(passphrase, salt);
47032
47461
  try {
47033
47462
  const sealed = encryptWithKey(key, Buffer.from(plaintext, "utf8"));
@@ -47145,7 +47574,7 @@ async function refuseExistingKeystore(path) {
47145
47574
  await migrateLegacyVapiHome({ targetDirectory: getVapiPaths().directory });
47146
47575
  }
47147
47576
  try {
47148
- await stat2(path);
47577
+ await stat3(path);
47149
47578
  throw new KeystoreError(
47150
47579
  `Keystore already exists at ${path}. Refusing to replace the local payment key.`
47151
47580
  );
@@ -47167,7 +47596,7 @@ function validatePrivateKey(value) {
47167
47596
  async function readStoredKeystore(path) {
47168
47597
  let raw;
47169
47598
  try {
47170
- raw = await readFile2(path, "utf8");
47599
+ raw = await readFile3(path, "utf8");
47171
47600
  } catch (error61) {
47172
47601
  if (isMissingFile(error61)) {
47173
47602
  throw new KeystoreError(`No vAPI keystore found at ${path}. Run vapi init.`);
@@ -47240,8 +47669,8 @@ async function createSolanaSigner(seed) {
47240
47669
  }
47241
47670
  }
47242
47671
  async function writeKeystore(path, keystore, exclusive) {
47243
- await mkdir2(dirname2(path), { recursive: true, mode: 448 });
47244
- const temporaryPath = `${path}.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
47672
+ await mkdir3(dirname3(path), { recursive: true, mode: 448 });
47673
+ const temporaryPath = `${path}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`;
47245
47674
  await writeFile2(temporaryPath, `${JSON.stringify(keystore, null, 2)}
47246
47675
  `, {
47247
47676
  encoding: "utf8",
@@ -47250,7 +47679,7 @@ async function writeKeystore(path, keystore, exclusive) {
47250
47679
  });
47251
47680
  if (exclusive) {
47252
47681
  try {
47253
- await stat2(path);
47682
+ await stat3(path);
47254
47683
  throw new KeystoreError(
47255
47684
  `Keystore already exists at ${path}. Refusing to replace the local payment key.`
47256
47685
  );
@@ -47258,13 +47687,13 @@ async function writeKeystore(path, keystore, exclusive) {
47258
47687
  if (!isMissingFile(error61)) throw error61;
47259
47688
  }
47260
47689
  }
47261
- await rename2(temporaryPath, path);
47690
+ await rename3(temporaryPath, path);
47262
47691
  }
47263
47692
 
47264
47693
  // src/vault.ts
47265
- import { randomBytes as randomBytes3 } from "node:crypto";
47266
- import { mkdir as mkdir3, open as open2, readFile as readFile3, rename as rename3, rm, stat as stat3, unlink, writeFile as writeFile3 } from "node:fs/promises";
47267
- import { dirname as dirname3 } from "node:path";
47694
+ import { randomBytes as randomBytes4 } from "node:crypto";
47695
+ import { mkdir as mkdir4, open as open3, readFile as readFile4, rename as rename4, rm, stat as stat4, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
47696
+ import { dirname as dirname4 } from "node:path";
47268
47697
 
47269
47698
  // src/wallet-name.ts
47270
47699
  var WALLET_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
@@ -47272,6 +47701,9 @@ var walletNameSchema = external_exports.string().regex(
47272
47701
  WALLET_NAME_PATTERN,
47273
47702
  "A wallet name is 1 to 32 characters of lowercase letters, digits and dashes, starting with a letter or digit."
47274
47703
  );
47704
+ function isWalletName(value) {
47705
+ return WALLET_NAME_PATTERN.test(value);
47706
+ }
47275
47707
 
47276
47708
  // src/vault.ts
47277
47709
  var VaultError = class extends Error {
@@ -47590,6 +48022,9 @@ async function exportVaultAccountKey(args) {
47590
48022
  throw asVaultError(error61, "corrupt", "Unable to export the vault account key.");
47591
48023
  }
47592
48024
  }
48025
+ async function exportMemberKey(args) {
48026
+ return await exportVaultAccountKey(args);
48027
+ }
47593
48028
  function assertVaultKey(key) {
47594
48029
  if (key.byteLength !== 32) {
47595
48030
  throw new VaultError("bad_key", "A device vault key must contain exactly 32 bytes.");
@@ -47706,7 +48141,7 @@ async function readVaultFile(path, key) {
47706
48141
  async function readVaultFileUnlocked(path) {
47707
48142
  let raw;
47708
48143
  try {
47709
- raw = await readFile3(path, "utf8");
48144
+ raw = await readFile4(path, "utf8");
47710
48145
  } catch (error61) {
47711
48146
  if (isMissingFile2(error61)) {
47712
48147
  throw new VaultError("not_found", "No vault file was found at the requested path.", {
@@ -47718,8 +48153,8 @@ async function readVaultFileUnlocked(path) {
47718
48153
  return parseVaultFile(raw);
47719
48154
  }
47720
48155
  async function writeVaultFile(path, file2) {
47721
- await mkdir3(dirname3(path), { recursive: true, mode: 448 });
47722
- const temporaryPath = `${path}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`;
48156
+ await mkdir4(dirname4(path), { recursive: true, mode: 448 });
48157
+ const temporaryPath = `${path}.${process.pid}.${randomBytes4(6).toString("hex")}.tmp`;
47723
48158
  try {
47724
48159
  await writeFile3(temporaryPath, `${JSON.stringify(file2, null, 2)}
47725
48160
  `, {
@@ -47727,20 +48162,20 @@ async function writeVaultFile(path, file2) {
47727
48162
  mode: 384,
47728
48163
  flag: "wx"
47729
48164
  });
47730
- await rename3(temporaryPath, path);
48165
+ await rename4(temporaryPath, path);
47731
48166
  } catch (error61) {
47732
48167
  await rm(temporaryPath, { force: true }).catch(() => void 0);
47733
48168
  throw error61;
47734
48169
  }
47735
48170
  }
47736
48171
  async function withVaultLock(path, operation) {
47737
- await mkdir3(dirname3(path), { recursive: true, mode: 448 });
48172
+ await mkdir4(dirname4(path), { recursive: true, mode: 448 });
47738
48173
  const lockPath = `${path}.lock`;
47739
48174
  const deadline = Date.now() + VAULT_LOCK_TIMEOUT_MS;
47740
48175
  let handle;
47741
48176
  while (!handle) {
47742
48177
  try {
47743
- handle = await open2(lockPath, "wx", 384);
48178
+ handle = await open3(lockPath, "wx", 384);
47744
48179
  } catch (error61) {
47745
48180
  if (!isExistingFile(error61)) throw error61;
47746
48181
  await removeStaleVaultLock(lockPath);
@@ -47754,13 +48189,13 @@ async function withVaultLock(path, operation) {
47754
48189
  return await operation();
47755
48190
  } finally {
47756
48191
  await handle.close();
47757
- await unlink(lockPath).catch(() => void 0);
48192
+ await unlink2(lockPath).catch(() => void 0);
47758
48193
  }
47759
48194
  }
47760
48195
  async function removeStaleVaultLock(path) {
47761
48196
  try {
47762
- const metadata = await stat3(path);
47763
- if (Date.now() - metadata.mtimeMs > STALE_VAULT_LOCK_MS) await unlink(path);
48197
+ const metadata = await stat4(path);
48198
+ if (Date.now() - metadata.mtimeMs > STALE_VAULT_LOCK_MS) await unlink2(path);
47764
48199
  } catch (error61) {
47765
48200
  if (!isMissingFile2(error61)) throw error61;
47766
48201
  }
@@ -47774,12 +48209,413 @@ function isExistingFile(error61) {
47774
48209
  function asVaultError(error61, code, message) {
47775
48210
  return error61 instanceof VaultError ? error61 : new VaultError(code, message, { cause: error61 });
47776
48211
  }
48212
+
48213
+ // src/device.ts
48214
+ var DEVICE_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,31}$/;
48215
+
48216
+ // src/agent-link.ts
48217
+ var DEFAULT_AGENT_SCOPES = ["mcp:call", "router.use"];
48218
+ var ALLOWED_AGENT_SCOPES = /* @__PURE__ */ new Set([...DEFAULT_AGENT_SCOPES, "call.publish"]);
48219
+ var publicFetch = createPublicFetch({ allowPrivateNetwork: false });
48220
+ var agentSecretAccounts = (wallet) => ({
48221
+ tokens: `vapi.agent.${wallet}.tokens`,
48222
+ routerStake: `vapi.agent.${wallet}.router.stake`,
48223
+ routerBalance: `vapi.agent.${wallet}.router.balance`
48224
+ });
48225
+
48226
+ // src/agent-profile.ts
48227
+ var DEFAULT_AGENT_TOOLS = ["call.search", "call.inspect", "call.pay"];
48228
+ var AGENT_GRANTS = ["read", "delegate", "allocate"];
48229
+ var agentProfileShape = {
48230
+ version: external_exports.literal(1),
48231
+ name: walletNameSchema,
48232
+ wallet: external_exports.string(),
48233
+ model: external_exports.string().min(1),
48234
+ instructions: external_exports.string().max(2e4),
48235
+ verifiedOnly: external_exports.boolean().default(true),
48236
+ approveAboveUsd: external_exports.number().min(0).default(0.5),
48237
+ maxSteps: external_exports.number().int().min(1).max(50).default(12),
48238
+ paused: external_exports.boolean().default(false),
48239
+ grants: external_exports.array(external_exports.enum(AGENT_GRANTS)).default([]),
48240
+ createdAt: external_exports.string()
48241
+ };
48242
+ function createAgentProfileSchema(toolNames) {
48243
+ if (toolNames.length === 0) {
48244
+ throw new Error("Agent profiles require at least one registered tool.");
48245
+ }
48246
+ const tools = [...toolNames];
48247
+ return external_exports.object({ ...agentProfileShape, tools: external_exports.array(external_exports.enum(tools)).default(tools) });
48248
+ }
48249
+ var agentProfileSchema = createAgentProfileSchema(DEFAULT_AGENT_TOOLS);
48250
+
48251
+ // src/agent-run.ts
48252
+ var RUN_ID_PATTERN = /^run_[0-9a-f]{24}$/;
48253
+ var runRefSchema = external_exports.strictObject({
48254
+ id: external_exports.string().regex(RUN_ID_PATTERN),
48255
+ swarm: external_exports.string().optional(),
48256
+ member: external_exports.string().optional(),
48257
+ parentRunId: external_exports.string().optional()
48258
+ });
48259
+
48260
+ // src/swarm.ts
48261
+ var SWARM_NAME_PATTERN = /^[a-z][a-z0-9-]{0,15}$/;
48262
+ var SWARM_ROLE_PATTERN = /^[a-z][a-z0-9]{0,7}$/;
48263
+ var atomicSchema = external_exports.string().regex(/^\d+$/);
48264
+ var addressSchema2 = external_exports.string().regex(/^0x[0-9a-fA-F]{40}$/);
48265
+ var capsSchema = external_exports.strictObject({ perCallAtomic: atomicSchema, perDayAtomic: atomicSchema });
48266
+ var movementIdSchema = external_exports.string().regex(/^mv_[A-Za-z0-9_-]{8,128}$/u);
48267
+ var amountUsdSchema = external_exports.string().regex(/^\d+\.\d{2}$/u);
48268
+ var setupFundingStatusSchema = external_exports.enum(["planned", "sent", "incomplete"]);
48269
+ var blockedFundingLegSchema = external_exports.strictObject({
48270
+ to: external_exports.string().trim().min(1),
48271
+ amountUsd: amountUsdSchema,
48272
+ reason: external_exports.string().trim().min(1)
48273
+ });
48274
+ var setupFundingSchema = external_exports.strictObject({
48275
+ amountUsd: amountUsdSchema,
48276
+ from: walletNameSchema,
48277
+ movementId: movementIdSchema.optional(),
48278
+ status: setupFundingStatusSchema,
48279
+ policy: external_exports.strictObject({
48280
+ strategy: external_exports.enum(["targets", "even", "weights"]),
48281
+ movementId: movementIdSchema.optional(),
48282
+ status: setupFundingStatusSchema,
48283
+ blocked: external_exports.array(blockedFundingLegSchema).optional()
48284
+ }).optional()
48285
+ });
48286
+ var accountSteps = {
48287
+ creating: external_exports.boolean().default(false),
48288
+ created: external_exports.boolean(),
48289
+ capped: external_exports.boolean(),
48290
+ linked: external_exports.boolean()
48291
+ };
48292
+ var treasurySchema = external_exports.strictObject({
48293
+ account: walletNameSchema,
48294
+ // A planned account has no address until its vault derivation succeeds.
48295
+ address: addressSchema2.optional(),
48296
+ steps: external_exports.strictObject(accountSteps)
48297
+ }).refine(
48298
+ (value) => !value.steps.created || value.address !== void 0,
48299
+ "Created accounts require an address."
48300
+ );
48301
+ var memberSchema = external_exports.strictObject({
48302
+ account: walletNameSchema,
48303
+ address: addressSchema2.optional(),
48304
+ role: external_exports.string().regex(SWARM_ROLE_PATTERN),
48305
+ weight: external_exports.number().int().positive(),
48306
+ targetAtomic: atomicSchema,
48307
+ ceilingAtomic: atomicSchema.nullable(),
48308
+ steps: external_exports.strictObject({ ...accountSteps, profiled: external_exports.boolean() })
48309
+ }).refine(
48310
+ (value) => !value.steps.created || value.address !== void 0,
48311
+ "Created accounts require an address."
48312
+ );
48313
+ var swarmFileSchema = external_exports.strictObject({
48314
+ v: external_exports.literal(1),
48315
+ name: external_exports.string().regex(SWARM_NAME_PATTERN),
48316
+ device: external_exports.string().regex(DEVICE_NAME_PATTERN),
48317
+ network: external_exports.enum([BASE_MAINNET_CAIP2, ARC_MAINNET_CAIP2]),
48318
+ createdAt: external_exports.iso.datetime(),
48319
+ treasury: treasurySchema,
48320
+ members: external_exports.array(memberSchema),
48321
+ setupFunding: setupFundingSchema.optional(),
48322
+ policy: external_exports.strictObject({
48323
+ strategy: external_exports.enum(["targets", "even", "weights"]),
48324
+ treasuryCaps: capsSchema
48325
+ })
48326
+ }).refine(
48327
+ (value) => (/* @__PURE__ */ new Set([value.treasury.account, ...value.members.map((member) => member.account)])).size === value.members.length + 1,
48328
+ "Swarm accounts must be unique."
48329
+ );
48330
+
48331
+ // src/member-bundle.ts
48332
+ var MEMBER_BUNDLE_MAX_BYTES = 32 * 1024;
48333
+ var REMOTE_BLOCKED_GRANTS = /* @__PURE__ */ new Set([
48334
+ "delegate",
48335
+ "allocate"
48336
+ ]);
48337
+ var BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
48338
+ var ADDRESS_PATTERN2 = /^0x[0-9a-fA-F]{40}$/;
48339
+ var PRIVATE_KEY_PATTERN = /^0x[0-9a-fA-F]{64}$/;
48340
+ var ATOMIC_PATTERN = /^\d+$/;
48341
+ var FORBIDDEN_CONFIG_KEYS = /* @__PURE__ */ new Set(["rpcUrl", "apiKey"]);
48342
+ var MemberBundleError = class extends Error {
48343
+ constructor(code, message) {
48344
+ super(message);
48345
+ this.code = code;
48346
+ this.name = "MemberBundleError";
48347
+ }
48348
+ code;
48349
+ };
48350
+ var hexString = (pattern, message) => external_exports.custom((value) => typeof value === "string" && pattern.test(value), message);
48351
+ var linkSchema = external_exports.strictObject({
48352
+ apiBase: external_exports.string(),
48353
+ clientId: external_exports.string(),
48354
+ owner: external_exports.custom((value) => typeof value === "string" && value.startsWith("0x")),
48355
+ label: external_exports.string(),
48356
+ scopes: external_exports.array(external_exports.string()),
48357
+ linkedAt: external_exports.iso.datetime(),
48358
+ routerBaseUrl: external_exports.string().optional()
48359
+ });
48360
+ var remoteTokensSchema = external_exports.strictObject({
48361
+ accessToken: external_exports.string().min(1),
48362
+ expiresAt: external_exports.number().finite(),
48363
+ scopes: external_exports.array(external_exports.string()),
48364
+ refreshable: external_exports.literal(false)
48365
+ });
48366
+ var storedTokensSchema = external_exports.object({
48367
+ accessToken: external_exports.string().min(1),
48368
+ refreshToken: external_exports.string().min(1),
48369
+ expiresAt: external_exports.number().finite(),
48370
+ scopes: external_exports.array(external_exports.string())
48371
+ });
48372
+ var credentialsSchema = external_exports.strictObject({
48373
+ tokens: external_exports.string().min(1).refine(isRemoteTokens, "A member bundle carries a non-refreshable access token only."),
48374
+ routerStake: external_exports.string().min(1).optional(),
48375
+ routerBalance: external_exports.string().min(1).optional()
48376
+ });
48377
+ var remoteProfileSchema = agentProfileSchema.strict().refine((profile) => profile.grants.every((grant) => !REMOTE_BLOCKED_GRANTS.has(grant)), {
48378
+ message: "A remote member never holds the delegate or allocate grant.",
48379
+ path: ["grants"]
48380
+ });
48381
+ var credentialFreeUrl = external_exports.url().refine((value) => unsafeUrlPart(value) === void 0, {
48382
+ message: "A member bundle URL never carries a user name, password, query or fragment."
48383
+ });
48384
+ var memberBundleConfigSchema = external_exports.unknown().refine((value) => !hasForbiddenConfigKey(value), {
48385
+ message: "A member bundle never carries RPC URLs or API keys."
48386
+ }).pipe(
48387
+ external_exports.strictObject({
48388
+ discoveryUrl: credentialFreeUrl,
48389
+ marketplaceDiscoveryUrl: credentialFreeUrl,
48390
+ networks: external_exports.record(
48391
+ external_exports.string().refine(isMemberBundleNetwork, {
48392
+ message: "Expected a network with a public RPC default."
48393
+ }),
48394
+ external_exports.strictObject({ usdc: external_exports.string() })
48395
+ ).refine(
48396
+ (networks) => Object.entries(networks).every(
48397
+ ([id, network]) => isMemberBundleNetwork(id) && network.usdc === NETWORKS[id].usdc
48398
+ ),
48399
+ { message: "Expected the canonical USDC token of each network." }
48400
+ ).refine((networks) => Object.keys(networks).length === 1, {
48401
+ message: "A member bundle carries exactly one network: the swarm's."
48402
+ })
48403
+ })
48404
+ );
48405
+ var memberBundleSchema = external_exports.strictObject({
48406
+ v: external_exports.literal(1),
48407
+ account: walletNameSchema,
48408
+ address: hexString(ADDRESS_PATTERN2, "Expected a 20-byte 0x address."),
48409
+ privateKey: hexString(PRIVATE_KEY_PATTERN, "Expected a 32-byte 0x private key."),
48410
+ swarm: external_exports.string().regex(SWARM_NAME_PATTERN),
48411
+ profile: remoteProfileSchema,
48412
+ link: linkSchema,
48413
+ credentials: credentialsSchema,
48414
+ caps: external_exports.strictObject(spendCapsSchema.shape),
48415
+ allowanceExpiresAt: external_exports.iso.datetime(),
48416
+ ceilingAtomic: external_exports.string().regex(ATOMIC_PATTERN, "Expected non-negative atomic units."),
48417
+ config: memberBundleConfigSchema,
48418
+ runId: external_exports.string().regex(RUN_ID_PATTERN),
48419
+ parentRunId: external_exports.string().regex(RUN_ID_PATTERN).optional()
48420
+ });
48421
+ function memberBundleConfig(owner, network) {
48422
+ const discoveryUrl = safeDiscoveryUrl("discoveryUrl", owner.discoveryUrl);
48423
+ const marketplaceDiscoveryUrl = safeDiscoveryUrl(
48424
+ "marketplaceDiscoveryUrl",
48425
+ owner.marketplaceDiscoveryUrl
48426
+ );
48427
+ if (!Object.hasOwn(owner.networks, network) || !isMemberBundleNetwork(network)) {
48428
+ throw new MemberBundleError(
48429
+ "unsupported_network",
48430
+ `A member bundle runs on the swarm network ${network}, which must be enabled in this config and have a public RPC default.`
48431
+ );
48432
+ }
48433
+ return {
48434
+ discoveryUrl,
48435
+ marketplaceDiscoveryUrl,
48436
+ networks: { [network]: { usdc: NETWORKS[network].usdc } }
48437
+ };
48438
+ }
48439
+ function headlessConfigFromBundle(config2) {
48440
+ const networks = {};
48441
+ for (const [id, network] of Object.entries(config2.networks)) {
48442
+ if (!isMemberBundleNetwork(id) || network === void 0) continue;
48443
+ networks[id] = { rpcUrl: NETWORKS[id].publicRpcUrl, usdc: network.usdc };
48444
+ }
48445
+ return configSchema.parse({
48446
+ discoveryUrl: config2.discoveryUrl,
48447
+ marketplaceDiscoveryUrl: config2.marketplaceDiscoveryUrl,
48448
+ networks,
48449
+ spendCaps: { ...DEFAULT_SPEND_CAPS }
48450
+ });
48451
+ }
48452
+ function createMemberBundle(input2) {
48453
+ const bundle = parseBundle({ ...input2, profile: withoutRemoteGrants(input2.profile), v: 1 });
48454
+ assertKeyMatchesAddress(bundle);
48455
+ const encoded = Buffer.from(JSON.stringify(bundle), "utf8").toString("base64url");
48456
+ if (encoded.length > MEMBER_BUNDLE_MAX_BYTES) {
48457
+ throw new MemberBundleError(
48458
+ "too_large",
48459
+ `The member bundle is larger than ${MEMBER_BUNDLE_MAX_BYTES} bytes.`
48460
+ );
48461
+ }
48462
+ return encoded;
48463
+ }
48464
+ function openMemberBundle(text) {
48465
+ if (typeof text !== "string") {
48466
+ throw new MemberBundleError("invalid", "The member bundle is not a string.");
48467
+ }
48468
+ if (text.length > MEMBER_BUNDLE_MAX_BYTES) {
48469
+ throw new MemberBundleError(
48470
+ "too_large",
48471
+ `The member bundle is larger than ${MEMBER_BUNDLE_MAX_BYTES} bytes.`
48472
+ );
48473
+ }
48474
+ if (!BASE64URL_PATTERN.test(text)) {
48475
+ throw new MemberBundleError("invalid", "The member bundle is not base64url text.");
48476
+ }
48477
+ let decoded;
48478
+ try {
48479
+ decoded = JSON.parse(Buffer.from(text, "base64url").toString("utf8"));
48480
+ } catch {
48481
+ throw new MemberBundleError("invalid", "The member bundle does not decode to JSON.");
48482
+ }
48483
+ const bundle = parseBundle(decoded);
48484
+ assertKeyMatchesAddress(bundle);
48485
+ return bundle;
48486
+ }
48487
+ async function readMemberCredentials(args) {
48488
+ if (!isWalletName(args.account)) {
48489
+ throw new MemberBundleError("invalid", "The member account name is not valid.");
48490
+ }
48491
+ const names = agentSecretAccounts(args.account);
48492
+ const storedTokens = await args.secrets.get(names.tokens);
48493
+ if (storedTokens === void 0 || storedTokens === "") {
48494
+ throw new MemberBundleError(
48495
+ "not_linked",
48496
+ `The account ${args.account} is not linked to vAPI. Link it with vapi login first.`
48497
+ );
48498
+ }
48499
+ const routerStake = await args.secrets.get(names.routerStake);
48500
+ const routerBalance = await args.secrets.get(names.routerBalance);
48501
+ const parsed = parseStoredTokens(storedTokens);
48502
+ if (parsed === void 0) {
48503
+ throw new MemberBundleError(
48504
+ "not_linked",
48505
+ `The account ${args.account}'s vAPI credentials cannot be exported safely. Run vapi login --account ${args.account} again.`
48506
+ );
48507
+ }
48508
+ const tokens = JSON.stringify({
48509
+ accessToken: parsed.accessToken,
48510
+ expiresAt: parsed.expiresAt,
48511
+ scopes: parsed.scopes,
48512
+ refreshable: false
48513
+ });
48514
+ return {
48515
+ tokens,
48516
+ ...routerStake === void 0 || routerStake === "" ? {} : { routerStake },
48517
+ ...routerBalance === void 0 || routerBalance === "" ? {} : { routerBalance }
48518
+ };
48519
+ }
48520
+ function isRemoteTokens(value) {
48521
+ try {
48522
+ return remoteTokensSchema.safeParse(JSON.parse(value)).success;
48523
+ } catch {
48524
+ return false;
48525
+ }
48526
+ }
48527
+ function parseStoredTokens(value) {
48528
+ try {
48529
+ const parsed = storedTokensSchema.safeParse(JSON.parse(value));
48530
+ return parsed.success ? parsed.data : void 0;
48531
+ } catch {
48532
+ return void 0;
48533
+ }
48534
+ }
48535
+ function isMemberBundleNetwork(id) {
48536
+ return Object.hasOwn(NETWORKS, id) && typeof NETWORKS[id].publicRpcUrl === "string";
48537
+ }
48538
+ function hasForbiddenConfigKey(value) {
48539
+ if (Array.isArray(value)) return value.some(hasForbiddenConfigKey);
48540
+ if (typeof value !== "object" || value === null) return false;
48541
+ return Object.entries(value).some(
48542
+ ([key, item]) => FORBIDDEN_CONFIG_KEYS.has(key) || hasForbiddenConfigKey(item)
48543
+ );
48544
+ }
48545
+ function unsafeUrlPart(value) {
48546
+ let url2;
48547
+ try {
48548
+ url2 = new URL(value);
48549
+ } catch {
48550
+ return "an unparseable value";
48551
+ }
48552
+ if (url2.username !== "" || url2.password !== "") return "a user name or password";
48553
+ if (url2.search !== "" || value.includes("?")) return "a query string";
48554
+ if (url2.hash !== "" || value.includes("#")) return "a fragment";
48555
+ return void 0;
48556
+ }
48557
+ function safeDiscoveryUrl(field, value) {
48558
+ const part = unsafeUrlPart(value);
48559
+ if (part !== void 0) {
48560
+ throw new MemberBundleError(
48561
+ "unsafe_config",
48562
+ `The owner config's ${field} has ${part}, which can carry a credential, so it never goes into a member bundle. Point ${field} at a plain URL (check VAPI_DISCOVERY_URL, VAPI_MARKETPLACE_DISCOVERY_URL and config.json).`
48563
+ );
48564
+ }
48565
+ return value;
48566
+ }
48567
+ function withoutRemoteGrants(profile) {
48568
+ if (typeof profile !== "object" || profile === null || !Array.isArray(profile.grants)) {
48569
+ return profile;
48570
+ }
48571
+ return {
48572
+ ...profile,
48573
+ grants: profile.grants.filter((grant) => !REMOTE_BLOCKED_GRANTS.has(grant))
48574
+ };
48575
+ }
48576
+ function parseBundle(value) {
48577
+ const parsed = memberBundleSchema.safeParse(value);
48578
+ if (!parsed.success) {
48579
+ const fields = [
48580
+ ...new Set(parsed.error.issues.map((issue2) => issue2.path.map(String).join(".") || "(root)"))
48581
+ ];
48582
+ throw new MemberBundleError(
48583
+ "invalid",
48584
+ `The member bundle is not valid (fields: ${fields.join(", ")}).`
48585
+ );
48586
+ }
48587
+ return parsed.data;
48588
+ }
48589
+ function assertKeyMatchesAddress(bundle) {
48590
+ let derived;
48591
+ try {
48592
+ derived = privateKeyToAccount(bundle.privateKey).address;
48593
+ } catch {
48594
+ throw new MemberBundleError("key_mismatch", "The member bundle's key is not a valid key.");
48595
+ }
48596
+ if (derived.toLowerCase() !== bundle.address.toLowerCase()) {
48597
+ throw new MemberBundleError(
48598
+ "key_mismatch",
48599
+ "The member bundle's key does not match its address."
48600
+ );
48601
+ }
48602
+ }
47777
48603
  export {
48604
+ MEMBER_BUNDLE_MAX_BYTES,
48605
+ MemberBundleError,
47778
48606
  createKeystoreWithPhrase,
48607
+ createMemberBundle,
47779
48608
  decryptPrivateKey,
47780
48609
  exportKeystoreKeys,
48610
+ exportMemberKey,
47781
48611
  exportRecoveryPhrase,
47782
48612
  exportVaultAccountKey,
47783
- exportVaultPhrase
48613
+ exportVaultPhrase,
48614
+ headlessConfigFromBundle,
48615
+ memberBundleConfig,
48616
+ memberBundleConfigSchema,
48617
+ memberBundleSchema,
48618
+ openMemberBundle,
48619
+ readMemberCredentials
47784
48620
  };
47785
48621
  //# sourceMappingURL=secrets.js.map