@dominusnode/openai-functions 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/README.md +32 -29
- package/dist/handler.d.ts +1 -1
- package/dist/handler.js +480 -96
- package/functions.json +13 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -6,26 +6,26 @@ OpenAI function-calling schemas and handler implementations for the Dominus Node
|
|
|
6
6
|
|
|
7
7
|
This directory contains:
|
|
8
8
|
|
|
9
|
-
| File
|
|
10
|
-
|
|
11
|
-
| `functions.json` | Array of 8 OpenAI function definitions (JSON Schema format)
|
|
12
|
-
| `handler.ts`
|
|
13
|
-
| `handler.py`
|
|
9
|
+
| File | Description |
|
|
10
|
+
| ---------------- | ------------------------------------------------------------------------- |
|
|
11
|
+
| `functions.json` | Array of 8 OpenAI function definitions (JSON Schema format) |
|
|
12
|
+
| `handler.ts` | TypeScript handler that dispatches function calls to the Dominus Node API |
|
|
13
|
+
| `handler.py` | Python handler that dispatches function calls to the Dominus Node API |
|
|
14
14
|
|
|
15
15
|
The function schemas follow the [OpenAI function calling specification](https://platform.openai.com/docs/guides/function-calling), which has become a de facto standard adopted by Claude (tool_use), Gemini, Mistral, Llama, and others.
|
|
16
16
|
|
|
17
17
|
## Available Functions
|
|
18
18
|
|
|
19
|
-
| Function
|
|
20
|
-
|
|
21
|
-
| `dominusnode_proxied_fetch`
|
|
22
|
-
| `dominusnode_check_balance`
|
|
23
|
-
| `dominusnode_check_usage`
|
|
24
|
-
| `dominusnode_get_proxy_config`
|
|
25
|
-
| `dominusnode_list_sessions`
|
|
26
|
-
| `dominusnode_create_agentic_wallet`
|
|
27
|
-
| `dominusnode_fund_agentic_wallet`
|
|
28
|
-
| `dominusnode_agentic_wallet_balance` | Check an agentic wallet's balance and status
|
|
19
|
+
| Function | Description | Auth Required |
|
|
20
|
+
| ------------------------------------ | ------------------------------------------------------------------ | ------------- |
|
|
21
|
+
| `dominusnode_proxied_fetch` | Make an HTTP request through Dominus Node's rotating proxy network | Yes |
|
|
22
|
+
| `dominusnode_check_balance` | Check wallet balance (cents, USD, currency) | Yes |
|
|
23
|
+
| `dominusnode_check_usage` | Check usage stats for a time period (day/week/month) | Yes |
|
|
24
|
+
| `dominusnode_get_proxy_config` | Get proxy endpoints, supported countries, geo-targeting info | Yes |
|
|
25
|
+
| `dominusnode_list_sessions` | List currently active proxy sessions | Yes |
|
|
26
|
+
| `dominusnode_create_agentic_wallet` | Create a sub-wallet for an AI agent with spending limits | Yes |
|
|
27
|
+
| `dominusnode_fund_agentic_wallet` | Transfer funds from main wallet to an agentic wallet | Yes |
|
|
28
|
+
| `dominusnode_agentic_wallet_balance` | Check an agentic wallet's balance and status | Yes |
|
|
29
29
|
|
|
30
30
|
## Usage with OpenAI GPT (Function Calling)
|
|
31
31
|
|
|
@@ -176,13 +176,13 @@ console.log(JSON.parse(fetchResult));
|
|
|
176
176
|
// Example: create and fund an agentic wallet for an AI agent
|
|
177
177
|
const wallet = await handler("dominusnode_create_agentic_wallet", {
|
|
178
178
|
label: "research-agent-1",
|
|
179
|
-
spending_limit_cents: 500,
|
|
179
|
+
spending_limit_cents: 500, // $5.00 per-transaction limit
|
|
180
180
|
});
|
|
181
181
|
const walletData = JSON.parse(wallet);
|
|
182
182
|
|
|
183
183
|
await handler("dominusnode_fund_agentic_wallet", {
|
|
184
184
|
wallet_id: walletData.id,
|
|
185
|
-
amount_cents: 2000,
|
|
185
|
+
amount_cents: 2000, // Fund with $20.00
|
|
186
186
|
});
|
|
187
187
|
```
|
|
188
188
|
|
|
@@ -199,15 +199,15 @@ The `functions.json` file follows the standard OpenAI function definition schema
|
|
|
199
199
|
|
|
200
200
|
### Framework-Specific Notes
|
|
201
201
|
|
|
202
|
-
| Framework
|
|
203
|
-
|
|
204
|
-
| **OpenAI SDK**
|
|
205
|
-
| **Anthropic SDK** | Convert to `tools` format (rename `parameters` to `input_schema`)
|
|
206
|
-
| **Google Gemini** | Convert to `FunctionDeclaration` objects
|
|
207
|
-
| **LangChain**
|
|
208
|
-
| **Vercel AI SDK** | See the `integrations/vercel-ai/` package
|
|
209
|
-
| **LlamaIndex**
|
|
210
|
-
| **Ollama**
|
|
202
|
+
| Framework | How to Use |
|
|
203
|
+
| ----------------- | ------------------------------------------------------------------------------ |
|
|
204
|
+
| **OpenAI SDK** | Pass `functions` directly to `chat.completions.create()` |
|
|
205
|
+
| **Anthropic SDK** | Convert to `tools` format (rename `parameters` to `input_schema`) |
|
|
206
|
+
| **Google Gemini** | Convert to `FunctionDeclaration` objects |
|
|
207
|
+
| **LangChain** | Use `StructuredTool.from_function()` or the Dominus Node LangChain integration |
|
|
208
|
+
| **Vercel AI SDK** | See the `integrations/vercel-ai/` package |
|
|
209
|
+
| **LlamaIndex** | Use `FunctionTool.from_defaults()` with the handler |
|
|
210
|
+
| **Ollama** | Pass as `tools` parameter in chat API |
|
|
211
211
|
|
|
212
212
|
## Security
|
|
213
213
|
|
|
@@ -224,6 +224,7 @@ Both handlers (TypeScript and Python) include comprehensive SSRF prevention that
|
|
|
224
224
|
### Header Injection Prevention
|
|
225
225
|
|
|
226
226
|
User-supplied HTTP headers are filtered to block:
|
|
227
|
+
|
|
227
228
|
- Security-sensitive headers (Host, Authorization, Proxy-Authorization, etc.)
|
|
228
229
|
- CRLF injection attempts (headers containing \r or \n)
|
|
229
230
|
- Null byte injection
|
|
@@ -248,18 +249,20 @@ Requests targeting OFAC-sanctioned countries (CU, IR, KP, RU, SY) are blocked at
|
|
|
248
249
|
|
|
249
250
|
## Proxy Pricing
|
|
250
251
|
|
|
251
|
-
| Proxy Type
|
|
252
|
-
|
|
252
|
+
| Proxy Type | Price | Best For |
|
|
253
|
+
| ----------------- | -------- | -------------------------------------- |
|
|
253
254
|
| Datacenter (`dc`) | $3.00/GB | General scraping, speed-critical tasks |
|
|
254
|
-
| Residential
|
|
255
|
+
| Residential | $5.00/GB | Anti-detection, geo-restricted content |
|
|
255
256
|
|
|
256
257
|
## Dependencies
|
|
257
258
|
|
|
258
259
|
### TypeScript Handler
|
|
260
|
+
|
|
259
261
|
- Node.js 18+ (uses native `fetch` and `AbortSignal.timeout`)
|
|
260
262
|
- No external dependencies
|
|
261
263
|
|
|
262
264
|
### Python Handler
|
|
265
|
+
|
|
263
266
|
- Python 3.8+
|
|
264
267
|
- `httpx` (`pip install httpx`)
|
|
265
268
|
|
package/dist/handler.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node OpenAI-compatible function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 57 tools covering proxy, wallet, usage, account lifecycle, API keys,
|
|
5
5
|
* plans, and teams.
|
|
6
6
|
*
|
|
7
7
|
* Provides a factory function that creates a handler for dispatching
|
package/dist/handler.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node OpenAI-compatible function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 57 tools covering proxy, wallet, usage, account lifecycle, API keys,
|
|
5
5
|
* plans, and teams.
|
|
6
6
|
*
|
|
7
7
|
* Provides a factory function that creates a handler for dispatching
|
|
@@ -25,10 +25,63 @@
|
|
|
25
25
|
*
|
|
26
26
|
* @module
|
|
27
27
|
*/
|
|
28
|
+
import * as crypto from "node:crypto";
|
|
28
29
|
import dns from "dns/promises";
|
|
29
30
|
import * as http from "node:http";
|
|
30
31
|
import * as tls from "node:tls";
|
|
31
32
|
// ---------------------------------------------------------------------------
|
|
33
|
+
// SHA-256 Proof-of-Work solver
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
function countLeadingZeroBits(buf) {
|
|
36
|
+
let count = 0;
|
|
37
|
+
for (const byte of buf) {
|
|
38
|
+
if (byte === 0) {
|
|
39
|
+
count += 8;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
let mask = 0x80;
|
|
43
|
+
while (mask && !(byte & mask)) {
|
|
44
|
+
count++;
|
|
45
|
+
mask >>= 1;
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
return count;
|
|
50
|
+
}
|
|
51
|
+
async function solvePoW(baseUrl) {
|
|
52
|
+
try {
|
|
53
|
+
const resp = await fetch(`${baseUrl}/api/auth/pow/challenge`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "Content-Type": "application/json" },
|
|
56
|
+
redirect: "error",
|
|
57
|
+
});
|
|
58
|
+
if (!resp.ok)
|
|
59
|
+
return null;
|
|
60
|
+
const text = await resp.text();
|
|
61
|
+
if (text.length > 10_485_760)
|
|
62
|
+
return null;
|
|
63
|
+
const challenge = JSON.parse(text);
|
|
64
|
+
const prefix = challenge.prefix ?? "";
|
|
65
|
+
const difficulty = challenge.difficulty ?? 20;
|
|
66
|
+
const challengeId = challenge.challengeId ?? "";
|
|
67
|
+
if (!prefix || !challengeId)
|
|
68
|
+
return null;
|
|
69
|
+
for (let nonce = 0; nonce < 100_000_000; nonce++) {
|
|
70
|
+
const hash = crypto
|
|
71
|
+
.createHash("sha256")
|
|
72
|
+
.update(prefix + nonce.toString())
|
|
73
|
+
.digest();
|
|
74
|
+
if (countLeadingZeroBits(hash) >= difficulty) {
|
|
75
|
+
return { challengeId, nonce: nonce.toString() };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
32
85
|
// SSRF Prevention -- URL validation
|
|
33
86
|
// ---------------------------------------------------------------------------
|
|
34
87
|
const BLOCKED_HOSTNAMES = new Set([
|
|
@@ -284,7 +337,7 @@ async function checkDnsRebinding(hostname) {
|
|
|
284
337
|
// ---------------------------------------------------------------------------
|
|
285
338
|
// Credential sanitization
|
|
286
339
|
// ---------------------------------------------------------------------------
|
|
287
|
-
const CREDENTIAL_RE = /dn_(live|test)_[a-zA-Z0-9]+/g;
|
|
340
|
+
const CREDENTIAL_RE = /dn_(live|test|proxy)_[a-zA-Z0-9]+/g;
|
|
288
341
|
function sanitizeError(message) {
|
|
289
342
|
return message.replace(CREDENTIAL_RE, "***");
|
|
290
343
|
}
|
|
@@ -504,8 +557,13 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
504
557
|
try {
|
|
505
558
|
// Strip security-sensitive headers from user-provided headers
|
|
506
559
|
const BLOCKED_HEADERS = new Set([
|
|
507
|
-
"host",
|
|
508
|
-
"
|
|
560
|
+
"host",
|
|
561
|
+
"connection",
|
|
562
|
+
"content-length",
|
|
563
|
+
"transfer-encoding",
|
|
564
|
+
"proxy-authorization",
|
|
565
|
+
"authorization",
|
|
566
|
+
"user-agent",
|
|
509
567
|
]);
|
|
510
568
|
const safeHeaders = {};
|
|
511
569
|
if (headers) {
|
|
@@ -536,13 +594,18 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
536
594
|
const timeout = setTimeout(() => reject(new Error("Proxy request timed out after 30000ms")), 30_000);
|
|
537
595
|
if (parsed.protocol === "https:") {
|
|
538
596
|
// HTTPS: CONNECT tunnel + TLS
|
|
539
|
-
const connectHost = parsed.hostname.includes(":")
|
|
597
|
+
const connectHost = parsed.hostname.includes(":")
|
|
598
|
+
? `[${parsed.hostname}]`
|
|
599
|
+
: parsed.hostname;
|
|
540
600
|
const connectReq = http.request({
|
|
541
601
|
hostname: proxyHost,
|
|
542
602
|
port: proxyPort,
|
|
543
603
|
method: "CONNECT",
|
|
544
604
|
path: `${connectHost}:${parsed.port || 443}`,
|
|
545
|
-
headers: {
|
|
605
|
+
headers: {
|
|
606
|
+
"Proxy-Authorization": proxyAuth,
|
|
607
|
+
Host: `${connectHost}:${parsed.port || 443}`,
|
|
608
|
+
},
|
|
546
609
|
});
|
|
547
610
|
connectReq.on("connect", (_res, tunnelSocket) => {
|
|
548
611
|
if (_res.statusCode !== 200) {
|
|
@@ -586,7 +649,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
586
649
|
return;
|
|
587
650
|
}
|
|
588
651
|
const headerSection = raw.substring(0, headerEnd);
|
|
589
|
-
const body = raw
|
|
652
|
+
const body = raw
|
|
653
|
+
.substring(headerEnd + 4)
|
|
654
|
+
.substring(0, MAX_BODY_BYTES);
|
|
590
655
|
const statusLine = headerSection.split("\r\n")[0];
|
|
591
656
|
const statusMatch = statusLine.match(/^HTTP\/\d\.\d\s+(\d+)/);
|
|
592
657
|
const status = statusMatch ? parseInt(statusMatch[1], 10) : 0;
|
|
@@ -594,18 +659,29 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
594
659
|
for (const line of headerSection.split("\r\n").slice(1)) {
|
|
595
660
|
const ci = line.indexOf(":");
|
|
596
661
|
if (ci > 0)
|
|
597
|
-
headers[line.substring(0, ci).trim().toLowerCase()] = line
|
|
662
|
+
headers[line.substring(0, ci).trim().toLowerCase()] = line
|
|
663
|
+
.substring(ci + 1)
|
|
664
|
+
.trim();
|
|
598
665
|
}
|
|
599
666
|
stripDangerousKeys(headers);
|
|
600
667
|
resolve({ status, headers, body });
|
|
601
668
|
};
|
|
602
669
|
tlsSocket.on("end", finalize);
|
|
603
670
|
tlsSocket.on("close", finalize);
|
|
604
|
-
tlsSocket.on("error", (err) => {
|
|
671
|
+
tlsSocket.on("error", (err) => {
|
|
672
|
+
clearTimeout(timeout);
|
|
673
|
+
reject(err);
|
|
674
|
+
});
|
|
605
675
|
});
|
|
606
|
-
tlsSocket.on("error", (err) => {
|
|
676
|
+
tlsSocket.on("error", (err) => {
|
|
677
|
+
clearTimeout(timeout);
|
|
678
|
+
reject(err);
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
connectReq.on("error", (err) => {
|
|
682
|
+
clearTimeout(timeout);
|
|
683
|
+
reject(err);
|
|
607
684
|
});
|
|
608
|
-
connectReq.on("error", (err) => { clearTimeout(timeout); reject(err); });
|
|
609
685
|
connectReq.end();
|
|
610
686
|
}
|
|
611
687
|
else {
|
|
@@ -615,19 +691,28 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
615
691
|
port: proxyPort,
|
|
616
692
|
method,
|
|
617
693
|
path: url,
|
|
618
|
-
headers: {
|
|
694
|
+
headers: {
|
|
695
|
+
...safeHeaders,
|
|
696
|
+
"Proxy-Authorization": proxyAuth,
|
|
697
|
+
Host: parsed.host,
|
|
698
|
+
},
|
|
619
699
|
}, (res) => {
|
|
620
700
|
const chunks = [];
|
|
621
701
|
let byteCount = 0;
|
|
622
|
-
res.on("data", (chunk) => {
|
|
623
|
-
|
|
702
|
+
res.on("data", (chunk) => {
|
|
703
|
+
byteCount += chunk.length;
|
|
704
|
+
if (byteCount <= MAX_BODY_BYTES)
|
|
705
|
+
chunks.push(chunk);
|
|
706
|
+
});
|
|
624
707
|
let httpFinalized = false;
|
|
625
708
|
const finalize = () => {
|
|
626
709
|
if (httpFinalized)
|
|
627
710
|
return;
|
|
628
711
|
httpFinalized = true;
|
|
629
712
|
clearTimeout(timeout);
|
|
630
|
-
const body = Buffer.concat(chunks)
|
|
713
|
+
const body = Buffer.concat(chunks)
|
|
714
|
+
.toString("utf-8")
|
|
715
|
+
.substring(0, MAX_BODY_BYTES);
|
|
631
716
|
const headers = {};
|
|
632
717
|
for (const [k, v] of Object.entries(res.headers)) {
|
|
633
718
|
if (v)
|
|
@@ -638,9 +723,15 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
638
723
|
};
|
|
639
724
|
res.on("end", finalize);
|
|
640
725
|
res.on("close", finalize);
|
|
641
|
-
res.on("error", (err) => {
|
|
726
|
+
res.on("error", (err) => {
|
|
727
|
+
clearTimeout(timeout);
|
|
728
|
+
reject(err);
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
req.on("error", (err) => {
|
|
732
|
+
clearTimeout(timeout);
|
|
733
|
+
reject(err);
|
|
642
734
|
});
|
|
643
|
-
req.on("error", (err) => { clearTimeout(timeout); reject(err); });
|
|
644
735
|
req.end();
|
|
645
736
|
}
|
|
646
737
|
});
|
|
@@ -680,13 +771,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
680
771
|
const label = args.label;
|
|
681
772
|
const spendingLimitCents = args.spending_limit_cents;
|
|
682
773
|
if (!label || typeof label !== "string") {
|
|
683
|
-
return JSON.stringify({
|
|
774
|
+
return JSON.stringify({
|
|
775
|
+
error: "label is required and must be a string",
|
|
776
|
+
});
|
|
684
777
|
}
|
|
685
778
|
if (label.length > 100) {
|
|
686
779
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
687
780
|
}
|
|
688
781
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
689
|
-
return JSON.stringify({
|
|
782
|
+
return JSON.stringify({
|
|
783
|
+
error: "label contains invalid control characters",
|
|
784
|
+
});
|
|
690
785
|
}
|
|
691
786
|
if (!Number.isInteger(spendingLimitCents) ||
|
|
692
787
|
spendingLimitCents <= 0 ||
|
|
@@ -702,7 +797,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
702
797
|
// Optional daily_limit_cents
|
|
703
798
|
if (args.daily_limit_cents !== undefined) {
|
|
704
799
|
const dailyLimit = args.daily_limit_cents;
|
|
705
|
-
if (!Number.isInteger(dailyLimit) ||
|
|
800
|
+
if (!Number.isInteger(dailyLimit) ||
|
|
801
|
+
dailyLimit < 1 ||
|
|
802
|
+
dailyLimit > 1_000_000) {
|
|
706
803
|
return JSON.stringify({
|
|
707
804
|
error: "daily_limit_cents must be an integer between 1 and 1,000,000",
|
|
708
805
|
});
|
|
@@ -713,18 +810,26 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
713
810
|
if (args.allowed_domains !== undefined) {
|
|
714
811
|
const domains = args.allowed_domains;
|
|
715
812
|
if (!Array.isArray(domains)) {
|
|
716
|
-
return JSON.stringify({
|
|
813
|
+
return JSON.stringify({
|
|
814
|
+
error: "allowed_domains must be an array of strings",
|
|
815
|
+
});
|
|
717
816
|
}
|
|
718
817
|
if (domains.length > 100) {
|
|
719
|
-
return JSON.stringify({
|
|
818
|
+
return JSON.stringify({
|
|
819
|
+
error: "allowed_domains must have 100 or fewer entries",
|
|
820
|
+
});
|
|
720
821
|
}
|
|
721
822
|
const domainRe = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/;
|
|
722
823
|
for (const d of domains) {
|
|
723
824
|
if (typeof d !== "string") {
|
|
724
|
-
return JSON.stringify({
|
|
825
|
+
return JSON.stringify({
|
|
826
|
+
error: "Each allowed_domains entry must be a string",
|
|
827
|
+
});
|
|
725
828
|
}
|
|
726
829
|
if (d.length > 253) {
|
|
727
|
-
return JSON.stringify({
|
|
830
|
+
return JSON.stringify({
|
|
831
|
+
error: "Each allowed_domains entry must be 253 characters or fewer",
|
|
832
|
+
});
|
|
728
833
|
}
|
|
729
834
|
if (!domainRe.test(d)) {
|
|
730
835
|
return JSON.stringify({ error: `Invalid domain format: ${d}` });
|
|
@@ -739,7 +844,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
739
844
|
const walletId = args.wallet_id;
|
|
740
845
|
const amountCents = args.amount_cents;
|
|
741
846
|
if (!walletId || typeof walletId !== "string") {
|
|
742
|
-
return JSON.stringify({
|
|
847
|
+
return JSON.stringify({
|
|
848
|
+
error: "wallet_id is required and must be a string",
|
|
849
|
+
});
|
|
743
850
|
}
|
|
744
851
|
if (!Number.isInteger(amountCents) ||
|
|
745
852
|
amountCents <= 0 ||
|
|
@@ -754,7 +861,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
754
861
|
async function handleAgenticWalletBalance(args) {
|
|
755
862
|
const walletId = args.wallet_id;
|
|
756
863
|
if (!walletId || typeof walletId !== "string") {
|
|
757
|
-
return JSON.stringify({
|
|
864
|
+
return JSON.stringify({
|
|
865
|
+
error: "wallet_id is required and must be a string",
|
|
866
|
+
});
|
|
758
867
|
}
|
|
759
868
|
const result = await api("GET", `/api/agent-wallet/${encodeURIComponent(walletId)}`);
|
|
760
869
|
return JSON.stringify(result);
|
|
@@ -766,13 +875,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
766
875
|
async function handleAgenticTransactions(args) {
|
|
767
876
|
const walletId = args.wallet_id;
|
|
768
877
|
if (!walletId || typeof walletId !== "string") {
|
|
769
|
-
return JSON.stringify({
|
|
878
|
+
return JSON.stringify({
|
|
879
|
+
error: "wallet_id is required and must be a string",
|
|
880
|
+
});
|
|
770
881
|
}
|
|
771
882
|
const limit = args.limit;
|
|
772
883
|
const params = new URLSearchParams();
|
|
773
884
|
if (limit !== undefined) {
|
|
774
885
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
775
|
-
return JSON.stringify({
|
|
886
|
+
return JSON.stringify({
|
|
887
|
+
error: "limit must be an integer between 1 and 100",
|
|
888
|
+
});
|
|
776
889
|
}
|
|
777
890
|
params.set("limit", String(limit));
|
|
778
891
|
}
|
|
@@ -783,7 +896,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
783
896
|
async function handleFreezeAgenticWallet(args) {
|
|
784
897
|
const walletId = args.wallet_id;
|
|
785
898
|
if (!walletId || typeof walletId !== "string") {
|
|
786
|
-
return JSON.stringify({
|
|
899
|
+
return JSON.stringify({
|
|
900
|
+
error: "wallet_id is required and must be a string",
|
|
901
|
+
});
|
|
787
902
|
}
|
|
788
903
|
const result = await api("POST", `/api/agent-wallet/${encodeURIComponent(walletId)}/freeze`);
|
|
789
904
|
return JSON.stringify(result);
|
|
@@ -791,7 +906,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
791
906
|
async function handleUnfreezeAgenticWallet(args) {
|
|
792
907
|
const walletId = args.wallet_id;
|
|
793
908
|
if (!walletId || typeof walletId !== "string") {
|
|
794
|
-
return JSON.stringify({
|
|
909
|
+
return JSON.stringify({
|
|
910
|
+
error: "wallet_id is required and must be a string",
|
|
911
|
+
});
|
|
795
912
|
}
|
|
796
913
|
const result = await api("POST", `/api/agent-wallet/${encodeURIComponent(walletId)}/unfreeze`);
|
|
797
914
|
return JSON.stringify(result);
|
|
@@ -799,7 +916,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
799
916
|
async function handleDeleteAgenticWallet(args) {
|
|
800
917
|
const walletId = args.wallet_id;
|
|
801
918
|
if (!walletId || typeof walletId !== "string") {
|
|
802
|
-
return JSON.stringify({
|
|
919
|
+
return JSON.stringify({
|
|
920
|
+
error: "wallet_id is required and must be a string",
|
|
921
|
+
});
|
|
803
922
|
}
|
|
804
923
|
const result = await api("DELETE", `/api/agent-wallet/${encodeURIComponent(walletId)}`);
|
|
805
924
|
return JSON.stringify(result);
|
|
@@ -813,13 +932,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
813
932
|
return JSON.stringify({ error: "name must be 100 characters or fewer" });
|
|
814
933
|
}
|
|
815
934
|
if (/[\x00-\x1f\x7f]/.test(name)) {
|
|
816
|
-
return JSON.stringify({
|
|
935
|
+
return JSON.stringify({
|
|
936
|
+
error: "name contains invalid control characters",
|
|
937
|
+
});
|
|
817
938
|
}
|
|
818
939
|
const body = { name };
|
|
819
940
|
if (args.max_members !== undefined) {
|
|
820
941
|
const maxMembers = Number(args.max_members);
|
|
821
942
|
if (!Number.isInteger(maxMembers) || maxMembers < 1 || maxMembers > 100) {
|
|
822
|
-
return JSON.stringify({
|
|
943
|
+
return JSON.stringify({
|
|
944
|
+
error: "max_members must be an integer between 1 and 100",
|
|
945
|
+
});
|
|
823
946
|
}
|
|
824
947
|
body.maxMembers = maxMembers;
|
|
825
948
|
}
|
|
@@ -833,7 +956,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
833
956
|
async function handleTeamDetails(args) {
|
|
834
957
|
const teamId = args.team_id;
|
|
835
958
|
if (!teamId || typeof teamId !== "string") {
|
|
836
|
-
return JSON.stringify({
|
|
959
|
+
return JSON.stringify({
|
|
960
|
+
error: "team_id is required and must be a string",
|
|
961
|
+
});
|
|
837
962
|
}
|
|
838
963
|
const result = await api("GET", `/api/teams/${encodeURIComponent(teamId)}`);
|
|
839
964
|
return JSON.stringify(result);
|
|
@@ -842,7 +967,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
842
967
|
const teamId = args.team_id;
|
|
843
968
|
const amountCents = args.amount_cents;
|
|
844
969
|
if (!teamId || typeof teamId !== "string") {
|
|
845
|
-
return JSON.stringify({
|
|
970
|
+
return JSON.stringify({
|
|
971
|
+
error: "team_id is required and must be a string",
|
|
972
|
+
});
|
|
846
973
|
}
|
|
847
974
|
if (!Number.isInteger(amountCents) ||
|
|
848
975
|
amountCents < 100 ||
|
|
@@ -858,16 +985,22 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
858
985
|
const teamId = args.team_id;
|
|
859
986
|
const label = args.label;
|
|
860
987
|
if (!teamId || typeof teamId !== "string") {
|
|
861
|
-
return JSON.stringify({
|
|
988
|
+
return JSON.stringify({
|
|
989
|
+
error: "team_id is required and must be a string",
|
|
990
|
+
});
|
|
862
991
|
}
|
|
863
992
|
if (!label || typeof label !== "string") {
|
|
864
|
-
return JSON.stringify({
|
|
993
|
+
return JSON.stringify({
|
|
994
|
+
error: "label is required and must be a string",
|
|
995
|
+
});
|
|
865
996
|
}
|
|
866
997
|
if (label.length > 100) {
|
|
867
998
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
868
999
|
}
|
|
869
1000
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
870
|
-
return JSON.stringify({
|
|
1001
|
+
return JSON.stringify({
|
|
1002
|
+
error: "label contains invalid control characters",
|
|
1003
|
+
});
|
|
871
1004
|
}
|
|
872
1005
|
const result = await api("POST", `/api/teams/${encodeURIComponent(teamId)}/keys`, { label });
|
|
873
1006
|
return JSON.stringify(result);
|
|
@@ -875,13 +1008,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
875
1008
|
async function handleTeamUsage(args) {
|
|
876
1009
|
const teamId = args.team_id;
|
|
877
1010
|
if (!teamId || typeof teamId !== "string") {
|
|
878
|
-
return JSON.stringify({
|
|
1011
|
+
return JSON.stringify({
|
|
1012
|
+
error: "team_id is required and must be a string",
|
|
1013
|
+
});
|
|
879
1014
|
}
|
|
880
1015
|
const limit = args.limit;
|
|
881
1016
|
const params = new URLSearchParams();
|
|
882
1017
|
if (limit !== undefined) {
|
|
883
1018
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
884
|
-
return JSON.stringify({
|
|
1019
|
+
return JSON.stringify({
|
|
1020
|
+
error: "limit must be an integer between 1 and 100",
|
|
1021
|
+
});
|
|
885
1022
|
}
|
|
886
1023
|
params.set("limit", String(limit));
|
|
887
1024
|
}
|
|
@@ -892,7 +1029,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
892
1029
|
async function handleUpdateTeam(args) {
|
|
893
1030
|
const teamId = args.team_id;
|
|
894
1031
|
if (!teamId || typeof teamId !== "string") {
|
|
895
|
-
return JSON.stringify({
|
|
1032
|
+
return JSON.stringify({
|
|
1033
|
+
error: "team_id is required and must be a string",
|
|
1034
|
+
});
|
|
896
1035
|
}
|
|
897
1036
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
898
1037
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -904,22 +1043,30 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
904
1043
|
return JSON.stringify({ error: "name must be a non-empty string" });
|
|
905
1044
|
}
|
|
906
1045
|
if (name.length > 100) {
|
|
907
|
-
return JSON.stringify({
|
|
1046
|
+
return JSON.stringify({
|
|
1047
|
+
error: "name must be 100 characters or fewer",
|
|
1048
|
+
});
|
|
908
1049
|
}
|
|
909
1050
|
if (/[\x00-\x1f\x7f]/.test(name)) {
|
|
910
|
-
return JSON.stringify({
|
|
1051
|
+
return JSON.stringify({
|
|
1052
|
+
error: "name contains invalid control characters",
|
|
1053
|
+
});
|
|
911
1054
|
}
|
|
912
1055
|
body.name = name;
|
|
913
1056
|
}
|
|
914
1057
|
if (args.max_members !== undefined) {
|
|
915
1058
|
const maxMembers = Number(args.max_members);
|
|
916
1059
|
if (!Number.isInteger(maxMembers) || maxMembers < 1 || maxMembers > 100) {
|
|
917
|
-
return JSON.stringify({
|
|
1060
|
+
return JSON.stringify({
|
|
1061
|
+
error: "max_members must be an integer between 1 and 100",
|
|
1062
|
+
});
|
|
918
1063
|
}
|
|
919
1064
|
body.maxMembers = maxMembers;
|
|
920
1065
|
}
|
|
921
1066
|
if (Object.keys(body).length === 0) {
|
|
922
|
-
return JSON.stringify({
|
|
1067
|
+
return JSON.stringify({
|
|
1068
|
+
error: "At least one of name or max_members must be provided",
|
|
1069
|
+
});
|
|
923
1070
|
}
|
|
924
1071
|
const result = await api("PATCH", `/api/teams/${encodeURIComponent(teamId)}`, body);
|
|
925
1072
|
return JSON.stringify(result);
|
|
@@ -933,7 +1080,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
933
1080
|
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
934
1081
|
});
|
|
935
1082
|
}
|
|
936
|
-
const result = await api("POST", "/api/wallet/topup/paypal", {
|
|
1083
|
+
const result = await api("POST", "/api/wallet/topup/paypal", {
|
|
1084
|
+
amountCents,
|
|
1085
|
+
});
|
|
937
1086
|
return JSON.stringify(result);
|
|
938
1087
|
}
|
|
939
1088
|
async function handleTopupStripe(args) {
|
|
@@ -945,21 +1094,38 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
945
1094
|
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
946
1095
|
});
|
|
947
1096
|
}
|
|
948
|
-
const result = await api("POST", "/api/wallet/topup/stripe", {
|
|
1097
|
+
const result = await api("POST", "/api/wallet/topup/stripe", {
|
|
1098
|
+
amountCents,
|
|
1099
|
+
});
|
|
949
1100
|
return JSON.stringify(result);
|
|
950
1101
|
}
|
|
951
1102
|
async function handleTopupCrypto(args) {
|
|
952
1103
|
const amountUsd = args.amount_usd;
|
|
953
1104
|
const currency = args.currency;
|
|
954
|
-
if (typeof amountUsd !== "number" ||
|
|
1105
|
+
if (typeof amountUsd !== "number" ||
|
|
1106
|
+
!Number.isFinite(amountUsd) ||
|
|
1107
|
+
amountUsd < 5 ||
|
|
1108
|
+
amountUsd > 1000) {
|
|
955
1109
|
return JSON.stringify({
|
|
956
1110
|
error: "amount_usd must be a number between 5 and 1,000",
|
|
957
1111
|
});
|
|
958
1112
|
}
|
|
959
1113
|
const validCurrencies = new Set([
|
|
960
|
-
"BTC",
|
|
1114
|
+
"BTC",
|
|
1115
|
+
"ETH",
|
|
1116
|
+
"LTC",
|
|
1117
|
+
"XMR",
|
|
1118
|
+
"ZEC",
|
|
1119
|
+
"USDC",
|
|
1120
|
+
"SOL",
|
|
1121
|
+
"USDT",
|
|
1122
|
+
"DAI",
|
|
1123
|
+
"BNB",
|
|
1124
|
+
"LINK",
|
|
961
1125
|
]);
|
|
962
|
-
if (!currency ||
|
|
1126
|
+
if (!currency ||
|
|
1127
|
+
typeof currency !== "string" ||
|
|
1128
|
+
!validCurrencies.has(currency.toUpperCase())) {
|
|
963
1129
|
return JSON.stringify({
|
|
964
1130
|
error: "currency must be one of: BTC, ETH, LTC, XMR, ZEC, USDC, SOL, USDT, DAI, BNB, LINK",
|
|
965
1131
|
});
|
|
@@ -973,7 +1139,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
973
1139
|
async function handleUpdateWalletPolicy(args) {
|
|
974
1140
|
const walletId = args.wallet_id;
|
|
975
1141
|
if (!walletId || typeof walletId !== "string") {
|
|
976
|
-
return JSON.stringify({
|
|
1142
|
+
return JSON.stringify({
|
|
1143
|
+
error: "wallet_id is required and must be a string",
|
|
1144
|
+
});
|
|
977
1145
|
}
|
|
978
1146
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(walletId)) {
|
|
979
1147
|
return JSON.stringify({ error: "wallet_id must be a valid UUID" });
|
|
@@ -986,7 +1154,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
986
1154
|
}
|
|
987
1155
|
else {
|
|
988
1156
|
const dailyLimit = args.daily_limit_cents;
|
|
989
|
-
if (!Number.isInteger(dailyLimit) ||
|
|
1157
|
+
if (!Number.isInteger(dailyLimit) ||
|
|
1158
|
+
dailyLimit < 1 ||
|
|
1159
|
+
dailyLimit > 1_000_000) {
|
|
990
1160
|
return JSON.stringify({
|
|
991
1161
|
error: "daily_limit_cents must be an integer between 1 and 1,000,000 (or null to remove)",
|
|
992
1162
|
});
|
|
@@ -1002,18 +1172,26 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1002
1172
|
else {
|
|
1003
1173
|
const domains = args.allowed_domains;
|
|
1004
1174
|
if (!Array.isArray(domains)) {
|
|
1005
|
-
return JSON.stringify({
|
|
1175
|
+
return JSON.stringify({
|
|
1176
|
+
error: "allowed_domains must be an array of strings or null",
|
|
1177
|
+
});
|
|
1006
1178
|
}
|
|
1007
1179
|
if (domains.length > 100) {
|
|
1008
|
-
return JSON.stringify({
|
|
1180
|
+
return JSON.stringify({
|
|
1181
|
+
error: "allowed_domains must have 100 or fewer entries",
|
|
1182
|
+
});
|
|
1009
1183
|
}
|
|
1010
1184
|
const domainRe = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/;
|
|
1011
1185
|
for (const d of domains) {
|
|
1012
1186
|
if (typeof d !== "string") {
|
|
1013
|
-
return JSON.stringify({
|
|
1187
|
+
return JSON.stringify({
|
|
1188
|
+
error: "Each allowed_domains entry must be a string",
|
|
1189
|
+
});
|
|
1014
1190
|
}
|
|
1015
1191
|
if (d.length > 253) {
|
|
1016
|
-
return JSON.stringify({
|
|
1192
|
+
return JSON.stringify({
|
|
1193
|
+
error: "Each allowed_domains entry must be 253 characters or fewer",
|
|
1194
|
+
});
|
|
1017
1195
|
}
|
|
1018
1196
|
if (!domainRe.test(d)) {
|
|
1019
1197
|
return JSON.stringify({ error: `Invalid domain format: ${d}` });
|
|
@@ -1023,7 +1201,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1023
1201
|
}
|
|
1024
1202
|
}
|
|
1025
1203
|
if (Object.keys(body).length === 0) {
|
|
1026
|
-
return JSON.stringify({
|
|
1204
|
+
return JSON.stringify({
|
|
1205
|
+
error: "At least one of daily_limit_cents or allowed_domains must be provided",
|
|
1206
|
+
});
|
|
1027
1207
|
}
|
|
1028
1208
|
const result = await api("PATCH", `/api/agent-wallet/${encodeURIComponent(walletId)}/policy`, body);
|
|
1029
1209
|
return JSON.stringify(result);
|
|
@@ -1033,13 +1213,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1033
1213
|
const userId = args.user_id;
|
|
1034
1214
|
const role = args.role;
|
|
1035
1215
|
if (!teamId || typeof teamId !== "string") {
|
|
1036
|
-
return JSON.stringify({
|
|
1216
|
+
return JSON.stringify({
|
|
1217
|
+
error: "team_id is required and must be a string",
|
|
1218
|
+
});
|
|
1037
1219
|
}
|
|
1038
1220
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1039
1221
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1040
1222
|
}
|
|
1041
1223
|
if (!userId || typeof userId !== "string") {
|
|
1042
|
-
return JSON.stringify({
|
|
1224
|
+
return JSON.stringify({
|
|
1225
|
+
error: "user_id is required and must be a string",
|
|
1226
|
+
});
|
|
1043
1227
|
}
|
|
1044
1228
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
1045
1229
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -1068,7 +1252,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1068
1252
|
if (args.limit !== undefined) {
|
|
1069
1253
|
const limit = args.limit;
|
|
1070
1254
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
1071
|
-
return JSON.stringify({
|
|
1255
|
+
return JSON.stringify({
|
|
1256
|
+
error: "limit must be an integer between 1 and 100",
|
|
1257
|
+
});
|
|
1072
1258
|
}
|
|
1073
1259
|
params.set("limit", String(limit));
|
|
1074
1260
|
}
|
|
@@ -1083,7 +1269,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1083
1269
|
async function handleCheckPayment(args) {
|
|
1084
1270
|
const invoiceId = args.invoice_id;
|
|
1085
1271
|
if (!invoiceId || typeof invoiceId !== "string") {
|
|
1086
|
-
return JSON.stringify({
|
|
1272
|
+
return JSON.stringify({
|
|
1273
|
+
error: "invoice_id is required and must be a string",
|
|
1274
|
+
});
|
|
1087
1275
|
}
|
|
1088
1276
|
const result = await api("GET", `/api/wallet/topup/crypto/${encodeURIComponent(invoiceId)}/status`);
|
|
1089
1277
|
return JSON.stringify(result);
|
|
@@ -1094,7 +1282,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1094
1282
|
async function handleGetDailyUsage(args) {
|
|
1095
1283
|
const days = args.days ?? 30;
|
|
1096
1284
|
if (!Number.isInteger(days) || days < 1 || days > 90) {
|
|
1097
|
-
return JSON.stringify({
|
|
1285
|
+
return JSON.stringify({
|
|
1286
|
+
error: "days must be an integer between 1 and 90",
|
|
1287
|
+
});
|
|
1098
1288
|
}
|
|
1099
1289
|
const params = new URLSearchParams({ days: String(days) });
|
|
1100
1290
|
const result = await api("GET", `/api/usage/daily?${params.toString()}`);
|
|
@@ -1105,7 +1295,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1105
1295
|
if (args.limit !== undefined) {
|
|
1106
1296
|
const limit = args.limit;
|
|
1107
1297
|
if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
|
|
1108
|
-
return JSON.stringify({
|
|
1298
|
+
return JSON.stringify({
|
|
1299
|
+
error: "limit must be an integer between 1 and 50",
|
|
1300
|
+
});
|
|
1109
1301
|
}
|
|
1110
1302
|
params.set("limit", String(limit));
|
|
1111
1303
|
}
|
|
@@ -1120,16 +1312,22 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1120
1312
|
const email = args.email;
|
|
1121
1313
|
const password = args.password;
|
|
1122
1314
|
if (!email || typeof email !== "string") {
|
|
1123
|
-
return JSON.stringify({
|
|
1315
|
+
return JSON.stringify({
|
|
1316
|
+
error: "email is required and must be a string",
|
|
1317
|
+
});
|
|
1124
1318
|
}
|
|
1125
1319
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1126
1320
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1127
1321
|
}
|
|
1128
1322
|
if (!password || typeof password !== "string") {
|
|
1129
|
-
return JSON.stringify({
|
|
1323
|
+
return JSON.stringify({
|
|
1324
|
+
error: "password is required and must be a string",
|
|
1325
|
+
});
|
|
1130
1326
|
}
|
|
1131
1327
|
if (password.length < 8 || password.length > 128) {
|
|
1132
|
-
return JSON.stringify({
|
|
1328
|
+
return JSON.stringify({
|
|
1329
|
+
error: "password must be between 8 and 128 characters",
|
|
1330
|
+
});
|
|
1133
1331
|
}
|
|
1134
1332
|
const headers = {
|
|
1135
1333
|
"User-Agent": "dominusnode-openai-functions/1.0.0",
|
|
@@ -1139,10 +1337,15 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1139
1337
|
headers["X-DominusNode-Agent"] = "mcp";
|
|
1140
1338
|
headers["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1141
1339
|
}
|
|
1340
|
+
// Solve PoW for CAPTCHA-free registration
|
|
1341
|
+
const pow = await solvePoW(baseUrl);
|
|
1342
|
+
const regBody = { email, password };
|
|
1343
|
+
if (pow)
|
|
1344
|
+
regBody.pow = pow;
|
|
1142
1345
|
const response = await fetch(`${baseUrl}/api/auth/register`, {
|
|
1143
1346
|
method: "POST",
|
|
1144
1347
|
headers,
|
|
1145
|
-
body: JSON.stringify(
|
|
1348
|
+
body: JSON.stringify(regBody),
|
|
1146
1349
|
signal: AbortSignal.timeout(timeoutMs),
|
|
1147
1350
|
redirect: "error",
|
|
1148
1351
|
});
|
|
@@ -1161,26 +1364,38 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1161
1364
|
}
|
|
1162
1365
|
if (message.length > 500)
|
|
1163
1366
|
message = message.slice(0, 500) + "... [truncated]";
|
|
1164
|
-
return JSON.stringify({
|
|
1367
|
+
return JSON.stringify({
|
|
1368
|
+
error: `Registration failed: ${sanitizeError(message)}`,
|
|
1369
|
+
});
|
|
1165
1370
|
}
|
|
1166
1371
|
const data = safeJsonParse(text);
|
|
1167
1372
|
stripDangerousKeys(data);
|
|
1168
|
-
return JSON.stringify({
|
|
1373
|
+
return JSON.stringify({
|
|
1374
|
+
userId: data.userId,
|
|
1375
|
+
email: data.email,
|
|
1376
|
+
message: data.message,
|
|
1377
|
+
});
|
|
1169
1378
|
}
|
|
1170
1379
|
async function handleLogin(args) {
|
|
1171
1380
|
const email = args.email;
|
|
1172
1381
|
const password = args.password;
|
|
1173
1382
|
if (!email || typeof email !== "string") {
|
|
1174
|
-
return JSON.stringify({
|
|
1383
|
+
return JSON.stringify({
|
|
1384
|
+
error: "email is required and must be a string",
|
|
1385
|
+
});
|
|
1175
1386
|
}
|
|
1176
1387
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1177
1388
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1178
1389
|
}
|
|
1179
1390
|
if (!password || typeof password !== "string") {
|
|
1180
|
-
return JSON.stringify({
|
|
1391
|
+
return JSON.stringify({
|
|
1392
|
+
error: "password is required and must be a string",
|
|
1393
|
+
});
|
|
1181
1394
|
}
|
|
1182
1395
|
if (password.length < 8 || password.length > 128) {
|
|
1183
|
-
return JSON.stringify({
|
|
1396
|
+
return JSON.stringify({
|
|
1397
|
+
error: "password must be between 8 and 128 characters",
|
|
1398
|
+
});
|
|
1184
1399
|
}
|
|
1185
1400
|
const headers = {
|
|
1186
1401
|
"User-Agent": "dominusnode-openai-functions/1.0.0",
|
|
@@ -1212,7 +1427,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1212
1427
|
}
|
|
1213
1428
|
if (message.length > 500)
|
|
1214
1429
|
message = message.slice(0, 500) + "... [truncated]";
|
|
1215
|
-
return JSON.stringify({
|
|
1430
|
+
return JSON.stringify({
|
|
1431
|
+
error: `Login failed: ${sanitizeError(message)}`,
|
|
1432
|
+
});
|
|
1216
1433
|
}
|
|
1217
1434
|
const data = safeJsonParse(text);
|
|
1218
1435
|
stripDangerousKeys(data);
|
|
@@ -1225,7 +1442,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1225
1442
|
async function handleVerifyEmail(args) {
|
|
1226
1443
|
const token = args.token;
|
|
1227
1444
|
if (!token || typeof token !== "string") {
|
|
1228
|
-
return JSON.stringify({
|
|
1445
|
+
return JSON.stringify({
|
|
1446
|
+
error: "token is required and must be a string",
|
|
1447
|
+
});
|
|
1229
1448
|
}
|
|
1230
1449
|
const headers = {
|
|
1231
1450
|
"User-Agent": "dominusnode-openai-functions/1.0.0",
|
|
@@ -1257,7 +1476,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1257
1476
|
}
|
|
1258
1477
|
if (message.length > 500)
|
|
1259
1478
|
message = message.slice(0, 500) + "... [truncated]";
|
|
1260
|
-
return JSON.stringify({
|
|
1479
|
+
return JSON.stringify({
|
|
1480
|
+
error: `Email verification failed: ${sanitizeError(message)}`,
|
|
1481
|
+
});
|
|
1261
1482
|
}
|
|
1262
1483
|
const data = safeJsonParse(text);
|
|
1263
1484
|
stripDangerousKeys(data);
|
|
@@ -1271,13 +1492,19 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1271
1492
|
const currentPassword = args.current_password;
|
|
1272
1493
|
const newPassword = args.new_password;
|
|
1273
1494
|
if (!currentPassword || typeof currentPassword !== "string") {
|
|
1274
|
-
return JSON.stringify({
|
|
1495
|
+
return JSON.stringify({
|
|
1496
|
+
error: "current_password is required and must be a string",
|
|
1497
|
+
});
|
|
1275
1498
|
}
|
|
1276
1499
|
if (!newPassword || typeof newPassword !== "string") {
|
|
1277
|
-
return JSON.stringify({
|
|
1500
|
+
return JSON.stringify({
|
|
1501
|
+
error: "new_password is required and must be a string",
|
|
1502
|
+
});
|
|
1278
1503
|
}
|
|
1279
1504
|
if (newPassword.length < 8 || newPassword.length > 128) {
|
|
1280
|
-
return JSON.stringify({
|
|
1505
|
+
return JSON.stringify({
|
|
1506
|
+
error: "new_password must be between 8 and 128 characters",
|
|
1507
|
+
});
|
|
1281
1508
|
}
|
|
1282
1509
|
const result = await api("POST", "/api/auth/change-password", {
|
|
1283
1510
|
currentPassword,
|
|
@@ -1295,13 +1522,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1295
1522
|
async function handleCreateKey(args) {
|
|
1296
1523
|
const label = args.label;
|
|
1297
1524
|
if (!label || typeof label !== "string") {
|
|
1298
|
-
return JSON.stringify({
|
|
1525
|
+
return JSON.stringify({
|
|
1526
|
+
error: "label is required and must be a string",
|
|
1527
|
+
});
|
|
1299
1528
|
}
|
|
1300
1529
|
if (label.length > 100) {
|
|
1301
1530
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
1302
1531
|
}
|
|
1303
1532
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
1304
|
-
return JSON.stringify({
|
|
1533
|
+
return JSON.stringify({
|
|
1534
|
+
error: "label contains invalid control characters",
|
|
1535
|
+
});
|
|
1305
1536
|
}
|
|
1306
1537
|
const result = await api("POST", "/api/keys", { label });
|
|
1307
1538
|
return JSON.stringify(result);
|
|
@@ -1309,7 +1540,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1309
1540
|
async function handleRevokeKey(args) {
|
|
1310
1541
|
const keyId = args.key_id;
|
|
1311
1542
|
if (!keyId || typeof keyId !== "string") {
|
|
1312
|
-
return JSON.stringify({
|
|
1543
|
+
return JSON.stringify({
|
|
1544
|
+
error: "key_id is required and must be a string",
|
|
1545
|
+
});
|
|
1313
1546
|
}
|
|
1314
1547
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(keyId)) {
|
|
1315
1548
|
return JSON.stringify({ error: "key_id must be a valid UUID" });
|
|
@@ -1331,7 +1564,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1331
1564
|
async function handleChangePlan(args) {
|
|
1332
1565
|
const planId = args.plan_id;
|
|
1333
1566
|
if (!planId || typeof planId !== "string") {
|
|
1334
|
-
return JSON.stringify({
|
|
1567
|
+
return JSON.stringify({
|
|
1568
|
+
error: "plan_id is required and must be a string",
|
|
1569
|
+
});
|
|
1335
1570
|
}
|
|
1336
1571
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(planId)) {
|
|
1337
1572
|
return JSON.stringify({ error: "plan_id must be a valid UUID" });
|
|
@@ -1345,7 +1580,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1345
1580
|
async function handleTeamDelete(args) {
|
|
1346
1581
|
const teamId = args.team_id;
|
|
1347
1582
|
if (!teamId || typeof teamId !== "string") {
|
|
1348
|
-
return JSON.stringify({
|
|
1583
|
+
return JSON.stringify({
|
|
1584
|
+
error: "team_id is required and must be a string",
|
|
1585
|
+
});
|
|
1349
1586
|
}
|
|
1350
1587
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1351
1588
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1357,13 +1594,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1357
1594
|
const teamId = args.team_id;
|
|
1358
1595
|
const keyId = args.key_id;
|
|
1359
1596
|
if (!teamId || typeof teamId !== "string") {
|
|
1360
|
-
return JSON.stringify({
|
|
1597
|
+
return JSON.stringify({
|
|
1598
|
+
error: "team_id is required and must be a string",
|
|
1599
|
+
});
|
|
1361
1600
|
}
|
|
1362
1601
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1363
1602
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1364
1603
|
}
|
|
1365
1604
|
if (!keyId || typeof keyId !== "string") {
|
|
1366
|
-
return JSON.stringify({
|
|
1605
|
+
return JSON.stringify({
|
|
1606
|
+
error: "key_id is required and must be a string",
|
|
1607
|
+
});
|
|
1367
1608
|
}
|
|
1368
1609
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(keyId)) {
|
|
1369
1610
|
return JSON.stringify({ error: "key_id must be a valid UUID" });
|
|
@@ -1374,7 +1615,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1374
1615
|
async function handleTeamListKeys(args) {
|
|
1375
1616
|
const teamId = args.team_id;
|
|
1376
1617
|
if (!teamId || typeof teamId !== "string") {
|
|
1377
|
-
return JSON.stringify({
|
|
1618
|
+
return JSON.stringify({
|
|
1619
|
+
error: "team_id is required and must be a string",
|
|
1620
|
+
});
|
|
1378
1621
|
}
|
|
1379
1622
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1380
1623
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1385,7 +1628,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1385
1628
|
async function handleTeamListMembers(args) {
|
|
1386
1629
|
const teamId = args.team_id;
|
|
1387
1630
|
if (!teamId || typeof teamId !== "string") {
|
|
1388
|
-
return JSON.stringify({
|
|
1631
|
+
return JSON.stringify({
|
|
1632
|
+
error: "team_id is required and must be a string",
|
|
1633
|
+
});
|
|
1389
1634
|
}
|
|
1390
1635
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1391
1636
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1397,13 +1642,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1397
1642
|
const teamId = args.team_id;
|
|
1398
1643
|
const userId = args.user_id;
|
|
1399
1644
|
if (!teamId || typeof teamId !== "string") {
|
|
1400
|
-
return JSON.stringify({
|
|
1645
|
+
return JSON.stringify({
|
|
1646
|
+
error: "team_id is required and must be a string",
|
|
1647
|
+
});
|
|
1401
1648
|
}
|
|
1402
1649
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1403
1650
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1404
1651
|
}
|
|
1405
1652
|
if (!userId || typeof userId !== "string") {
|
|
1406
|
-
return JSON.stringify({
|
|
1653
|
+
return JSON.stringify({
|
|
1654
|
+
error: "user_id is required and must be a string",
|
|
1655
|
+
});
|
|
1407
1656
|
}
|
|
1408
1657
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
1409
1658
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -1415,13 +1664,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1415
1664
|
const teamId = args.team_id;
|
|
1416
1665
|
const userId = args.user_id;
|
|
1417
1666
|
if (!teamId || typeof teamId !== "string") {
|
|
1418
|
-
return JSON.stringify({
|
|
1667
|
+
return JSON.stringify({
|
|
1668
|
+
error: "team_id is required and must be a string",
|
|
1669
|
+
});
|
|
1419
1670
|
}
|
|
1420
1671
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1421
1672
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1422
1673
|
}
|
|
1423
1674
|
if (!userId || typeof userId !== "string") {
|
|
1424
|
-
return JSON.stringify({
|
|
1675
|
+
return JSON.stringify({
|
|
1676
|
+
error: "user_id is required and must be a string",
|
|
1677
|
+
});
|
|
1425
1678
|
}
|
|
1426
1679
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
1427
1680
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -1434,13 +1687,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1434
1687
|
const email = args.email;
|
|
1435
1688
|
const role = args.role;
|
|
1436
1689
|
if (!teamId || typeof teamId !== "string") {
|
|
1437
|
-
return JSON.stringify({
|
|
1690
|
+
return JSON.stringify({
|
|
1691
|
+
error: "team_id is required and must be a string",
|
|
1692
|
+
});
|
|
1438
1693
|
}
|
|
1439
1694
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1440
1695
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1441
1696
|
}
|
|
1442
1697
|
if (!email || typeof email !== "string") {
|
|
1443
|
-
return JSON.stringify({
|
|
1698
|
+
return JSON.stringify({
|
|
1699
|
+
error: "email is required and must be a string",
|
|
1700
|
+
});
|
|
1444
1701
|
}
|
|
1445
1702
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1446
1703
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
@@ -1457,7 +1714,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1457
1714
|
async function handleTeamListInvites(args) {
|
|
1458
1715
|
const teamId = args.team_id;
|
|
1459
1716
|
if (!teamId || typeof teamId !== "string") {
|
|
1460
|
-
return JSON.stringify({
|
|
1717
|
+
return JSON.stringify({
|
|
1718
|
+
error: "team_id is required and must be a string",
|
|
1719
|
+
});
|
|
1461
1720
|
}
|
|
1462
1721
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1463
1722
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1469,13 +1728,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1469
1728
|
const teamId = args.team_id;
|
|
1470
1729
|
const inviteId = args.invite_id;
|
|
1471
1730
|
if (!teamId || typeof teamId !== "string") {
|
|
1472
|
-
return JSON.stringify({
|
|
1731
|
+
return JSON.stringify({
|
|
1732
|
+
error: "team_id is required and must be a string",
|
|
1733
|
+
});
|
|
1473
1734
|
}
|
|
1474
1735
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1475
1736
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1476
1737
|
}
|
|
1477
1738
|
if (!inviteId || typeof inviteId !== "string") {
|
|
1478
|
-
return JSON.stringify({
|
|
1739
|
+
return JSON.stringify({
|
|
1740
|
+
error: "invite_id is required and must be a string",
|
|
1741
|
+
});
|
|
1479
1742
|
}
|
|
1480
1743
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(inviteId)) {
|
|
1481
1744
|
return JSON.stringify({ error: "invite_id must be a valid UUID" });
|
|
@@ -1550,12 +1813,133 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1550
1813
|
dominusnode_team_cancel_invite: handleTeamCancelInvite,
|
|
1551
1814
|
// x402 (1)
|
|
1552
1815
|
dominusnode_x402_info: handleX402Info,
|
|
1816
|
+
// MPP (5)
|
|
1817
|
+
dominusnode_mpp_info: handleMppInfo,
|
|
1818
|
+
dominusnode_mpp_challenge: handleMppChallenge,
|
|
1819
|
+
dominusnode_pay_mpp: handlePayMpp,
|
|
1820
|
+
dominusnode_mpp_session_open: handleMppSessionOpen,
|
|
1821
|
+
dominusnode_mpp_session_close: handleMppSessionClose,
|
|
1553
1822
|
};
|
|
1554
1823
|
async function handleX402Info() {
|
|
1555
1824
|
const result = await api("GET", "/api/x402/info");
|
|
1556
1825
|
return JSON.stringify(result);
|
|
1557
1826
|
}
|
|
1558
1827
|
// -----------------------------------------------------------------------
|
|
1828
|
+
// MPP (Machine Payment Protocol) handlers
|
|
1829
|
+
// -----------------------------------------------------------------------
|
|
1830
|
+
async function handleMppInfo() {
|
|
1831
|
+
// MPP info is public (no auth required), but we use the authenticated path
|
|
1832
|
+
// for simplicity since the handler is already authenticated.
|
|
1833
|
+
const result = await api("GET", "/api/mpp/info");
|
|
1834
|
+
return JSON.stringify(result);
|
|
1835
|
+
}
|
|
1836
|
+
async function handleMppChallenge(args) {
|
|
1837
|
+
const poolType = String(args.pool_type ?? "dc");
|
|
1838
|
+
if (poolType !== "dc" && poolType !== "residential") {
|
|
1839
|
+
return JSON.stringify({
|
|
1840
|
+
error: "pool_type must be 'dc' or 'residential'",
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
// This is a public endpoint -- no auth required
|
|
1844
|
+
try {
|
|
1845
|
+
const reqHeaders = {
|
|
1846
|
+
"User-Agent": "dominusnode-openai-functions/1.0.0",
|
|
1847
|
+
"Content-Type": "application/json",
|
|
1848
|
+
};
|
|
1849
|
+
if (agentSecret) {
|
|
1850
|
+
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1851
|
+
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1852
|
+
}
|
|
1853
|
+
const response = await fetch(`${baseUrl}/api/mpp/challenge`, {
|
|
1854
|
+
method: "POST",
|
|
1855
|
+
headers: reqHeaders,
|
|
1856
|
+
body: JSON.stringify({ poolType }),
|
|
1857
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1858
|
+
redirect: "error",
|
|
1859
|
+
});
|
|
1860
|
+
const responseText = await response.text();
|
|
1861
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
1862
|
+
return JSON.stringify({ error: "Response body exceeds size limit" });
|
|
1863
|
+
}
|
|
1864
|
+
if (!response.ok) {
|
|
1865
|
+
let message;
|
|
1866
|
+
try {
|
|
1867
|
+
const parsed = JSON.parse(responseText);
|
|
1868
|
+
message = parsed.error ?? parsed.message ?? responseText;
|
|
1869
|
+
}
|
|
1870
|
+
catch {
|
|
1871
|
+
message = responseText;
|
|
1872
|
+
}
|
|
1873
|
+
if (message.length > 500)
|
|
1874
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
1875
|
+
return JSON.stringify({
|
|
1876
|
+
error: `MPP challenge failed: ${sanitizeError(message)}`,
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
const data = safeJsonParse(responseText);
|
|
1880
|
+
return JSON.stringify(data);
|
|
1881
|
+
}
|
|
1882
|
+
catch (err) {
|
|
1883
|
+
return JSON.stringify({
|
|
1884
|
+
error: `MPP challenge failed: ${sanitizeError(err instanceof Error ? err.message : String(err))}`,
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
async function handlePayMpp(args) {
|
|
1889
|
+
const amountCents = args.amount_cents;
|
|
1890
|
+
const method = String(args.method ?? "");
|
|
1891
|
+
if (!Number.isInteger(amountCents) ||
|
|
1892
|
+
amountCents < 500 ||
|
|
1893
|
+
amountCents > 100_000) {
|
|
1894
|
+
return JSON.stringify({
|
|
1895
|
+
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
if (!["tempo", "stripe_spt", "lightning"].includes(method)) {
|
|
1899
|
+
return JSON.stringify({
|
|
1900
|
+
error: "method must be one of: tempo, stripe_spt, lightning",
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
const result = await api("POST", "/api/mpp/topup", { amountCents, method });
|
|
1904
|
+
return JSON.stringify(result);
|
|
1905
|
+
}
|
|
1906
|
+
async function handleMppSessionOpen(args) {
|
|
1907
|
+
const maxDepositCents = args.max_deposit_cents;
|
|
1908
|
+
const method = String(args.method ?? "");
|
|
1909
|
+
const poolType = String(args.pool_type ?? "dc");
|
|
1910
|
+
if (!Number.isInteger(maxDepositCents) ||
|
|
1911
|
+
maxDepositCents < 500 ||
|
|
1912
|
+
maxDepositCents > 100_000) {
|
|
1913
|
+
return JSON.stringify({
|
|
1914
|
+
error: "max_deposit_cents must be an integer between 500 and 100,000",
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
if (!["tempo", "stripe_spt", "lightning"].includes(method)) {
|
|
1918
|
+
return JSON.stringify({
|
|
1919
|
+
error: "method must be one of: tempo, stripe_spt, lightning",
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
if (!["dc", "residential"].includes(poolType)) {
|
|
1923
|
+
return JSON.stringify({
|
|
1924
|
+
error: "pool_type must be one of: dc, residential",
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
const result = await api("POST", "/api/mpp/session/open", {
|
|
1928
|
+
maxDepositCents,
|
|
1929
|
+
method,
|
|
1930
|
+
poolType,
|
|
1931
|
+
});
|
|
1932
|
+
return JSON.stringify(result);
|
|
1933
|
+
}
|
|
1934
|
+
async function handleMppSessionClose(args) {
|
|
1935
|
+
const channelId = String(args.channel_id ?? "");
|
|
1936
|
+
if (!channelId) {
|
|
1937
|
+
return JSON.stringify({ error: "channel_id is required" });
|
|
1938
|
+
}
|
|
1939
|
+
const result = await api("POST", "/api/mpp/session/close", { channelId });
|
|
1940
|
+
return JSON.stringify(result);
|
|
1941
|
+
}
|
|
1942
|
+
// -----------------------------------------------------------------------
|
|
1559
1943
|
// Main handler
|
|
1560
1944
|
// -----------------------------------------------------------------------
|
|
1561
1945
|
return async function handler(name, args) {
|
package/functions.json
CHANGED
|
@@ -447,7 +447,19 @@
|
|
|
447
447
|
"currency": {
|
|
448
448
|
"type": "string",
|
|
449
449
|
"description": "Cryptocurrency to pay with: BTC, ETH, LTC, XMR, ZEC, USDC, SOL, USDT, DAI, BNB, or LINK.",
|
|
450
|
-
"enum": [
|
|
450
|
+
"enum": [
|
|
451
|
+
"BTC",
|
|
452
|
+
"ETH",
|
|
453
|
+
"LTC",
|
|
454
|
+
"XMR",
|
|
455
|
+
"ZEC",
|
|
456
|
+
"USDC",
|
|
457
|
+
"SOL",
|
|
458
|
+
"USDT",
|
|
459
|
+
"DAI",
|
|
460
|
+
"BNB",
|
|
461
|
+
"LINK"
|
|
462
|
+
]
|
|
451
463
|
}
|
|
452
464
|
},
|
|
453
465
|
"required": ["amount_usd", "currency"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dominusnode/openai-functions",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Dominus Node OpenAI-compatible function calling handler — dispatches LLM function calls to the Dominus Node REST API",
|
|
5
5
|
"main": "dist/handler.js",
|
|
6
6
|
"types": "dist/handler.d.ts",
|
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
|
+
"prepare": "npm run build",
|
|
11
12
|
"test": "vitest run",
|
|
12
13
|
"test:py": "python -m pytest test_handler.py -v"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
16
|
+
"@types/node": "^22.0.0",
|
|
15
17
|
"typescript": "^5.4.0",
|
|
16
18
|
"vitest": "^1.6.0"
|
|
17
19
|
},
|