@dominusnode/ai-tools 1.2.0 → 1.5.2

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/tools.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { tool } from "ai";
2
2
  import { z } from "zod";
3
+ import * as crypto from "node:crypto";
3
4
  import dns from "dns/promises";
4
5
  import * as http from "node:http";
5
6
  import * as tls from "node:tls";
@@ -73,11 +74,66 @@ function isPrivateIp(hostname) {
73
74
  return true;
74
75
  return false;
75
76
  }
77
+ // ---------------------------------------------------------------------------
78
+ // SHA-256 Proof-of-Work solver
79
+ // ---------------------------------------------------------------------------
80
+ function countLeadingZeroBits(buf) {
81
+ let count = 0;
82
+ for (const byte of buf) {
83
+ if (byte === 0) {
84
+ count += 8;
85
+ continue;
86
+ }
87
+ let mask = 0x80;
88
+ while (mask && !(byte & mask)) {
89
+ count++;
90
+ mask >>= 1;
91
+ }
92
+ break;
93
+ }
94
+ return count;
95
+ }
96
+ async function solvePoW(powBaseUrl) {
97
+ try {
98
+ const resp = await fetch(`${powBaseUrl}/api/auth/pow/challenge`, {
99
+ method: "POST",
100
+ headers: { "Content-Type": "application/json" },
101
+ redirect: "error",
102
+ });
103
+ if (!resp.ok)
104
+ return null;
105
+ const text = await resp.text();
106
+ if (text.length > 10_485_760)
107
+ return null;
108
+ const challenge = JSON.parse(text);
109
+ const prefix = challenge.prefix ?? "";
110
+ const difficulty = challenge.difficulty ?? 20;
111
+ const challengeId = challenge.challengeId ?? "";
112
+ if (!prefix || !challengeId)
113
+ return null;
114
+ for (let nonce = 0; nonce < 100_000_000; nonce++) {
115
+ const hash = crypto
116
+ .createHash("sha256")
117
+ .update(prefix + nonce.toString())
118
+ .digest();
119
+ if (countLeadingZeroBits(hash) >= difficulty) {
120
+ return { challengeId, nonce: nonce.toString() };
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
76
129
  /** Validate a URL is safe to fetch through the proxy. */
77
130
  function validateUrl(urlStr) {
78
131
  // Length limit
79
132
  if (urlStr.length > 2048) {
80
- return { valid: false, error: "URL exceeds maximum length of 2048 characters" };
133
+ return {
134
+ valid: false,
135
+ error: "URL exceeds maximum length of 2048 characters",
136
+ };
81
137
  }
82
138
  let url;
83
139
  try {
@@ -88,7 +144,10 @@ function validateUrl(urlStr) {
88
144
  }
89
145
  // Protocol check — only http(s)
90
146
  if (url.protocol !== "http:" && url.protocol !== "https:") {
91
- return { valid: false, error: `Unsupported protocol: ${url.protocol} — only http and https are allowed` };
147
+ return {
148
+ valid: false,
149
+ error: `Unsupported protocol: ${url.protocol} — only http and https are allowed`,
150
+ };
92
151
  }
93
152
  // Hostname must be present
94
153
  if (!url.hostname) {
@@ -103,16 +162,27 @@ function validateUrl(urlStr) {
103
162
  return { valid: false, error: "Requests to localhost are not allowed" };
104
163
  }
105
164
  // Block internal network TLDs
106
- if (lowerHost.endsWith(".local") || lowerHost.endsWith(".internal") || lowerHost.endsWith(".arpa")) {
107
- return { valid: false, error: "Requests to internal network hostnames are not allowed" };
165
+ if (lowerHost.endsWith(".local") ||
166
+ lowerHost.endsWith(".internal") ||
167
+ lowerHost.endsWith(".arpa")) {
168
+ return {
169
+ valid: false,
170
+ error: "Requests to internal network hostnames are not allowed",
171
+ };
108
172
  }
109
173
  // Block private/reserved IPs
110
174
  if (isPrivateIp(url.hostname)) {
111
- return { valid: false, error: "Requests to private/reserved IP addresses are not allowed" };
175
+ return {
176
+ valid: false,
177
+ error: "Requests to private/reserved IP addresses are not allowed",
178
+ };
112
179
  }
113
180
  // Block credentials in URL (user:pass@host)
114
181
  if (url.username || url.password) {
115
- return { valid: false, error: "URLs with embedded credentials are not allowed" };
182
+ return {
183
+ valid: false,
184
+ error: "URLs with embedded credentials are not allowed",
185
+ };
116
186
  }
117
187
  return { valid: true, url };
118
188
  }
@@ -122,7 +192,8 @@ const MAX_BODY_LENGTH = 4000;
122
192
  function truncateBody(body) {
123
193
  if (body.length <= MAX_BODY_LENGTH)
124
194
  return body;
125
- return body.slice(0, MAX_BODY_LENGTH) + `\n...[truncated, ${body.length - MAX_BODY_LENGTH} chars omitted]`;
195
+ return (body.slice(0, MAX_BODY_LENGTH) +
196
+ `\n...[truncated, ${body.length - MAX_BODY_LENGTH} chars omitted]`);
126
197
  }
127
198
  // ---------------------------------------------------------------------------
128
199
  // Safe header subset — never forward sensitive headers to the AI
@@ -197,7 +268,7 @@ async function checkDnsRebinding(hostname) {
197
268
  // ---------------------------------------------------------------------------
198
269
  // Credential sanitization for error messages
199
270
  // ---------------------------------------------------------------------------
200
- const CREDENTIAL_RE = /dn_(live|test)_[a-zA-Z0-9]+|eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g;
271
+ const CREDENTIAL_RE = /dn_(live|test|proxy)_[a-zA-Z0-9]+|eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g;
201
272
  function sanitizeError(message) {
202
273
  return message.replace(CREDENTIAL_RE, "***");
203
274
  }
@@ -245,7 +316,11 @@ export function createProxiedFetchTool(client, apiKey) {
245
316
  "Supports geo-targeting by country and choice of datacenter (dc) or residential proxy. " +
246
317
  "Use this to fetch web pages, APIs, or any HTTP resource through a proxy IP.",
247
318
  parameters: z.object({
248
- url: z.string().max(2048).url().describe("The URL to fetch through the proxy"),
319
+ url: z
320
+ .string()
321
+ .max(2048)
322
+ .url()
323
+ .describe("The URL to fetch through the proxy"),
249
324
  method: z
250
325
  .enum(["GET", "HEAD", "OPTIONS"])
251
326
  .default("GET")
@@ -264,7 +339,7 @@ export function createProxiedFetchTool(client, apiKey) {
264
339
  .optional()
265
340
  .describe("Optional HTTP headers to include in the request"),
266
341
  }),
267
- execute: async ({ url, method, country, proxyType, headers }) => {
342
+ execute: async ({ url, method, country, proxyType, headers, }) => {
268
343
  // SSRF validation
269
344
  const validation = validateUrl(url);
270
345
  if (!validation.valid) {
@@ -272,14 +347,18 @@ export function createProxiedFetchTool(client, apiKey) {
272
347
  }
273
348
  // OFAC sanctioned country check
274
349
  if (country && SANCTIONED_COUNTRIES.has(country.toUpperCase())) {
275
- return { error: `Country '${country.toUpperCase()}' is blocked (OFAC sanctioned)` };
350
+ return {
351
+ error: `Country '${country.toUpperCase()}' is blocked (OFAC sanctioned)`,
352
+ };
276
353
  }
277
354
  // DNS rebinding protection
278
355
  try {
279
356
  await checkDnsRebinding(validation.url.hostname);
280
357
  }
281
358
  catch (err) {
282
- return { error: err instanceof Error ? err.message : "DNS validation failed" };
359
+ return {
360
+ error: err instanceof Error ? err.message : "DNS validation failed",
361
+ };
283
362
  }
284
363
  // Build the proxy URL using the SDK
285
364
  const proxyUrl = client.proxy.buildUrl(apiKey, {
@@ -293,12 +372,22 @@ export function createProxiedFetchTool(client, apiKey) {
293
372
  const proxyAuth = "Basic " +
294
373
  Buffer.from(`${proxyUrlObj.username}:${proxyUrlObj.password}`).toString("base64");
295
374
  // Validate custom headers for CRLF injection
296
- const STRIPPED_HEADERS = new Set(["host", "connection", "content-length", "transfer-encoding", "proxy-authorization", "authorization", "user-agent"]);
375
+ const STRIPPED_HEADERS = new Set([
376
+ "host",
377
+ "connection",
378
+ "content-length",
379
+ "transfer-encoding",
380
+ "proxy-authorization",
381
+ "authorization",
382
+ "user-agent",
383
+ ]);
297
384
  const safeHeaders = {};
298
385
  if (headers) {
299
386
  for (const [k, v] of Object.entries(headers)) {
300
387
  if (/[\r\n\0]/.test(k) || /[\r\n\0]/.test(v)) {
301
- return { error: `Header "${k.replace(/[\r\n\0]/g, "")}" contains invalid characters` };
388
+ return {
389
+ error: `Header "${k.replace(/[\r\n\0]/g, "")}" contains invalid characters`,
390
+ };
302
391
  }
303
392
  if (!STRIPPED_HEADERS.has(k.toLowerCase())) {
304
393
  safeHeaders[k] = v;
@@ -309,14 +398,23 @@ export function createProxiedFetchTool(client, apiKey) {
309
398
  const MAX_RESP = 1_048_576; // 1MB
310
399
  const result = await new Promise((resolve, reject) => {
311
400
  const timer = setTimeout(() => reject(new Error("Proxy request timed out")), 30_000);
312
- const customHeaderLines = Object.entries(safeHeaders).map(([k, v]) => `${k}: ${v}\r\n`).join("");
401
+ const customHeaderLines = Object.entries(safeHeaders)
402
+ .map(([k, v]) => `${k}: ${v}\r\n`)
403
+ .join("");
313
404
  if (targetUrl.protocol === "https:") {
314
405
  // HTTPS: use CONNECT tunnel through proxy
315
- const connectHost = targetUrl.hostname.includes(":") ? `[${targetUrl.hostname}]` : targetUrl.hostname;
406
+ const connectHost = targetUrl.hostname.includes(":")
407
+ ? `[${targetUrl.hostname}]`
408
+ : targetUrl.hostname;
316
409
  const connectReq = http.request({
317
- hostname: proxyHost, port: proxyPort, method: "CONNECT",
410
+ hostname: proxyHost,
411
+ port: proxyPort,
412
+ method: "CONNECT",
318
413
  path: `${connectHost}:${targetUrl.port || 443}`,
319
- headers: { "Proxy-Authorization": proxyAuth, Host: `${connectHost}:${targetUrl.port || 443}` },
414
+ headers: {
415
+ "Proxy-Authorization": proxyAuth,
416
+ Host: `${connectHost}:${targetUrl.port || 443}`,
417
+ },
320
418
  });
321
419
  connectReq.on("connect", (_res, sock) => {
322
420
  if (_res.statusCode !== 200) {
@@ -325,13 +423,21 @@ export function createProxiedFetchTool(client, apiKey) {
325
423
  reject(new Error(`CONNECT failed: ${_res.statusCode}`));
326
424
  return;
327
425
  }
328
- const tlsSock = tls.connect({ host: targetUrl.hostname, socket: sock, servername: targetUrl.hostname, minVersion: "TLSv1.2" }, () => {
426
+ const tlsSock = tls.connect({
427
+ host: targetUrl.hostname,
428
+ socket: sock,
429
+ servername: targetUrl.hostname,
430
+ minVersion: "TLSv1.2",
431
+ }, () => {
329
432
  const reqLine = `${method} ${targetUrl.pathname + targetUrl.search} HTTP/1.1\r\nHost: ${targetUrl.host}\r\nUser-Agent: dominusnode-vercel-ai/1.0.0\r\n${customHeaderLines}Connection: close\r\n\r\n`;
330
433
  tlsSock.write(reqLine);
331
434
  const chunks = [];
332
435
  let bytes = 0;
333
- tlsSock.on("data", (c) => { bytes += c.length; if (bytes <= MAX_RESP + 16384)
334
- chunks.push(c); });
436
+ tlsSock.on("data", (c) => {
437
+ bytes += c.length;
438
+ if (bytes <= MAX_RESP + 16384)
439
+ chunks.push(c);
440
+ });
335
441
  let done = false;
336
442
  const fin = () => {
337
443
  if (done)
@@ -346,55 +452,96 @@ export function createProxiedFetchTool(client, apiKey) {
346
452
  }
347
453
  const hdr = raw.substring(0, hEnd);
348
454
  const body = raw.substring(hEnd + 4).substring(0, MAX_RESP);
349
- const sm = hdr.split("\r\n")[0].match(/^HTTP\/\d\.\d\s+(\d+)\s*(.*)/);
455
+ const sm = hdr
456
+ .split("\r\n")[0]
457
+ .match(/^HTTP\/\d\.\d\s+(\d+)\s*(.*)/);
350
458
  const hdrs = {};
351
459
  for (const l of hdr.split("\r\n").slice(1)) {
352
460
  const ci = l.indexOf(":");
353
461
  if (ci > 0)
354
- hdrs[l.substring(0, ci).trim().toLowerCase()] = l.substring(ci + 1).trim();
462
+ hdrs[l.substring(0, ci).trim().toLowerCase()] = l
463
+ .substring(ci + 1)
464
+ .trim();
355
465
  }
356
466
  stripDangerousKeys(hdrs);
357
- resolve({ status: sm ? parseInt(sm[1], 10) : 0, statusText: sm ? sm[2] ?? "" : "", headers: hdrs, body });
467
+ resolve({
468
+ status: sm ? parseInt(sm[1], 10) : 0,
469
+ statusText: sm ? (sm[2] ?? "") : "",
470
+ headers: hdrs,
471
+ body,
472
+ });
358
473
  };
359
474
  tlsSock.on("end", fin);
360
475
  tlsSock.on("close", fin);
361
- tlsSock.on("error", (e) => { clearTimeout(timer); reject(e); });
476
+ tlsSock.on("error", (e) => {
477
+ clearTimeout(timer);
478
+ reject(e);
479
+ });
480
+ });
481
+ tlsSock.on("error", (e) => {
482
+ clearTimeout(timer);
483
+ reject(e);
362
484
  });
363
- tlsSock.on("error", (e) => { clearTimeout(timer); reject(e); });
364
485
  });
365
- connectReq.on("error", (e) => { clearTimeout(timer); reject(e); });
486
+ connectReq.on("error", (e) => {
487
+ clearTimeout(timer);
488
+ reject(e);
489
+ });
366
490
  connectReq.end();
367
491
  }
368
492
  else {
369
493
  // HTTP: route through proxy with full URL as request path
370
494
  const req = http.request({
371
- hostname: proxyHost, port: proxyPort, method, path: targetUrl.toString(),
372
- headers: { "Proxy-Authorization": proxyAuth, Host: targetUrl.host ?? "", ...safeHeaders },
495
+ hostname: proxyHost,
496
+ port: proxyPort,
497
+ method,
498
+ path: targetUrl.toString(),
499
+ headers: {
500
+ "Proxy-Authorization": proxyAuth,
501
+ Host: targetUrl.host ?? "",
502
+ ...safeHeaders,
503
+ },
373
504
  }, (res) => {
374
505
  const chunks = [];
375
506
  let bytes = 0;
376
- res.on("data", (c) => { bytes += c.length; if (bytes <= MAX_RESP)
377
- chunks.push(c); });
507
+ res.on("data", (c) => {
508
+ bytes += c.length;
509
+ if (bytes <= MAX_RESP)
510
+ chunks.push(c);
511
+ });
378
512
  let done = false;
379
513
  const fin = () => {
380
514
  if (done)
381
515
  return;
382
516
  done = true;
383
517
  clearTimeout(timer);
384
- const body = Buffer.concat(chunks).toString("utf-8").substring(0, MAX_RESP);
518
+ const body = Buffer.concat(chunks)
519
+ .toString("utf-8")
520
+ .substring(0, MAX_RESP);
385
521
  const hdrs = {};
386
522
  for (const [k, v] of Object.entries(res.headers)) {
387
523
  if (v)
388
524
  hdrs[k] = Array.isArray(v) ? v.join(", ") : v;
389
525
  }
390
526
  stripDangerousKeys(hdrs);
391
- resolve({ status: res.statusCode ?? 0, statusText: res.statusMessage ?? "", headers: hdrs, body });
527
+ resolve({
528
+ status: res.statusCode ?? 0,
529
+ statusText: res.statusMessage ?? "",
530
+ headers: hdrs,
531
+ body,
532
+ });
392
533
  };
393
534
  res.on("end", fin);
394
535
  res.on("close", fin);
395
- res.on("error", (e) => { clearTimeout(timer); reject(e); });
536
+ res.on("error", (e) => {
537
+ clearTimeout(timer);
538
+ reject(e);
539
+ });
540
+ });
541
+ req.on("error", (e) => {
542
+ clearTimeout(timer);
543
+ reject(e);
396
544
  });
397
- req.on("error", (e) => { clearTimeout(timer); reject(e); });
398
545
  req.end();
399
546
  }
400
547
  });
@@ -535,7 +682,9 @@ export function createGetProxyConfigTool(client) {
535
682
  }
536
683
  catch (err) {
537
684
  const message = err instanceof Error ? err.message : "Unknown error";
538
- return { error: `Failed to get proxy config: ${sanitizeError(message)}` };
685
+ return {
686
+ error: `Failed to get proxy config: ${sanitizeError(message)}`,
687
+ };
539
688
  }
540
689
  },
541
690
  });
@@ -585,7 +734,9 @@ export function createTopupPaypalTool(client) {
585
734
  }),
586
735
  execute: async ({ amount_cents }) => {
587
736
  try {
588
- const result = await client.wallet.topupPaypal({ amountCents: amount_cents });
737
+ const result = await client.wallet.topupPaypal({
738
+ amountCents: amount_cents,
739
+ });
589
740
  return {
590
741
  orderId: result.orderId,
591
742
  approvalUrl: result.approvalUrl,
@@ -594,7 +745,9 @@ export function createTopupPaypalTool(client) {
594
745
  }
595
746
  catch (err) {
596
747
  const message = err instanceof Error ? err.message : "Unknown error";
597
- return { error: `Failed to create PayPal top-up: ${sanitizeError(message)}` };
748
+ return {
749
+ error: `Failed to create PayPal top-up: ${sanitizeError(message)}`,
750
+ };
598
751
  }
599
752
  },
600
753
  });
@@ -617,7 +770,9 @@ export function createTopupStripeTool(client) {
617
770
  }),
618
771
  execute: async ({ amount_cents }) => {
619
772
  try {
620
- const result = await client.wallet.topupStripe({ amountCents: amount_cents });
773
+ const result = await client.wallet.topupStripe({
774
+ amountCents: amount_cents,
775
+ });
621
776
  return {
622
777
  sessionId: result.sessionId,
623
778
  url: result.url,
@@ -626,7 +781,9 @@ export function createTopupStripeTool(client) {
626
781
  }
627
782
  catch (err) {
628
783
  const message = err instanceof Error ? err.message : "Unknown error";
629
- return { error: `Failed to create Stripe checkout: ${sanitizeError(message)}` };
784
+ return {
785
+ error: `Failed to create Stripe checkout: ${sanitizeError(message)}`,
786
+ };
630
787
  }
631
788
  },
632
789
  });
@@ -645,12 +802,27 @@ export function createTopupCryptoTool(client) {
645
802
  .max(1000)
646
803
  .describe("Amount in USD to top up (min $5, max $1,000)"),
647
804
  currency: z
648
- .enum(["BTC", "ETH", "LTC", "XMR", "ZEC", "USDC", "SOL", "USDT", "DAI", "BNB", "LINK"])
805
+ .enum([
806
+ "BTC",
807
+ "ETH",
808
+ "LTC",
809
+ "XMR",
810
+ "ZEC",
811
+ "USDC",
812
+ "SOL",
813
+ "USDT",
814
+ "DAI",
815
+ "BNB",
816
+ "LINK",
817
+ ])
649
818
  .describe("Cryptocurrency to pay with"),
650
819
  }),
651
- execute: async ({ amount_usd, currency }) => {
820
+ execute: async ({ amount_usd, currency, }) => {
652
821
  try {
653
- const result = await client.wallet.topupCrypto({ amountUsd: amount_usd, currency: currency.toLowerCase() });
822
+ const result = await client.wallet.topupCrypto({
823
+ amountUsd: amount_usd,
824
+ currency: currency.toLowerCase(),
825
+ });
654
826
  return {
655
827
  invoiceId: result.invoiceId,
656
828
  invoiceUrl: result.invoiceUrl,
@@ -660,7 +832,9 @@ export function createTopupCryptoTool(client) {
660
832
  }
661
833
  catch (err) {
662
834
  const message = err instanceof Error ? err.message : "Unknown error";
663
- return { error: `Failed to create crypto invoice: ${sanitizeError(message)}` };
835
+ return {
836
+ error: `Failed to create crypto invoice: ${sanitizeError(message)}`,
837
+ };
664
838
  }
665
839
  },
666
840
  });
@@ -698,7 +872,7 @@ async function apiRequest(client, method, path, body, agentSecret) {
698
872
  const apiKey = client.apiKey || "";
699
873
  const url = `${baseUrl}${path}`;
700
874
  const headers = {
701
- "Authorization": `Bearer ${apiKey}`,
875
+ Authorization: `Bearer ${apiKey}`,
702
876
  "Content-Type": "application/json",
703
877
  };
704
878
  if (agentSecret) {
@@ -733,18 +907,40 @@ export function createCreateAgenticWalletTool(client, agentSecret) {
733
907
  description: "Create a new agentic sub-wallet with a spending limit. " +
734
908
  "Agentic wallets are custodial sub-wallets for AI agents with per-transaction spending caps.",
735
909
  parameters: z.object({
736
- label: z.string().min(1).max(100).describe("Human-readable label for the wallet"),
737
- spending_limit_cents: z.number().int().min(1).max(2147483647).describe("Per-transaction spending limit in cents"),
738
- daily_limit_cents: z.number().int().min(1).max(1000000).optional().describe("Optional daily spending limit in cents"),
739
- allowed_domains: z.array(z.string().max(253).regex(DOMAIN_RE)).max(100).optional().describe("Optional list of allowed domains"),
910
+ label: z
911
+ .string()
912
+ .min(1)
913
+ .max(100)
914
+ .describe("Human-readable label for the wallet"),
915
+ spending_limit_cents: z
916
+ .number()
917
+ .int()
918
+ .min(1)
919
+ .max(2147483647)
920
+ .describe("Per-transaction spending limit in cents"),
921
+ daily_limit_cents: z
922
+ .number()
923
+ .int()
924
+ .min(1)
925
+ .max(1000000)
926
+ .optional()
927
+ .describe("Optional daily spending limit in cents"),
928
+ allowed_domains: z
929
+ .array(z.string().max(253).regex(DOMAIN_RE))
930
+ .max(100)
931
+ .optional()
932
+ .describe("Optional list of allowed domains"),
740
933
  }),
741
- execute: async ({ label, spending_limit_cents, daily_limit_cents, allowed_domains }) => {
934
+ execute: async ({ label, spending_limit_cents, daily_limit_cents, allowed_domains, }) => {
742
935
  // Validate no control chars in label
743
936
  if (/[\x00-\x1F\x7F]/.test(label)) {
744
937
  return { error: "label contains invalid control characters" };
745
938
  }
746
939
  try {
747
- const body = { label, spendingLimitCents: spending_limit_cents };
940
+ const body = {
941
+ label,
942
+ spendingLimitCents: spending_limit_cents,
943
+ };
748
944
  if (daily_limit_cents !== undefined)
749
945
  body.dailyLimitCents = daily_limit_cents;
750
946
  if (allowed_domains !== undefined)
@@ -753,7 +949,9 @@ export function createCreateAgenticWalletTool(client, agentSecret) {
753
949
  return result;
754
950
  }
755
951
  catch (err) {
756
- return { error: `Failed to create agentic wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
952
+ return {
953
+ error: `Failed to create agentic wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
954
+ };
757
955
  }
758
956
  },
759
957
  });
@@ -765,15 +963,25 @@ export function createFundAgenticWalletTool(client, agentSecret) {
765
963
  return tool({
766
964
  description: "Transfer funds from the main wallet to an agentic sub-wallet.",
767
965
  parameters: z.object({
768
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
769
- amount_cents: z.number().int().min(1).max(2147483647).describe("Amount in cents to transfer"),
966
+ wallet_id: z
967
+ .string()
968
+ .regex(UUID_RE, "Must be a valid UUID")
969
+ .describe("UUID of the agentic wallet"),
970
+ amount_cents: z
971
+ .number()
972
+ .int()
973
+ .min(1)
974
+ .max(2147483647)
975
+ .describe("Amount in cents to transfer"),
770
976
  }),
771
- execute: async ({ wallet_id, amount_cents }) => {
977
+ execute: async ({ wallet_id, amount_cents, }) => {
772
978
  try {
773
979
  return await apiRequest(client, "POST", `/api/agent-wallet/${encodeURIComponent(wallet_id)}/fund`, { amountCents: amount_cents }, agentSecret);
774
980
  }
775
981
  catch (err) {
776
- return { error: `Failed to fund wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
982
+ return {
983
+ error: `Failed to fund wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
984
+ };
777
985
  }
778
986
  },
779
987
  });
@@ -785,14 +993,19 @@ export function createAgenticWalletBalanceTool(client, agentSecret) {
785
993
  return tool({
786
994
  description: "Check the balance and details of an agentic sub-wallet.",
787
995
  parameters: z.object({
788
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
996
+ wallet_id: z
997
+ .string()
998
+ .regex(UUID_RE, "Must be a valid UUID")
999
+ .describe("UUID of the agentic wallet"),
789
1000
  }),
790
1001
  execute: async ({ wallet_id }) => {
791
1002
  try {
792
1003
  return await apiRequest(client, "GET", `/api/agent-wallet/${encodeURIComponent(wallet_id)}`, undefined, agentSecret);
793
1004
  }
794
1005
  catch (err) {
795
- return { error: `Failed to get wallet balance: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1006
+ return {
1007
+ error: `Failed to get wallet balance: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1008
+ };
796
1009
  }
797
1010
  },
798
1011
  });
@@ -809,7 +1022,9 @@ export function createListAgenticWalletsTool(client, agentSecret) {
809
1022
  return await apiRequest(client, "GET", "/api/agent-wallet", undefined, agentSecret);
810
1023
  }
811
1024
  catch (err) {
812
- return { error: `Failed to list wallets: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1025
+ return {
1026
+ error: `Failed to list wallets: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1027
+ };
813
1028
  }
814
1029
  },
815
1030
  });
@@ -821,16 +1036,27 @@ export function createAgenticTransactionsTool(client, agentSecret) {
821
1036
  return tool({
822
1037
  description: "List recent transactions for an agentic sub-wallet.",
823
1038
  parameters: z.object({
824
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
825
- limit: z.number().int().min(1).max(100).optional().describe("Maximum transactions to return (1-100)"),
1039
+ wallet_id: z
1040
+ .string()
1041
+ .regex(UUID_RE, "Must be a valid UUID")
1042
+ .describe("UUID of the agentic wallet"),
1043
+ limit: z
1044
+ .number()
1045
+ .int()
1046
+ .min(1)
1047
+ .max(100)
1048
+ .optional()
1049
+ .describe("Maximum transactions to return (1-100)"),
826
1050
  }),
827
- execute: async ({ wallet_id, limit }) => {
1051
+ execute: async ({ wallet_id, limit, }) => {
828
1052
  try {
829
1053
  const qs = limit ? `?limit=${limit}` : "";
830
1054
  return await apiRequest(client, "GET", `/api/agent-wallet/${encodeURIComponent(wallet_id)}/transactions${qs}`, undefined, agentSecret);
831
1055
  }
832
1056
  catch (err) {
833
- return { error: `Failed to get transactions: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1057
+ return {
1058
+ error: `Failed to get transactions: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1059
+ };
834
1060
  }
835
1061
  },
836
1062
  });
@@ -842,14 +1068,19 @@ export function createFreezeAgenticWalletTool(client, agentSecret) {
842
1068
  return tool({
843
1069
  description: "Freeze an agentic sub-wallet to prevent further spending.",
844
1070
  parameters: z.object({
845
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
1071
+ wallet_id: z
1072
+ .string()
1073
+ .regex(UUID_RE, "Must be a valid UUID")
1074
+ .describe("UUID of the agentic wallet"),
846
1075
  }),
847
1076
  execute: async ({ wallet_id }) => {
848
1077
  try {
849
1078
  return await apiRequest(client, "POST", `/api/agent-wallet/${encodeURIComponent(wallet_id)}/freeze`, undefined, agentSecret);
850
1079
  }
851
1080
  catch (err) {
852
- return { error: `Failed to freeze wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1081
+ return {
1082
+ error: `Failed to freeze wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1083
+ };
853
1084
  }
854
1085
  },
855
1086
  });
@@ -861,14 +1092,19 @@ export function createUnfreezeAgenticWalletTool(client, agentSecret) {
861
1092
  return tool({
862
1093
  description: "Unfreeze a previously frozen agentic sub-wallet to re-enable spending.",
863
1094
  parameters: z.object({
864
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
1095
+ wallet_id: z
1096
+ .string()
1097
+ .regex(UUID_RE, "Must be a valid UUID")
1098
+ .describe("UUID of the agentic wallet"),
865
1099
  }),
866
1100
  execute: async ({ wallet_id }) => {
867
1101
  try {
868
1102
  return await apiRequest(client, "POST", `/api/agent-wallet/${encodeURIComponent(wallet_id)}/unfreeze`, undefined, agentSecret);
869
1103
  }
870
1104
  catch (err) {
871
- return { error: `Failed to unfreeze wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1105
+ return {
1106
+ error: `Failed to unfreeze wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1107
+ };
872
1108
  }
873
1109
  },
874
1110
  });
@@ -881,14 +1117,19 @@ export function createDeleteAgenticWalletTool(client, agentSecret) {
881
1117
  return tool({
882
1118
  description: "Delete an agentic sub-wallet. Must be active (not frozen). Remaining balance returns to main wallet.",
883
1119
  parameters: z.object({
884
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
1120
+ wallet_id: z
1121
+ .string()
1122
+ .regex(UUID_RE, "Must be a valid UUID")
1123
+ .describe("UUID of the agentic wallet"),
885
1124
  }),
886
1125
  execute: async ({ wallet_id }) => {
887
1126
  try {
888
1127
  return await apiRequest(client, "DELETE", `/api/agent-wallet/${encodeURIComponent(wallet_id)}`, undefined, agentSecret);
889
1128
  }
890
1129
  catch (err) {
891
- return { error: `Failed to delete wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1130
+ return {
1131
+ error: `Failed to delete wallet: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1132
+ };
892
1133
  }
893
1134
  },
894
1135
  });
@@ -900,24 +1141,41 @@ export function createUpdateWalletPolicyTool(client, agentSecret) {
900
1141
  return tool({
901
1142
  description: "Update the policy (daily limit, allowed domains) of an agentic sub-wallet.",
902
1143
  parameters: z.object({
903
- wallet_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the agentic wallet"),
904
- daily_limit_cents: z.number().int().min(1).max(1000000).optional().describe("New daily spending limit in cents"),
905
- allowed_domains: z.array(z.string().max(253).regex(DOMAIN_RE)).max(100).optional().describe("New allowed domains list"),
1144
+ wallet_id: z
1145
+ .string()
1146
+ .regex(UUID_RE, "Must be a valid UUID")
1147
+ .describe("UUID of the agentic wallet"),
1148
+ daily_limit_cents: z
1149
+ .number()
1150
+ .int()
1151
+ .min(1)
1152
+ .max(1000000)
1153
+ .optional()
1154
+ .describe("New daily spending limit in cents"),
1155
+ allowed_domains: z
1156
+ .array(z.string().max(253).regex(DOMAIN_RE))
1157
+ .max(100)
1158
+ .optional()
1159
+ .describe("New allowed domains list"),
906
1160
  }),
907
- execute: async ({ wallet_id, daily_limit_cents, allowed_domains }) => {
1161
+ execute: async ({ wallet_id, daily_limit_cents, allowed_domains, }) => {
908
1162
  const body = {};
909
1163
  if (daily_limit_cents !== undefined)
910
1164
  body.dailyLimitCents = daily_limit_cents;
911
1165
  if (allowed_domains !== undefined)
912
1166
  body.allowedDomains = allowed_domains;
913
1167
  if (Object.keys(body).length === 0) {
914
- return { error: "At least one of daily_limit_cents or allowed_domains must be provided" };
1168
+ return {
1169
+ error: "At least one of daily_limit_cents or allowed_domains must be provided",
1170
+ };
915
1171
  }
916
1172
  try {
917
1173
  return await apiRequest(client, "PATCH", `/api/agent-wallet/${encodeURIComponent(wallet_id)}/policy`, body, agentSecret);
918
1174
  }
919
1175
  catch (err) {
920
- return { error: `Failed to update policy: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1176
+ return {
1177
+ error: `Failed to update policy: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1178
+ };
921
1179
  }
922
1180
  },
923
1181
  });
@@ -934,18 +1192,32 @@ export function createRegisterTool(agentSecret) {
934
1192
  "After registering, use verifyEmail or rely on MCP agent auto-verification.",
935
1193
  parameters: z.object({
936
1194
  email: z.string().email().describe("Email address for the new account"),
937
- password: z.string().min(8).max(128).describe("Password (min 8 characters)"),
1195
+ password: z
1196
+ .string()
1197
+ .min(8)
1198
+ .max(128)
1199
+ .describe("Password (min 8 characters)"),
938
1200
  }),
939
- execute: async ({ email, password }) => {
1201
+ execute: async ({ email, password, }) => {
940
1202
  try {
941
1203
  const baseUrl = process.env.DOMINUSNODE_BASE_URL || "https://api.dominusnode.com";
942
- const headers = { "Content-Type": "application/json" };
1204
+ const headers = {
1205
+ "Content-Type": "application/json",
1206
+ };
943
1207
  if (agentSecret) {
944
1208
  headers["X-DominusNode-Agent"] = "mcp";
945
1209
  headers["X-DominusNode-Agent-Secret"] = agentSecret;
946
1210
  }
1211
+ // Solve PoW for CAPTCHA-free registration
1212
+ const pow = await solvePoW(baseUrl);
1213
+ const regBody = { email, password };
1214
+ if (pow)
1215
+ regBody.pow = pow;
947
1216
  const resp = await fetch(`${baseUrl}/api/auth/register`, {
948
- method: "POST", headers, body: JSON.stringify({ email, password }), redirect: "error",
1217
+ method: "POST",
1218
+ headers,
1219
+ body: JSON.stringify(regBody),
1220
+ redirect: "error",
949
1221
  });
950
1222
  if (!resp.ok) {
951
1223
  const text = await resp.text().catch(() => "");
@@ -953,10 +1225,16 @@ export function createRegisterTool(agentSecret) {
953
1225
  }
954
1226
  const data = JSON.parse(await resp.text());
955
1227
  stripDangerousKeys(data);
956
- return { userId: data.user?.id, email: data.user?.email, message: "Account created. Verify email to unlock financial features." };
1228
+ return {
1229
+ userId: data.user?.id,
1230
+ email: data.user?.email,
1231
+ message: "Account created. Verify email to unlock financial features.",
1232
+ };
957
1233
  }
958
1234
  catch (err) {
959
- return { error: `Failed to register: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1235
+ return {
1236
+ error: `Failed to register: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1237
+ };
960
1238
  }
961
1239
  },
962
1240
  });
@@ -971,16 +1249,21 @@ export function createLoginTool(agentSecret) {
971
1249
  email: z.string().email().describe("Account email address"),
972
1250
  password: z.string().min(1).describe("Account password"),
973
1251
  }),
974
- execute: async ({ email, password }) => {
1252
+ execute: async ({ email, password, }) => {
975
1253
  try {
976
1254
  const baseUrl = process.env.DOMINUSNODE_BASE_URL || "https://api.dominusnode.com";
977
- const headers = { "Content-Type": "application/json" };
1255
+ const headers = {
1256
+ "Content-Type": "application/json",
1257
+ };
978
1258
  if (agentSecret) {
979
1259
  headers["X-DominusNode-Agent"] = "mcp";
980
1260
  headers["X-DominusNode-Agent-Secret"] = agentSecret;
981
1261
  }
982
1262
  const resp = await fetch(`${baseUrl}/api/auth/login`, {
983
- method: "POST", headers, body: JSON.stringify({ email, password }), redirect: "error",
1263
+ method: "POST",
1264
+ headers,
1265
+ body: JSON.stringify({ email, password }),
1266
+ redirect: "error",
984
1267
  });
985
1268
  if (!resp.ok) {
986
1269
  const text = await resp.text().catch(() => "");
@@ -989,12 +1272,21 @@ export function createLoginTool(agentSecret) {
989
1272
  const data = JSON.parse(await resp.text());
990
1273
  stripDangerousKeys(data);
991
1274
  if (data.mfaRequired) {
992
- return { mfaRequired: true, challengeToken: data.challengeToken, message: "MFA verification required" };
1275
+ return {
1276
+ mfaRequired: true,
1277
+ challengeToken: data.challengeToken,
1278
+ message: "MFA verification required",
1279
+ };
993
1280
  }
994
- return { accessToken: data.accessToken ? "[REDACTED]" : undefined, message: "Login successful" };
1281
+ return {
1282
+ accessToken: data.accessToken ? "[REDACTED]" : undefined,
1283
+ message: "Login successful",
1284
+ };
995
1285
  }
996
1286
  catch (err) {
997
- return { error: `Failed to login: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1287
+ return {
1288
+ error: `Failed to login: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1289
+ };
998
1290
  }
999
1291
  },
1000
1292
  });
@@ -1020,7 +1312,9 @@ export function createGetAccountInfoTool(client, agentSecret) {
1020
1312
  };
1021
1313
  }
1022
1314
  catch (err) {
1023
- return { error: `Failed to get account info: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1315
+ return {
1316
+ error: `Failed to get account info: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1317
+ };
1024
1318
  }
1025
1319
  },
1026
1320
  });
@@ -1032,18 +1326,26 @@ export function createVerifyEmailTool(agentSecret) {
1032
1326
  return tool({
1033
1327
  description: "Verify email address using the verification token sent to email. MCP agents are auto-verified.",
1034
1328
  parameters: z.object({
1035
- token: z.string().min(1).describe("Email verification token from the verification email"),
1329
+ token: z
1330
+ .string()
1331
+ .min(1)
1332
+ .describe("Email verification token from the verification email"),
1036
1333
  }),
1037
1334
  execute: async ({ token }) => {
1038
1335
  try {
1039
1336
  const baseUrl = process.env.DOMINUSNODE_BASE_URL || "https://api.dominusnode.com";
1040
- const headers = { "Content-Type": "application/json" };
1337
+ const headers = {
1338
+ "Content-Type": "application/json",
1339
+ };
1041
1340
  if (agentSecret) {
1042
1341
  headers["X-DominusNode-Agent"] = "mcp";
1043
1342
  headers["X-DominusNode-Agent-Secret"] = agentSecret;
1044
1343
  }
1045
1344
  const resp = await fetch(`${baseUrl}/api/auth/verify-email`, {
1046
- method: "POST", headers, body: JSON.stringify({ token }), redirect: "error",
1345
+ method: "POST",
1346
+ headers,
1347
+ body: JSON.stringify({ token }),
1348
+ redirect: "error",
1047
1349
  });
1048
1350
  if (!resp.ok) {
1049
1351
  const text = await resp.text().catch(() => "");
@@ -1052,7 +1354,9 @@ export function createVerifyEmailTool(agentSecret) {
1052
1354
  return { success: true, message: "Email verified successfully" };
1053
1355
  }
1054
1356
  catch (err) {
1055
- return { error: `Failed to verify email: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1357
+ return {
1358
+ error: `Failed to verify email: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1359
+ };
1056
1360
  }
1057
1361
  },
1058
1362
  });
@@ -1070,7 +1374,9 @@ export function createResendVerificationTool(client, agentSecret) {
1070
1374
  return { success: true, message: "Verification email sent" };
1071
1375
  }
1072
1376
  catch (err) {
1073
- return { error: `Failed to resend verification: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1377
+ return {
1378
+ error: `Failed to resend verification: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1379
+ };
1074
1380
  }
1075
1381
  },
1076
1382
  });
@@ -1083,9 +1389,13 @@ export function createUpdatePasswordTool(client, agentSecret) {
1083
1389
  description: "Change the password for the current Dominus Node account.",
1084
1390
  parameters: z.object({
1085
1391
  current_password: z.string().min(1).describe("Current password"),
1086
- new_password: z.string().min(8).max(128).describe("New password (min 8 characters)"),
1392
+ new_password: z
1393
+ .string()
1394
+ .min(8)
1395
+ .max(128)
1396
+ .describe("New password (min 8 characters)"),
1087
1397
  }),
1088
- execute: async ({ current_password, new_password }) => {
1398
+ execute: async ({ current_password, new_password, }) => {
1089
1399
  try {
1090
1400
  await apiRequest(client, "POST", "/api/auth/change-password", {
1091
1401
  currentPassword: current_password,
@@ -1094,7 +1404,9 @@ export function createUpdatePasswordTool(client, agentSecret) {
1094
1404
  return { success: true, message: "Password updated" };
1095
1405
  }
1096
1406
  catch (err) {
1097
- return { error: `Failed to update password: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1407
+ return {
1408
+ error: `Failed to update password: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1409
+ };
1098
1410
  }
1099
1411
  },
1100
1412
  });
@@ -1114,7 +1426,9 @@ export function createListKeysTool(client, agentSecret) {
1114
1426
  return await apiRequest(client, "GET", "/api/keys", undefined, agentSecret);
1115
1427
  }
1116
1428
  catch (err) {
1117
- return { error: `Failed to list keys: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1429
+ return {
1430
+ error: `Failed to list keys: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1431
+ };
1118
1432
  }
1119
1433
  },
1120
1434
  });
@@ -1127,7 +1441,12 @@ export function createCreateKeyTool(client, agentSecret) {
1127
1441
  description: "Create a new Dominus Node API key. The full key is shown only once — store it securely. " +
1128
1442
  "WARNING: API keys are secret credentials. Never log or share them.",
1129
1443
  parameters: z.object({
1130
- label: z.string().min(1).max(100).optional().describe("Human-readable label for the key"),
1444
+ label: z
1445
+ .string()
1446
+ .min(1)
1447
+ .max(100)
1448
+ .optional()
1449
+ .describe("Human-readable label for the key"),
1131
1450
  }),
1132
1451
  execute: async ({ label }) => {
1133
1452
  if (label && /[\x00-\x1F\x7F]/.test(label)) {
@@ -1140,7 +1459,9 @@ export function createCreateKeyTool(client, agentSecret) {
1140
1459
  return await apiRequest(client, "POST", "/api/keys", body, agentSecret);
1141
1460
  }
1142
1461
  catch (err) {
1143
- return { error: `Failed to create key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1462
+ return {
1463
+ error: `Failed to create key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1464
+ };
1144
1465
  }
1145
1466
  },
1146
1467
  });
@@ -1152,7 +1473,10 @@ export function createRevokeKeyTool(client, agentSecret) {
1152
1473
  return tool({
1153
1474
  description: "Revoke (permanently delete) a Dominus Node API key. This cannot be undone.",
1154
1475
  parameters: z.object({
1155
- key_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the API key to revoke"),
1476
+ key_id: z
1477
+ .string()
1478
+ .regex(UUID_RE, "Must be a valid UUID")
1479
+ .describe("UUID of the API key to revoke"),
1156
1480
  }),
1157
1481
  execute: async ({ key_id }) => {
1158
1482
  try {
@@ -1160,7 +1484,9 @@ export function createRevokeKeyTool(client, agentSecret) {
1160
1484
  return { success: true, message: "API key revoked" };
1161
1485
  }
1162
1486
  catch (err) {
1163
- return { error: `Failed to revoke key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1487
+ return {
1488
+ error: `Failed to revoke key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1489
+ };
1164
1490
  }
1165
1491
  },
1166
1492
  });
@@ -1175,8 +1501,19 @@ export function createGetTransactionsTool(client, agentSecret) {
1175
1501
  return tool({
1176
1502
  description: "Get wallet transaction history showing top-ups, usage charges, and transfers.",
1177
1503
  parameters: z.object({
1178
- limit: z.number().int().min(1).max(100).optional().describe("Maximum transactions to return (default 50)"),
1179
- offset: z.number().int().min(0).optional().describe("Offset for pagination"),
1504
+ limit: z
1505
+ .number()
1506
+ .int()
1507
+ .min(1)
1508
+ .max(100)
1509
+ .optional()
1510
+ .describe("Maximum transactions to return (default 50)"),
1511
+ offset: z
1512
+ .number()
1513
+ .int()
1514
+ .min(0)
1515
+ .optional()
1516
+ .describe("Offset for pagination"),
1180
1517
  }),
1181
1518
  execute: async ({ limit, offset }) => {
1182
1519
  try {
@@ -1189,7 +1526,9 @@ export function createGetTransactionsTool(client, agentSecret) {
1189
1526
  return await apiRequest(client, "GET", `/api/wallet/transactions${qs}`, undefined, agentSecret);
1190
1527
  }
1191
1528
  catch (err) {
1192
- return { error: `Failed to get transactions: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1529
+ return {
1530
+ error: `Failed to get transactions: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1531
+ };
1193
1532
  }
1194
1533
  },
1195
1534
  });
@@ -1206,7 +1545,9 @@ export function createGetForecastTool(client, agentSecret) {
1206
1545
  return await apiRequest(client, "GET", "/api/wallet/forecast", undefined, agentSecret);
1207
1546
  }
1208
1547
  catch (err) {
1209
- return { error: `Failed to get forecast: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1548
+ return {
1549
+ error: `Failed to get forecast: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1550
+ };
1210
1551
  }
1211
1552
  },
1212
1553
  });
@@ -1218,14 +1559,19 @@ export function createCheckPaymentTool(client, agentSecret) {
1218
1559
  return tool({
1219
1560
  description: "Check the status of a cryptocurrency payment invoice. Use after creating a crypto top-up.",
1220
1561
  parameters: z.object({
1221
- invoice_id: z.string().min(1).describe("The invoice ID from the crypto top-up creation"),
1562
+ invoice_id: z
1563
+ .string()
1564
+ .min(1)
1565
+ .describe("The invoice ID from the crypto top-up creation"),
1222
1566
  }),
1223
1567
  execute: async ({ invoice_id }) => {
1224
1568
  try {
1225
1569
  return await apiRequest(client, "GET", `/api/wallet/crypto/status/${encodeURIComponent(invoice_id)}`, undefined, agentSecret);
1226
1570
  }
1227
1571
  catch (err) {
1228
- return { error: `Failed to check payment: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1572
+ return {
1573
+ error: `Failed to check payment: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1574
+ };
1229
1575
  }
1230
1576
  },
1231
1577
  });
@@ -1240,8 +1586,14 @@ export function createGetDailyUsageTool(client, agentSecret) {
1240
1586
  return tool({
1241
1587
  description: "Get daily proxy usage breakdown showing bytes, cost, and request count per day.",
1242
1588
  parameters: z.object({
1243
- since: z.string().optional().describe("Start date (ISO 8601). Defaults to 30 days ago."),
1244
- until: z.string().optional().describe("End date (ISO 8601). Defaults to now."),
1589
+ since: z
1590
+ .string()
1591
+ .optional()
1592
+ .describe("Start date (ISO 8601). Defaults to 30 days ago."),
1593
+ until: z
1594
+ .string()
1595
+ .optional()
1596
+ .describe("End date (ISO 8601). Defaults to now."),
1245
1597
  }),
1246
1598
  execute: async ({ since, until }) => {
1247
1599
  try {
@@ -1254,7 +1606,9 @@ export function createGetDailyUsageTool(client, agentSecret) {
1254
1606
  return await apiRequest(client, "GET", `/api/usage/daily${qs}`, undefined, agentSecret);
1255
1607
  }
1256
1608
  catch (err) {
1257
- return { error: `Failed to get daily usage: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1609
+ return {
1610
+ error: `Failed to get daily usage: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1611
+ };
1258
1612
  }
1259
1613
  },
1260
1614
  });
@@ -1266,11 +1620,23 @@ export function createGetTopHostsTool(client, agentSecret) {
1266
1620
  return tool({
1267
1621
  description: "Get the top accessed hosts (domains) through the proxy, ranked by total bytes transferred.",
1268
1622
  parameters: z.object({
1269
- since: z.string().optional().describe("Start date (ISO 8601). Defaults to 30 days ago."),
1270
- until: z.string().optional().describe("End date (ISO 8601). Defaults to now."),
1271
- limit: z.number().int().min(1).max(100).optional().describe("Max hosts to return (default 10)"),
1623
+ since: z
1624
+ .string()
1625
+ .optional()
1626
+ .describe("Start date (ISO 8601). Defaults to 30 days ago."),
1627
+ until: z
1628
+ .string()
1629
+ .optional()
1630
+ .describe("End date (ISO 8601). Defaults to now."),
1631
+ limit: z
1632
+ .number()
1633
+ .int()
1634
+ .min(1)
1635
+ .max(100)
1636
+ .optional()
1637
+ .describe("Max hosts to return (default 10)"),
1272
1638
  }),
1273
- execute: async ({ since, until, limit }) => {
1639
+ execute: async ({ since, until, limit, }) => {
1274
1640
  try {
1275
1641
  const params = new URLSearchParams();
1276
1642
  if (since)
@@ -1283,7 +1649,9 @@ export function createGetTopHostsTool(client, agentSecret) {
1283
1649
  return await apiRequest(client, "GET", `/api/usage/top-hosts${qs}`, undefined, agentSecret);
1284
1650
  }
1285
1651
  catch (err) {
1286
- return { error: `Failed to get top hosts: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1652
+ return {
1653
+ error: `Failed to get top hosts: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1654
+ };
1287
1655
  }
1288
1656
  },
1289
1657
  });
@@ -1303,7 +1671,9 @@ export function createGetPlanTool(client, agentSecret) {
1303
1671
  return await apiRequest(client, "GET", "/api/plans/user/plan", undefined, agentSecret);
1304
1672
  }
1305
1673
  catch (err) {
1306
- return { error: `Failed to get plan: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1674
+ return {
1675
+ error: `Failed to get plan: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1676
+ };
1307
1677
  }
1308
1678
  },
1309
1679
  });
@@ -1320,7 +1690,9 @@ export function createListPlansTool(client, agentSecret) {
1320
1690
  return await apiRequest(client, "GET", "/api/plans", undefined, agentSecret);
1321
1691
  }
1322
1692
  catch (err) {
1323
- return { error: `Failed to list plans: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1693
+ return {
1694
+ error: `Failed to list plans: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1695
+ };
1324
1696
  }
1325
1697
  },
1326
1698
  });
@@ -1339,7 +1711,9 @@ export function createChangePlanTool(client, agentSecret) {
1339
1711
  return await apiRequest(client, "PUT", "/api/plans/user/plan", { planId: plan_id }, agentSecret);
1340
1712
  }
1341
1713
  catch (err) {
1342
- return { error: `Failed to change plan: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1714
+ return {
1715
+ error: `Failed to change plan: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1716
+ };
1343
1717
  }
1344
1718
  },
1345
1719
  });
@@ -1359,7 +1733,9 @@ export function createGetProxyStatusTool(client, agentSecret) {
1359
1733
  return await apiRequest(client, "GET", "/api/proxy/status", undefined, agentSecret);
1360
1734
  }
1361
1735
  catch (err) {
1362
- return { error: `Failed to get proxy status: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1736
+ return {
1737
+ error: `Failed to get proxy status: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1738
+ };
1363
1739
  }
1364
1740
  },
1365
1741
  });
@@ -1375,9 +1751,15 @@ export function createCreateTeamTool(client, agentSecret) {
1375
1751
  description: "Create a new Dominus Node team with a shared wallet for collaborative proxy usage.",
1376
1752
  parameters: z.object({
1377
1753
  name: z.string().min(1).max(100).describe("Team name"),
1378
- max_members: z.number().int().min(2).max(100).optional().describe("Maximum team members (default 10)"),
1754
+ max_members: z
1755
+ .number()
1756
+ .int()
1757
+ .min(2)
1758
+ .max(100)
1759
+ .optional()
1760
+ .describe("Maximum team members (default 10)"),
1379
1761
  }),
1380
- execute: async ({ name, max_members }) => {
1762
+ execute: async ({ name, max_members, }) => {
1381
1763
  if (/[\x00-\x1F\x7F]/.test(name)) {
1382
1764
  return { error: "name contains invalid control characters" };
1383
1765
  }
@@ -1388,7 +1770,9 @@ export function createCreateTeamTool(client, agentSecret) {
1388
1770
  return await apiRequest(client, "POST", "/api/teams", body, agentSecret);
1389
1771
  }
1390
1772
  catch (err) {
1391
- return { error: `Failed to create team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1773
+ return {
1774
+ error: `Failed to create team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1775
+ };
1392
1776
  }
1393
1777
  },
1394
1778
  });
@@ -1405,7 +1789,9 @@ export function createListTeamsTool(client, agentSecret) {
1405
1789
  return await apiRequest(client, "GET", "/api/teams", undefined, agentSecret);
1406
1790
  }
1407
1791
  catch (err) {
1408
- return { error: `Failed to list teams: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1792
+ return {
1793
+ error: `Failed to list teams: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1794
+ };
1409
1795
  }
1410
1796
  },
1411
1797
  });
@@ -1417,14 +1803,19 @@ export function createTeamDetailsTool(client, agentSecret) {
1417
1803
  return tool({
1418
1804
  description: "Get detailed information about a team including wallet balance, members count, and settings.",
1419
1805
  parameters: z.object({
1420
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1806
+ team_id: z
1807
+ .string()
1808
+ .regex(UUID_RE, "Must be a valid UUID")
1809
+ .describe("UUID of the team"),
1421
1810
  }),
1422
1811
  execute: async ({ team_id }) => {
1423
1812
  try {
1424
1813
  return await apiRequest(client, "GET", `/api/teams/${encodeURIComponent(team_id)}`, undefined, agentSecret);
1425
1814
  }
1426
1815
  catch (err) {
1427
- return { error: `Failed to get team details: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1816
+ return {
1817
+ error: `Failed to get team details: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1818
+ };
1428
1819
  }
1429
1820
  },
1430
1821
  });
@@ -1436,11 +1827,20 @@ export function createUpdateTeamTool(client, agentSecret) {
1436
1827
  return tool({
1437
1828
  description: "Update team settings such as name or max members. Requires owner or admin role.",
1438
1829
  parameters: z.object({
1439
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1830
+ team_id: z
1831
+ .string()
1832
+ .regex(UUID_RE, "Must be a valid UUID")
1833
+ .describe("UUID of the team"),
1440
1834
  name: z.string().min(1).max(100).optional().describe("New team name"),
1441
- max_members: z.number().int().min(2).max(100).optional().describe("New max members limit"),
1835
+ max_members: z
1836
+ .number()
1837
+ .int()
1838
+ .min(2)
1839
+ .max(100)
1840
+ .optional()
1841
+ .describe("New max members limit"),
1442
1842
  }),
1443
- execute: async ({ team_id, name, max_members }) => {
1843
+ execute: async ({ team_id, name, max_members, }) => {
1444
1844
  if (name && /[\x00-\x1F\x7F]/.test(name)) {
1445
1845
  return { error: "name contains invalid control characters" };
1446
1846
  }
@@ -1450,13 +1850,17 @@ export function createUpdateTeamTool(client, agentSecret) {
1450
1850
  if (max_members !== undefined)
1451
1851
  body.maxMembers = max_members;
1452
1852
  if (Object.keys(body).length === 0) {
1453
- return { error: "At least one field (name or max_members) must be provided" };
1853
+ return {
1854
+ error: "At least one field (name or max_members) must be provided",
1855
+ };
1454
1856
  }
1455
1857
  try {
1456
1858
  return await apiRequest(client, "PATCH", `/api/teams/${encodeURIComponent(team_id)}`, body, agentSecret);
1457
1859
  }
1458
1860
  catch (err) {
1459
- return { error: `Failed to update team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1861
+ return {
1862
+ error: `Failed to update team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1863
+ };
1460
1864
  }
1461
1865
  },
1462
1866
  });
@@ -1468,7 +1872,10 @@ export function createTeamDeleteTool(client, agentSecret) {
1468
1872
  return tool({
1469
1873
  description: "Delete a team permanently. Requires owner role. Remaining team wallet balance is NOT refunded.",
1470
1874
  parameters: z.object({
1471
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team to delete"),
1875
+ team_id: z
1876
+ .string()
1877
+ .regex(UUID_RE, "Must be a valid UUID")
1878
+ .describe("UUID of the team to delete"),
1472
1879
  }),
1473
1880
  execute: async ({ team_id }) => {
1474
1881
  try {
@@ -1476,7 +1883,9 @@ export function createTeamDeleteTool(client, agentSecret) {
1476
1883
  return { success: true, message: "Team deleted" };
1477
1884
  }
1478
1885
  catch (err) {
1479
- return { error: `Failed to delete team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1886
+ return {
1887
+ error: `Failed to delete team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1888
+ };
1480
1889
  }
1481
1890
  },
1482
1891
  });
@@ -1488,15 +1897,25 @@ export function createTeamFundTool(client, agentSecret) {
1488
1897
  return tool({
1489
1898
  description: "Fund a team wallet by transferring from your personal wallet. Requires owner or admin role.",
1490
1899
  parameters: z.object({
1491
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1492
- amount_cents: z.number().int().min(1).max(2147483647).describe("Amount in cents to transfer"),
1900
+ team_id: z
1901
+ .string()
1902
+ .regex(UUID_RE, "Must be a valid UUID")
1903
+ .describe("UUID of the team"),
1904
+ amount_cents: z
1905
+ .number()
1906
+ .int()
1907
+ .min(1)
1908
+ .max(2147483647)
1909
+ .describe("Amount in cents to transfer"),
1493
1910
  }),
1494
- execute: async ({ team_id, amount_cents }) => {
1911
+ execute: async ({ team_id, amount_cents, }) => {
1495
1912
  try {
1496
1913
  return await apiRequest(client, "POST", `/api/teams/${encodeURIComponent(team_id)}/wallet/fund`, { amountCents: amount_cents }, agentSecret);
1497
1914
  }
1498
1915
  catch (err) {
1499
- return { error: `Failed to fund team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1916
+ return {
1917
+ error: `Failed to fund team: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1918
+ };
1500
1919
  }
1501
1920
  },
1502
1921
  });
@@ -1508,10 +1927,18 @@ export function createTeamCreateKeyTool(client, agentSecret) {
1508
1927
  return tool({
1509
1928
  description: "Create an API key for a team. Team keys bill to the team wallet. Requires owner or admin role.",
1510
1929
  parameters: z.object({
1511
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1512
- label: z.string().min(1).max(100).optional().describe("Label for the team API key"),
1930
+ team_id: z
1931
+ .string()
1932
+ .regex(UUID_RE, "Must be a valid UUID")
1933
+ .describe("UUID of the team"),
1934
+ label: z
1935
+ .string()
1936
+ .min(1)
1937
+ .max(100)
1938
+ .optional()
1939
+ .describe("Label for the team API key"),
1513
1940
  }),
1514
- execute: async ({ team_id, label }) => {
1941
+ execute: async ({ team_id, label, }) => {
1515
1942
  if (label && /[\x00-\x1F\x7F]/.test(label)) {
1516
1943
  return { error: "label contains invalid control characters" };
1517
1944
  }
@@ -1522,7 +1949,9 @@ export function createTeamCreateKeyTool(client, agentSecret) {
1522
1949
  return await apiRequest(client, "POST", `/api/teams/${encodeURIComponent(team_id)}/keys`, body, agentSecret);
1523
1950
  }
1524
1951
  catch (err) {
1525
- return { error: `Failed to create team key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1952
+ return {
1953
+ error: `Failed to create team key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1954
+ };
1526
1955
  }
1527
1956
  },
1528
1957
  });
@@ -1534,16 +1963,24 @@ export function createTeamRevokeKeyTool(client, agentSecret) {
1534
1963
  return tool({
1535
1964
  description: "Revoke (delete) a team API key. Requires owner or admin role.",
1536
1965
  parameters: z.object({
1537
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1538
- key_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team key to revoke"),
1966
+ team_id: z
1967
+ .string()
1968
+ .regex(UUID_RE, "Must be a valid UUID")
1969
+ .describe("UUID of the team"),
1970
+ key_id: z
1971
+ .string()
1972
+ .regex(UUID_RE, "Must be a valid UUID")
1973
+ .describe("UUID of the team key to revoke"),
1539
1974
  }),
1540
- execute: async ({ team_id, key_id }) => {
1975
+ execute: async ({ team_id, key_id, }) => {
1541
1976
  try {
1542
1977
  await apiRequest(client, "DELETE", `/api/teams/${encodeURIComponent(team_id)}/keys/${encodeURIComponent(key_id)}`, undefined, agentSecret);
1543
1978
  return { success: true, message: "Team key revoked" };
1544
1979
  }
1545
1980
  catch (err) {
1546
- return { error: `Failed to revoke team key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
1981
+ return {
1982
+ error: `Failed to revoke team key: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
1983
+ };
1547
1984
  }
1548
1985
  },
1549
1986
  });
@@ -1555,14 +1992,19 @@ export function createTeamListKeysTool(client, agentSecret) {
1555
1992
  return tool({
1556
1993
  description: "List all API keys for a team. Shows key ID, label, prefix, and creation date.",
1557
1994
  parameters: z.object({
1558
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1995
+ team_id: z
1996
+ .string()
1997
+ .regex(UUID_RE, "Must be a valid UUID")
1998
+ .describe("UUID of the team"),
1559
1999
  }),
1560
2000
  execute: async ({ team_id }) => {
1561
2001
  try {
1562
2002
  return await apiRequest(client, "GET", `/api/teams/${encodeURIComponent(team_id)}/keys`, undefined, agentSecret);
1563
2003
  }
1564
2004
  catch (err) {
1565
- return { error: `Failed to list team keys: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2005
+ return {
2006
+ error: `Failed to list team keys: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2007
+ };
1566
2008
  }
1567
2009
  },
1568
2010
  });
@@ -1574,14 +2016,19 @@ export function createTeamUsageTool(client, agentSecret) {
1574
2016
  return tool({
1575
2017
  description: "Get proxy usage statistics for a team including total bytes, cost, and per-member breakdown.",
1576
2018
  parameters: z.object({
1577
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
2019
+ team_id: z
2020
+ .string()
2021
+ .regex(UUID_RE, "Must be a valid UUID")
2022
+ .describe("UUID of the team"),
1578
2023
  }),
1579
2024
  execute: async ({ team_id }) => {
1580
2025
  try {
1581
2026
  return await apiRequest(client, "GET", `/api/teams/${encodeURIComponent(team_id)}/usage`, undefined, agentSecret);
1582
2027
  }
1583
2028
  catch (err) {
1584
- return { error: `Failed to get team usage: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2029
+ return {
2030
+ error: `Failed to get team usage: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2031
+ };
1585
2032
  }
1586
2033
  },
1587
2034
  });
@@ -1593,14 +2040,19 @@ export function createTeamListMembersTool(client, agentSecret) {
1593
2040
  return tool({
1594
2041
  description: "List all members of a team with their roles (owner/admin/member) and join dates.",
1595
2042
  parameters: z.object({
1596
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
2043
+ team_id: z
2044
+ .string()
2045
+ .regex(UUID_RE, "Must be a valid UUID")
2046
+ .describe("UUID of the team"),
1597
2047
  }),
1598
2048
  execute: async ({ team_id }) => {
1599
2049
  try {
1600
2050
  return await apiRequest(client, "GET", `/api/teams/${encodeURIComponent(team_id)}/members`, undefined, agentSecret);
1601
2051
  }
1602
2052
  catch (err) {
1603
- return { error: `Failed to list team members: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2053
+ return {
2054
+ error: `Failed to list team members: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2055
+ };
1604
2056
  }
1605
2057
  },
1606
2058
  });
@@ -1612,11 +2064,17 @@ export function createTeamAddMemberTool(client, agentSecret) {
1612
2064
  return tool({
1613
2065
  description: "Add a member directly to a team by email. Requires owner or admin role.",
1614
2066
  parameters: z.object({
1615
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
2067
+ team_id: z
2068
+ .string()
2069
+ .regex(UUID_RE, "Must be a valid UUID")
2070
+ .describe("UUID of the team"),
1616
2071
  email: z.string().email().describe("Email of the user to add"),
1617
- role: z.enum(["admin", "member"]).optional().describe("Role to assign (default: member)"),
2072
+ role: z
2073
+ .enum(["admin", "member"])
2074
+ .optional()
2075
+ .describe("Role to assign (default: member)"),
1618
2076
  }),
1619
- execute: async ({ team_id, email, role }) => {
2077
+ execute: async ({ team_id, email, role, }) => {
1620
2078
  try {
1621
2079
  const body = { email };
1622
2080
  if (role)
@@ -1624,7 +2082,9 @@ export function createTeamAddMemberTool(client, agentSecret) {
1624
2082
  return await apiRequest(client, "POST", `/api/teams/${encodeURIComponent(team_id)}/members`, body, agentSecret);
1625
2083
  }
1626
2084
  catch (err) {
1627
- return { error: `Failed to add member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2085
+ return {
2086
+ error: `Failed to add member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2087
+ };
1628
2088
  }
1629
2089
  },
1630
2090
  });
@@ -1636,16 +2096,24 @@ export function createTeamRemoveMemberTool(client, agentSecret) {
1636
2096
  return tool({
1637
2097
  description: "Remove a member from a team. Requires owner or admin role. Cannot remove the owner.",
1638
2098
  parameters: z.object({
1639
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1640
- user_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the member to remove"),
2099
+ team_id: z
2100
+ .string()
2101
+ .regex(UUID_RE, "Must be a valid UUID")
2102
+ .describe("UUID of the team"),
2103
+ user_id: z
2104
+ .string()
2105
+ .regex(UUID_RE, "Must be a valid UUID")
2106
+ .describe("UUID of the member to remove"),
1641
2107
  }),
1642
- execute: async ({ team_id, user_id }) => {
2108
+ execute: async ({ team_id, user_id, }) => {
1643
2109
  try {
1644
2110
  await apiRequest(client, "DELETE", `/api/teams/${encodeURIComponent(team_id)}/members/${encodeURIComponent(user_id)}`, undefined, agentSecret);
1645
2111
  return { success: true, message: "Member removed" };
1646
2112
  }
1647
2113
  catch (err) {
1648
- return { error: `Failed to remove member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2114
+ return {
2115
+ error: `Failed to remove member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2116
+ };
1649
2117
  }
1650
2118
  },
1651
2119
  });
@@ -1657,16 +2125,24 @@ export function createUpdateTeamMemberRoleTool(client, agentSecret) {
1657
2125
  return tool({
1658
2126
  description: "Update a team member's role (admin or member). Requires owner role.",
1659
2127
  parameters: z.object({
1660
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1661
- user_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the member"),
2128
+ team_id: z
2129
+ .string()
2130
+ .regex(UUID_RE, "Must be a valid UUID")
2131
+ .describe("UUID of the team"),
2132
+ user_id: z
2133
+ .string()
2134
+ .regex(UUID_RE, "Must be a valid UUID")
2135
+ .describe("UUID of the member"),
1662
2136
  role: z.enum(["admin", "member"]).describe("New role for the member"),
1663
2137
  }),
1664
- execute: async ({ team_id, user_id, role }) => {
2138
+ execute: async ({ team_id, user_id, role, }) => {
1665
2139
  try {
1666
2140
  return await apiRequest(client, "PATCH", `/api/teams/${encodeURIComponent(team_id)}/members/${encodeURIComponent(user_id)}`, { role }, agentSecret);
1667
2141
  }
1668
2142
  catch (err) {
1669
- return { error: `Failed to update member role: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2143
+ return {
2144
+ error: `Failed to update member role: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2145
+ };
1670
2146
  }
1671
2147
  },
1672
2148
  });
@@ -1678,11 +2154,17 @@ export function createTeamInviteMemberTool(client, agentSecret) {
1678
2154
  return tool({
1679
2155
  description: "Invite a user to join a team via email. They receive an invitation link. Requires owner or admin role.",
1680
2156
  parameters: z.object({
1681
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
2157
+ team_id: z
2158
+ .string()
2159
+ .regex(UUID_RE, "Must be a valid UUID")
2160
+ .describe("UUID of the team"),
1682
2161
  email: z.string().email().describe("Email address to invite"),
1683
- role: z.enum(["admin", "member"]).optional().describe("Role to assign when they accept (default: member)"),
2162
+ role: z
2163
+ .enum(["admin", "member"])
2164
+ .optional()
2165
+ .describe("Role to assign when they accept (default: member)"),
1684
2166
  }),
1685
- execute: async ({ team_id, email, role }) => {
2167
+ execute: async ({ team_id, email, role, }) => {
1686
2168
  try {
1687
2169
  const body = { email };
1688
2170
  if (role)
@@ -1690,7 +2172,9 @@ export function createTeamInviteMemberTool(client, agentSecret) {
1690
2172
  return await apiRequest(client, "POST", `/api/teams/${encodeURIComponent(team_id)}/invites`, body, agentSecret);
1691
2173
  }
1692
2174
  catch (err) {
1693
- return { error: `Failed to invite member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2175
+ return {
2176
+ error: `Failed to invite member: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2177
+ };
1694
2178
  }
1695
2179
  },
1696
2180
  });
@@ -1702,14 +2186,19 @@ export function createTeamListInvitesTool(client, agentSecret) {
1702
2186
  return tool({
1703
2187
  description: "List all pending invitations for a team.",
1704
2188
  parameters: z.object({
1705
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
2189
+ team_id: z
2190
+ .string()
2191
+ .regex(UUID_RE, "Must be a valid UUID")
2192
+ .describe("UUID of the team"),
1706
2193
  }),
1707
2194
  execute: async ({ team_id }) => {
1708
2195
  try {
1709
2196
  return await apiRequest(client, "GET", `/api/teams/${encodeURIComponent(team_id)}/invites`, undefined, agentSecret);
1710
2197
  }
1711
2198
  catch (err) {
1712
- return { error: `Failed to list invites: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2199
+ return {
2200
+ error: `Failed to list invites: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2201
+ };
1713
2202
  }
1714
2203
  },
1715
2204
  });
@@ -1721,20 +2210,207 @@ export function createTeamCancelInviteTool(client, agentSecret) {
1721
2210
  return tool({
1722
2211
  description: "Cancel a pending team invitation. Requires owner or admin role.",
1723
2212
  parameters: z.object({
1724
- team_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the team"),
1725
- invite_id: z.string().regex(UUID_RE, "Must be a valid UUID").describe("UUID of the invitation to cancel"),
2213
+ team_id: z
2214
+ .string()
2215
+ .regex(UUID_RE, "Must be a valid UUID")
2216
+ .describe("UUID of the team"),
2217
+ invite_id: z
2218
+ .string()
2219
+ .regex(UUID_RE, "Must be a valid UUID")
2220
+ .describe("UUID of the invitation to cancel"),
1726
2221
  }),
1727
- execute: async ({ team_id, invite_id }) => {
2222
+ execute: async ({ team_id, invite_id, }) => {
1728
2223
  try {
1729
2224
  await apiRequest(client, "DELETE", `/api/teams/${encodeURIComponent(team_id)}/invites/${encodeURIComponent(invite_id)}`, undefined, agentSecret);
1730
2225
  return { success: true, message: "Invitation cancelled" };
1731
2226
  }
1732
2227
  catch (err) {
1733
- return { error: `Failed to cancel invite: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}` };
2228
+ return {
2229
+ error: `Failed to cancel invite: ${sanitizeError(err instanceof Error ? err.message : "Unknown error")}`,
2230
+ };
2231
+ }
2232
+ },
2233
+ });
2234
+ }
2235
+ // ---------------------------------------------------------------------------
2236
+ // MPP (Machine Payment Protocol) tools
2237
+ // ---------------------------------------------------------------------------
2238
+ /**
2239
+ * Creates a tool to get MPP protocol info (no auth required).
2240
+ */
2241
+ export function createMppInfoTool(client, agentSecret) {
2242
+ return tool({
2243
+ description: "Get Machine Payment Protocol (MPP) information including enabled status, " +
2244
+ "supported payment methods, pricing, and session limits. No authentication required. " +
2245
+ "MPP enables keyless proxy access -- AI agents can use the proxy WITHOUT any API key " +
2246
+ "by calling mpp_challenge first, then using the returned credential as proxy auth.",
2247
+ parameters: z.object({}),
2248
+ execute: async () => {
2249
+ try {
2250
+ const result = await apiRequest(client, "GET", "/api/mpp/info", undefined, agentSecret);
2251
+ return result;
2252
+ }
2253
+ catch (err) {
2254
+ const message = err instanceof Error ? err.message : "Unknown error";
2255
+ return { error: `Failed to get MPP info: ${sanitizeError(message)}` };
2256
+ }
2257
+ },
2258
+ });
2259
+ }
2260
+ /**
2261
+ * Creates a tool to get an MPP challenge for keyless proxy access (no auth required).
2262
+ */
2263
+ export function createMppChallengeTool(client, agentSecret) {
2264
+ return tool({
2265
+ description: "Get an MPP challenge for keyless proxy access. No authentication required. " +
2266
+ "Returns a credential that can be used to access the proxy WITHOUT any API key -- " +
2267
+ "just pay per request via MPP. Specify 'dc' for datacenter ($3/GB) or " +
2268
+ "'residential' ($5/GB) proxy pool.",
2269
+ parameters: z.object({
2270
+ pool_type: z
2271
+ .enum(["dc", "residential"])
2272
+ .describe("Proxy pool type: 'dc' for datacenter ($3/GB) or 'residential' ($5/GB)"),
2273
+ }),
2274
+ execute: async ({ pool_type }) => {
2275
+ try {
2276
+ const baseUrl = client.baseUrl ||
2277
+ process.env.DOMINUSNODE_BASE_URL ||
2278
+ "https://api.dominusnode.com";
2279
+ const headers = {
2280
+ "Content-Type": "application/json",
2281
+ };
2282
+ if (agentSecret) {
2283
+ headers["X-DominusNode-Agent"] = "mcp";
2284
+ headers["X-DominusNode-Agent-Secret"] = agentSecret;
2285
+ }
2286
+ const resp = await fetch(`${baseUrl}/api/mpp/challenge`, {
2287
+ method: "POST",
2288
+ headers,
2289
+ body: JSON.stringify({ poolType: pool_type }),
2290
+ redirect: "error",
2291
+ });
2292
+ if (!resp.ok) {
2293
+ const text = await resp.text().catch(() => "");
2294
+ throw new Error(`MPP challenge failed (${resp.status}): ${text.slice(0, 200)}`);
2295
+ }
2296
+ const text = await resp.text();
2297
+ if (text.length > MAX_RESPONSE_BODY_BYTES) {
2298
+ throw new Error("Response body exceeds size limit");
2299
+ }
2300
+ const data = JSON.parse(text);
2301
+ stripDangerousKeys(data);
2302
+ return data;
2303
+ }
2304
+ catch (err) {
2305
+ const message = err instanceof Error ? err.message : "Unknown error";
2306
+ return {
2307
+ error: `Failed to get MPP challenge: ${sanitizeError(message)}`,
2308
+ };
2309
+ }
2310
+ },
2311
+ });
2312
+ }
2313
+ /**
2314
+ * Creates a tool to top up wallet via MPP.
2315
+ */
2316
+ export function createPayMppTool(client, agentSecret) {
2317
+ return tool({
2318
+ description: "Top up your Dominus Node wallet via Machine Payment Protocol (MPP). " +
2319
+ "Supports tempo, stripe_spt, and lightning payment methods.",
2320
+ parameters: z.object({
2321
+ amount_cents: z
2322
+ .number()
2323
+ .int()
2324
+ .min(500)
2325
+ .max(100000)
2326
+ .describe("Amount in cents to top up (min 500 = $5, max 100000 = $1,000)"),
2327
+ method: z
2328
+ .enum(["tempo", "stripe_spt", "lightning"])
2329
+ .describe("MPP payment method: tempo, stripe_spt, or lightning"),
2330
+ }),
2331
+ execute: async ({ amount_cents, method, }) => {
2332
+ try {
2333
+ const result = await apiRequest(client, "POST", "/api/mpp/topup", {
2334
+ amountCents: amount_cents,
2335
+ method,
2336
+ }, agentSecret);
2337
+ return result;
2338
+ }
2339
+ catch (err) {
2340
+ const message = err instanceof Error ? err.message : "Unknown error";
2341
+ return { error: `Failed to top up via MPP: ${sanitizeError(message)}` };
2342
+ }
2343
+ },
2344
+ });
2345
+ }
2346
+ /**
2347
+ * Creates a tool to open an MPP pay-as-you-go session.
2348
+ */
2349
+ export function createMppSessionOpenTool(client, agentSecret) {
2350
+ return tool({
2351
+ description: "Open a pay-as-you-go MPP session. Returns a channelId for metered proxy usage. " +
2352
+ "Deposit is held and refunded on close minus usage.",
2353
+ parameters: z.object({
2354
+ max_deposit_cents: z
2355
+ .number()
2356
+ .int()
2357
+ .min(500)
2358
+ .max(100000)
2359
+ .describe("Maximum deposit in cents for the session (min 500, max 100000)"),
2360
+ method: z
2361
+ .enum(["tempo", "stripe_spt", "lightning"])
2362
+ .describe("MPP payment method: tempo, stripe_spt, or lightning"),
2363
+ pool_type: z
2364
+ .enum(["dc", "residential"])
2365
+ .default("dc")
2366
+ .describe("Proxy pool type: dc ($3/GB) or residential ($5/GB)"),
2367
+ }),
2368
+ execute: async ({ max_deposit_cents, method, pool_type, }) => {
2369
+ try {
2370
+ const result = await apiRequest(client, "POST", "/api/mpp/session/open", {
2371
+ maxDepositCents: max_deposit_cents,
2372
+ method,
2373
+ poolType: pool_type,
2374
+ }, agentSecret);
2375
+ return result;
2376
+ }
2377
+ catch (err) {
2378
+ const message = err instanceof Error ? err.message : "Unknown error";
2379
+ return {
2380
+ error: `Failed to open MPP session: ${sanitizeError(message)}`,
2381
+ };
2382
+ }
2383
+ },
2384
+ });
2385
+ }
2386
+ /**
2387
+ * Creates a tool to close an MPP pay-as-you-go session.
2388
+ */
2389
+ export function createMppSessionCloseTool(client, agentSecret) {
2390
+ return tool({
2391
+ description: "Close an MPP pay-as-you-go session. Returns the amount spent and refunded.",
2392
+ parameters: z.object({
2393
+ channel_id: z
2394
+ .string()
2395
+ .min(1)
2396
+ .describe("The channelId returned from mpp_session_open"),
2397
+ }),
2398
+ execute: async ({ channel_id }) => {
2399
+ try {
2400
+ const result = await apiRequest(client, "POST", "/api/mpp/session/close", {
2401
+ channelId: channel_id,
2402
+ }, agentSecret);
2403
+ return result;
2404
+ }
2405
+ catch (err) {
2406
+ const message = err instanceof Error ? err.message : "Unknown error";
2407
+ return {
2408
+ error: `Failed to close MPP session: ${sanitizeError(message)}`,
2409
+ };
1734
2410
  }
1735
2411
  },
1736
2412
  });
1737
2413
  }
1738
2414
  // Re-export validation helpers for testing
1739
- export { validateUrl, isPrivateIp, truncateBody, filterHeaders, apiRequest, UUID_RE, DOMAIN_RE };
2415
+ export { validateUrl, isPrivateIp, truncateBody, filterHeaders, apiRequest, UUID_RE, DOMAIN_RE, };
1740
2416
  //# sourceMappingURL=tools.js.map