@dominusnode/gemini-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 +43 -41
- package/dist/handler.d.ts +1 -1
- package/dist/handler.js +506 -105
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -6,40 +6,40 @@ Gemini-format function declarations and handler implementations for the Dominus
|
|
|
6
6
|
|
|
7
7
|
This directory contains:
|
|
8
8
|
|
|
9
|
-
| File
|
|
10
|
-
|
|
11
|
-
| `functions.json` | Array of 22 Gemini `FunctionDeclaration` objects
|
|
12
|
-
| `handler.ts`
|
|
13
|
-
| `handler.py`
|
|
9
|
+
| File | Description |
|
|
10
|
+
| ---------------- | ------------------------------------------------------------------------- |
|
|
11
|
+
| `functions.json` | Array of 22 Gemini `FunctionDeclaration` objects |
|
|
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 declarations follow the [Gemini function calling specification](https://ai.google.dev/docs/function_calling), using uppercase types (`STRING`, `INTEGER`, `OBJECT`, `BOOLEAN`, `ARRAY`) and embedding constraints in description text rather than using JSON Schema keywords like `minimum`, `maximum`, `enum`, or `default`.
|
|
16
16
|
|
|
17
17
|
## Available Functions (22)
|
|
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`
|
|
29
|
-
| `dominusnode_list_agentic_wallets`
|
|
30
|
-
| `dominusnode_agentic_transactions`
|
|
31
|
-
| `dominusnode_freeze_agentic_wallet`
|
|
32
|
-
| `dominusnode_unfreeze_agentic_wallet` | Unfreeze an agentic wallet
|
|
33
|
-
| `dominusnode_delete_agentic_wallet`
|
|
34
|
-
| `dominusnode_create_team`
|
|
35
|
-
| `dominusnode_list_teams`
|
|
36
|
-
| `dominusnode_team_details`
|
|
37
|
-
| `dominusnode_team_fund`
|
|
38
|
-
| `dominusnode_team_create_key`
|
|
39
|
-
| `dominusnode_team_usage`
|
|
40
|
-
| `dominusnode_update_team`
|
|
41
|
-
| `dominusnode_update_team_member_role` | Update a team member's role
|
|
42
|
-
| `dominusnode_topup_paypal`
|
|
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
|
+
| `dominusnode_list_agentic_wallets` | List all agentic wallets | Yes |
|
|
30
|
+
| `dominusnode_agentic_transactions` | Get agentic wallet transaction history | Yes |
|
|
31
|
+
| `dominusnode_freeze_agentic_wallet` | Freeze an agentic wallet | Yes |
|
|
32
|
+
| `dominusnode_unfreeze_agentic_wallet` | Unfreeze an agentic wallet | Yes |
|
|
33
|
+
| `dominusnode_delete_agentic_wallet` | Delete an agentic wallet (refunds balance) | Yes |
|
|
34
|
+
| `dominusnode_create_team` | Create a team for shared proxy billing | Yes |
|
|
35
|
+
| `dominusnode_list_teams` | List teams you belong to | Yes |
|
|
36
|
+
| `dominusnode_team_details` | Get team details | Yes |
|
|
37
|
+
| `dominusnode_team_fund` | Fund a team wallet | Yes |
|
|
38
|
+
| `dominusnode_team_create_key` | Create a shared team API key | Yes |
|
|
39
|
+
| `dominusnode_team_usage` | Get team wallet transaction history | Yes |
|
|
40
|
+
| `dominusnode_update_team` | Update team settings | Yes |
|
|
41
|
+
| `dominusnode_update_team_member_role` | Update a team member's role | Yes |
|
|
42
|
+
| `dominusnode_topup_paypal` | Create a PayPal wallet top-up session | Yes |
|
|
43
43
|
|
|
44
44
|
## Usage with Google Gemini (Python)
|
|
45
45
|
|
|
@@ -154,7 +154,7 @@ console.log(JSON.parse(fetchResult));
|
|
|
154
154
|
|
|
155
155
|
// Example: PayPal top-up
|
|
156
156
|
const topup = await handler("dominusnode_topup_paypal", {
|
|
157
|
-
amount_cents: 5000,
|
|
157
|
+
amount_cents: 5000, // $50.00
|
|
158
158
|
});
|
|
159
159
|
console.log(JSON.parse(topup));
|
|
160
160
|
```
|
|
@@ -163,14 +163,14 @@ console.log(JSON.parse(topup));
|
|
|
163
163
|
|
|
164
164
|
Gemini function declarations differ from OpenAI's JSON Schema format:
|
|
165
165
|
|
|
166
|
-
| Feature
|
|
167
|
-
|
|
168
|
-
| Type names
|
|
169
|
-
| `default`
|
|
170
|
-
| `minimum`/`maximum`
|
|
171
|
-
| `enum`
|
|
172
|
-
| `minLength`/`maxLength` | Supported
|
|
173
|
-
| `additionalProperties`
|
|
166
|
+
| Feature | OpenAI/JSON Schema | Gemini |
|
|
167
|
+
| ----------------------- | ----------------------- | -------------------------------------- |
|
|
168
|
+
| Type names | `"string"`, `"integer"` | `"STRING"`, `"INTEGER"` |
|
|
169
|
+
| `default` | Supported | Not supported -- moved to description |
|
|
170
|
+
| `minimum`/`maximum` | Supported | Not supported -- moved to description |
|
|
171
|
+
| `enum` | Supported | Not supported -- listed in description |
|
|
172
|
+
| `minLength`/`maxLength` | Supported | Not supported -- moved to description |
|
|
173
|
+
| `additionalProperties` | Supported | Not supported -- omitted |
|
|
174
174
|
|
|
175
175
|
All constraints are expressed in the `description` field text for Gemini compatibility.
|
|
176
176
|
|
|
@@ -207,18 +207,20 @@ API keys (`dn_live_*`, `dn_test_*`) are scrubbed from all error messages returne
|
|
|
207
207
|
|
|
208
208
|
## Proxy Pricing
|
|
209
209
|
|
|
210
|
-
| Proxy Type
|
|
211
|
-
|
|
210
|
+
| Proxy Type | Price | Best For |
|
|
211
|
+
| ----------------- | -------- | -------------------------------------- |
|
|
212
212
|
| Datacenter (`dc`) | $3.00/GB | General scraping, speed-critical tasks |
|
|
213
|
-
| Residential
|
|
213
|
+
| Residential | $5.00/GB | Anti-detection, geo-restricted content |
|
|
214
214
|
|
|
215
215
|
## Dependencies
|
|
216
216
|
|
|
217
217
|
### TypeScript Handler
|
|
218
|
+
|
|
218
219
|
- Node.js 18+ (uses native `fetch` and `AbortSignal.timeout`)
|
|
219
220
|
- No external dependencies
|
|
220
221
|
|
|
221
222
|
### Python Handler
|
|
223
|
+
|
|
222
224
|
- Python 3.8+
|
|
223
225
|
- `httpx` (`pip install httpx`)
|
|
224
226
|
|
package/dist/handler.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node Gemini / Vertex AI function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 57 tools for AI agents to interact with the Dominus Node REST API.
|
|
5
5
|
*
|
|
6
6
|
* Provides a factory function that creates a handler for dispatching
|
|
7
7
|
* Google Gemini function calls to the Dominus Node REST API. Works with
|
package/dist/handler.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node Gemini / Vertex AI function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 57 tools for AI agents to interact with the Dominus Node REST API.
|
|
5
5
|
*
|
|
6
6
|
* Provides a factory function that creates a handler for dispatching
|
|
7
7
|
* Google Gemini function calls to the Dominus Node REST API. Works with
|
|
@@ -24,10 +24,63 @@
|
|
|
24
24
|
*
|
|
25
25
|
* @module
|
|
26
26
|
*/
|
|
27
|
+
import * as crypto from "node:crypto";
|
|
27
28
|
import dns from "dns/promises";
|
|
28
29
|
import * as http from "node:http";
|
|
29
30
|
import * as tls from "node:tls";
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
32
|
+
// SHA-256 Proof-of-Work solver
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
function countLeadingZeroBits(buf) {
|
|
35
|
+
let count = 0;
|
|
36
|
+
for (const byte of buf) {
|
|
37
|
+
if (byte === 0) {
|
|
38
|
+
count += 8;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
let mask = 0x80;
|
|
42
|
+
while (mask && !(byte & mask)) {
|
|
43
|
+
count++;
|
|
44
|
+
mask >>= 1;
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
return count;
|
|
49
|
+
}
|
|
50
|
+
async function solvePoW(baseUrl) {
|
|
51
|
+
try {
|
|
52
|
+
const resp = await fetch(`${baseUrl}/api/auth/pow/challenge`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { "Content-Type": "application/json" },
|
|
55
|
+
redirect: "error",
|
|
56
|
+
});
|
|
57
|
+
if (!resp.ok)
|
|
58
|
+
return null;
|
|
59
|
+
const text = await resp.text();
|
|
60
|
+
if (text.length > 10_485_760)
|
|
61
|
+
return null;
|
|
62
|
+
const challenge = JSON.parse(text);
|
|
63
|
+
const prefix = challenge.prefix ?? "";
|
|
64
|
+
const difficulty = challenge.difficulty ?? 20;
|
|
65
|
+
const challengeId = challenge.challengeId ?? "";
|
|
66
|
+
if (!prefix || !challengeId)
|
|
67
|
+
return null;
|
|
68
|
+
for (let nonce = 0; nonce < 100_000_000; nonce++) {
|
|
69
|
+
const hash = crypto
|
|
70
|
+
.createHash("sha256")
|
|
71
|
+
.update(prefix + nonce.toString())
|
|
72
|
+
.digest();
|
|
73
|
+
if (countLeadingZeroBits(hash) >= difficulty) {
|
|
74
|
+
return { challengeId, nonce: nonce.toString() };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
31
84
|
// SSRF Prevention -- URL validation
|
|
32
85
|
// ---------------------------------------------------------------------------
|
|
33
86
|
const BLOCKED_HOSTNAMES = new Set([
|
|
@@ -296,7 +349,7 @@ async function checkDnsRebinding(hostname) {
|
|
|
296
349
|
// ---------------------------------------------------------------------------
|
|
297
350
|
// Credential sanitization
|
|
298
351
|
// ---------------------------------------------------------------------------
|
|
299
|
-
const CREDENTIAL_RE = /dn_(live|test)_[a-zA-Z0-9]+/g;
|
|
352
|
+
const CREDENTIAL_RE = /dn_(live|test|proxy)_[a-zA-Z0-9]+/g;
|
|
300
353
|
function sanitizeError(message) {
|
|
301
354
|
return message.replace(CREDENTIAL_RE, "***");
|
|
302
355
|
}
|
|
@@ -509,8 +562,13 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
509
562
|
try {
|
|
510
563
|
// Strip security-sensitive headers from user-provided headers
|
|
511
564
|
const BLOCKED_HEADERS = new Set([
|
|
512
|
-
"host",
|
|
513
|
-
"
|
|
565
|
+
"host",
|
|
566
|
+
"connection",
|
|
567
|
+
"content-length",
|
|
568
|
+
"transfer-encoding",
|
|
569
|
+
"proxy-authorization",
|
|
570
|
+
"authorization",
|
|
571
|
+
"user-agent",
|
|
514
572
|
]);
|
|
515
573
|
const safeHeaders = {};
|
|
516
574
|
if (headers) {
|
|
@@ -546,7 +604,10 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
546
604
|
port: proxyPort,
|
|
547
605
|
method: "CONNECT",
|
|
548
606
|
path: `${parsed.hostname.includes(":") ? `[${parsed.hostname}]` : parsed.hostname}:${parsed.port || 443}`,
|
|
549
|
-
headers: {
|
|
607
|
+
headers: {
|
|
608
|
+
"Proxy-Authorization": proxyAuth,
|
|
609
|
+
Host: `${parsed.hostname.includes(":") ? `[${parsed.hostname}]` : parsed.hostname}:${parsed.port || 443}`,
|
|
610
|
+
},
|
|
550
611
|
});
|
|
551
612
|
connectReq.on("connect", (_res, tunnelSocket) => {
|
|
552
613
|
if (_res.statusCode !== 200) {
|
|
@@ -590,7 +651,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
590
651
|
return;
|
|
591
652
|
}
|
|
592
653
|
const headerSection = raw.substring(0, headerEnd);
|
|
593
|
-
const body = raw
|
|
654
|
+
const body = raw
|
|
655
|
+
.substring(headerEnd + 4)
|
|
656
|
+
.substring(0, MAX_BODY_BYTES);
|
|
594
657
|
const statusLine = headerSection.split("\r\n")[0];
|
|
595
658
|
const statusMatch = statusLine.match(/^HTTP\/\d\.\d\s+(\d+)/);
|
|
596
659
|
const status = statusMatch ? parseInt(statusMatch[1], 10) : 0;
|
|
@@ -598,18 +661,29 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
598
661
|
for (const line of headerSection.split("\r\n").slice(1)) {
|
|
599
662
|
const ci = line.indexOf(":");
|
|
600
663
|
if (ci > 0)
|
|
601
|
-
headers[line.substring(0, ci).trim().toLowerCase()] = line
|
|
664
|
+
headers[line.substring(0, ci).trim().toLowerCase()] = line
|
|
665
|
+
.substring(ci + 1)
|
|
666
|
+
.trim();
|
|
602
667
|
}
|
|
603
668
|
stripDangerousKeys(headers);
|
|
604
669
|
resolve({ status, headers, body });
|
|
605
670
|
};
|
|
606
671
|
tlsSocket.on("end", finalize);
|
|
607
672
|
tlsSocket.on("close", finalize);
|
|
608
|
-
tlsSocket.on("error", (err) => {
|
|
673
|
+
tlsSocket.on("error", (err) => {
|
|
674
|
+
clearTimeout(timeout);
|
|
675
|
+
reject(err);
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
tlsSocket.on("error", (err) => {
|
|
679
|
+
clearTimeout(timeout);
|
|
680
|
+
reject(err);
|
|
609
681
|
});
|
|
610
|
-
tlsSocket.on("error", (err) => { clearTimeout(timeout); reject(err); });
|
|
611
682
|
});
|
|
612
|
-
connectReq.on("error", (err) => {
|
|
683
|
+
connectReq.on("error", (err) => {
|
|
684
|
+
clearTimeout(timeout);
|
|
685
|
+
reject(err);
|
|
686
|
+
});
|
|
613
687
|
connectReq.end();
|
|
614
688
|
}
|
|
615
689
|
else {
|
|
@@ -619,19 +693,28 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
619
693
|
port: proxyPort,
|
|
620
694
|
method,
|
|
621
695
|
path: url,
|
|
622
|
-
headers: {
|
|
696
|
+
headers: {
|
|
697
|
+
...safeHeaders,
|
|
698
|
+
"Proxy-Authorization": proxyAuth,
|
|
699
|
+
Host: parsed.host,
|
|
700
|
+
},
|
|
623
701
|
}, (res) => {
|
|
624
702
|
const chunks = [];
|
|
625
703
|
let byteCount = 0;
|
|
626
704
|
let httpFinalized = false;
|
|
627
|
-
res.on("data", (chunk) => {
|
|
628
|
-
|
|
705
|
+
res.on("data", (chunk) => {
|
|
706
|
+
byteCount += chunk.length;
|
|
707
|
+
if (byteCount <= MAX_BODY_BYTES)
|
|
708
|
+
chunks.push(chunk);
|
|
709
|
+
});
|
|
629
710
|
const finalize = () => {
|
|
630
711
|
if (httpFinalized)
|
|
631
712
|
return;
|
|
632
713
|
httpFinalized = true;
|
|
633
714
|
clearTimeout(timeout);
|
|
634
|
-
const body = Buffer.concat(chunks)
|
|
715
|
+
const body = Buffer.concat(chunks)
|
|
716
|
+
.toString("utf-8")
|
|
717
|
+
.substring(0, MAX_BODY_BYTES);
|
|
635
718
|
const headers = {};
|
|
636
719
|
for (const [k, v] of Object.entries(res.headers)) {
|
|
637
720
|
if (v)
|
|
@@ -642,9 +725,15 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
642
725
|
};
|
|
643
726
|
res.on("end", finalize);
|
|
644
727
|
res.on("close", finalize);
|
|
645
|
-
res.on("error", (err) => {
|
|
728
|
+
res.on("error", (err) => {
|
|
729
|
+
clearTimeout(timeout);
|
|
730
|
+
reject(err);
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
req.on("error", (err) => {
|
|
734
|
+
clearTimeout(timeout);
|
|
735
|
+
reject(err);
|
|
646
736
|
});
|
|
647
|
-
req.on("error", (err) => { clearTimeout(timeout); reject(err); });
|
|
648
737
|
req.end();
|
|
649
738
|
}
|
|
650
739
|
});
|
|
@@ -684,13 +773,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
684
773
|
const label = args.label;
|
|
685
774
|
const spendingLimitCents = args.spending_limit_cents;
|
|
686
775
|
if (!label || typeof label !== "string") {
|
|
687
|
-
return JSON.stringify({
|
|
776
|
+
return JSON.stringify({
|
|
777
|
+
error: "label is required and must be a string",
|
|
778
|
+
});
|
|
688
779
|
}
|
|
689
780
|
if (label.length > 100) {
|
|
690
781
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
691
782
|
}
|
|
692
783
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
693
|
-
return JSON.stringify({
|
|
784
|
+
return JSON.stringify({
|
|
785
|
+
error: "label contains invalid control characters",
|
|
786
|
+
});
|
|
694
787
|
}
|
|
695
788
|
if (!Number.isInteger(spendingLimitCents) ||
|
|
696
789
|
spendingLimitCents <= 0 ||
|
|
@@ -704,9 +797,12 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
704
797
|
spendingLimitCents,
|
|
705
798
|
};
|
|
706
799
|
// Validate optional daily_limit_cents
|
|
707
|
-
if (args.daily_limit_cents !== undefined &&
|
|
800
|
+
if (args.daily_limit_cents !== undefined &&
|
|
801
|
+
args.daily_limit_cents !== null) {
|
|
708
802
|
const dailyLimit = Number(args.daily_limit_cents);
|
|
709
|
-
if (!Number.isInteger(dailyLimit) ||
|
|
803
|
+
if (!Number.isInteger(dailyLimit) ||
|
|
804
|
+
dailyLimit < 1 ||
|
|
805
|
+
dailyLimit > 1_000_000) {
|
|
710
806
|
return JSON.stringify({
|
|
711
807
|
error: "daily_limit_cents must be a positive integer between 1 and 1,000,000",
|
|
712
808
|
});
|
|
@@ -716,22 +812,32 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
716
812
|
// Validate optional allowed_domains
|
|
717
813
|
if (args.allowed_domains !== undefined && args.allowed_domains !== null) {
|
|
718
814
|
if (!Array.isArray(args.allowed_domains)) {
|
|
719
|
-
return JSON.stringify({
|
|
815
|
+
return JSON.stringify({
|
|
816
|
+
error: "allowed_domains must be an array of domain strings",
|
|
817
|
+
});
|
|
720
818
|
}
|
|
721
819
|
if (args.allowed_domains.length > 100) {
|
|
722
|
-
return JSON.stringify({
|
|
820
|
+
return JSON.stringify({
|
|
821
|
+
error: "allowed_domains must have at most 100 entries",
|
|
822
|
+
});
|
|
723
823
|
}
|
|
724
824
|
const domainRe = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
725
825
|
for (let i = 0; i < args.allowed_domains.length; i++) {
|
|
726
826
|
const d = args.allowed_domains[i];
|
|
727
827
|
if (typeof d !== "string") {
|
|
728
|
-
return JSON.stringify({
|
|
828
|
+
return JSON.stringify({
|
|
829
|
+
error: `allowed_domains[${i}] must be a string`,
|
|
830
|
+
});
|
|
729
831
|
}
|
|
730
832
|
if (d.length > 253) {
|
|
731
|
-
return JSON.stringify({
|
|
833
|
+
return JSON.stringify({
|
|
834
|
+
error: `allowed_domains[${i}] exceeds 253 characters`,
|
|
835
|
+
});
|
|
732
836
|
}
|
|
733
837
|
if (!domainRe.test(d)) {
|
|
734
|
-
return JSON.stringify({
|
|
838
|
+
return JSON.stringify({
|
|
839
|
+
error: `allowed_domains[${i}] is not a valid domain: ${d}`,
|
|
840
|
+
});
|
|
735
841
|
}
|
|
736
842
|
}
|
|
737
843
|
body.allowedDomains = args.allowed_domains;
|
|
@@ -743,7 +849,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
743
849
|
const walletId = args.wallet_id;
|
|
744
850
|
const amountCents = args.amount_cents;
|
|
745
851
|
if (!walletId || typeof walletId !== "string") {
|
|
746
|
-
return JSON.stringify({
|
|
852
|
+
return JSON.stringify({
|
|
853
|
+
error: "wallet_id is required and must be a string",
|
|
854
|
+
});
|
|
747
855
|
}
|
|
748
856
|
if (!Number.isInteger(amountCents) ||
|
|
749
857
|
amountCents <= 0 ||
|
|
@@ -758,7 +866,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
758
866
|
async function handleAgenticWalletBalance(args) {
|
|
759
867
|
const walletId = args.wallet_id;
|
|
760
868
|
if (!walletId || typeof walletId !== "string") {
|
|
761
|
-
return JSON.stringify({
|
|
869
|
+
return JSON.stringify({
|
|
870
|
+
error: "wallet_id is required and must be a string",
|
|
871
|
+
});
|
|
762
872
|
}
|
|
763
873
|
const result = await api("GET", `/api/agent-wallet/${encodeURIComponent(walletId)}`);
|
|
764
874
|
return JSON.stringify(result);
|
|
@@ -770,13 +880,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
770
880
|
async function handleAgenticTransactions(args) {
|
|
771
881
|
const walletId = args.wallet_id;
|
|
772
882
|
if (!walletId || typeof walletId !== "string") {
|
|
773
|
-
return JSON.stringify({
|
|
883
|
+
return JSON.stringify({
|
|
884
|
+
error: "wallet_id is required and must be a string",
|
|
885
|
+
});
|
|
774
886
|
}
|
|
775
887
|
const limit = args.limit;
|
|
776
888
|
const params = new URLSearchParams();
|
|
777
889
|
if (limit !== undefined) {
|
|
778
890
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
779
|
-
return JSON.stringify({
|
|
891
|
+
return JSON.stringify({
|
|
892
|
+
error: "limit must be an integer between 1 and 100",
|
|
893
|
+
});
|
|
780
894
|
}
|
|
781
895
|
params.set("limit", String(limit));
|
|
782
896
|
}
|
|
@@ -787,7 +901,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
787
901
|
async function handleFreezeAgenticWallet(args) {
|
|
788
902
|
const walletId = args.wallet_id;
|
|
789
903
|
if (!walletId || typeof walletId !== "string") {
|
|
790
|
-
return JSON.stringify({
|
|
904
|
+
return JSON.stringify({
|
|
905
|
+
error: "wallet_id is required and must be a string",
|
|
906
|
+
});
|
|
791
907
|
}
|
|
792
908
|
const result = await api("POST", `/api/agent-wallet/${encodeURIComponent(walletId)}/freeze`);
|
|
793
909
|
return JSON.stringify(result);
|
|
@@ -795,7 +911,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
795
911
|
async function handleUnfreezeAgenticWallet(args) {
|
|
796
912
|
const walletId = args.wallet_id;
|
|
797
913
|
if (!walletId || typeof walletId !== "string") {
|
|
798
|
-
return JSON.stringify({
|
|
914
|
+
return JSON.stringify({
|
|
915
|
+
error: "wallet_id is required and must be a string",
|
|
916
|
+
});
|
|
799
917
|
}
|
|
800
918
|
const result = await api("POST", `/api/agent-wallet/${encodeURIComponent(walletId)}/unfreeze`);
|
|
801
919
|
return JSON.stringify(result);
|
|
@@ -803,7 +921,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
803
921
|
async function handleDeleteAgenticWallet(args) {
|
|
804
922
|
const walletId = args.wallet_id;
|
|
805
923
|
if (!walletId || typeof walletId !== "string") {
|
|
806
|
-
return JSON.stringify({
|
|
924
|
+
return JSON.stringify({
|
|
925
|
+
error: "wallet_id is required and must be a string",
|
|
926
|
+
});
|
|
807
927
|
}
|
|
808
928
|
const result = await api("DELETE", `/api/agent-wallet/${encodeURIComponent(walletId)}`);
|
|
809
929
|
return JSON.stringify(result);
|
|
@@ -817,13 +937,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
817
937
|
return JSON.stringify({ error: "name must be 100 characters or fewer" });
|
|
818
938
|
}
|
|
819
939
|
if (/[\x00-\x1f\x7f]/.test(name)) {
|
|
820
|
-
return JSON.stringify({
|
|
940
|
+
return JSON.stringify({
|
|
941
|
+
error: "name contains invalid control characters",
|
|
942
|
+
});
|
|
821
943
|
}
|
|
822
944
|
const body = { name };
|
|
823
945
|
if (args.max_members !== undefined) {
|
|
824
946
|
const maxMembers = Number(args.max_members);
|
|
825
947
|
if (!Number.isInteger(maxMembers) || maxMembers < 1 || maxMembers > 100) {
|
|
826
|
-
return JSON.stringify({
|
|
948
|
+
return JSON.stringify({
|
|
949
|
+
error: "max_members must be an integer between 1 and 100",
|
|
950
|
+
});
|
|
827
951
|
}
|
|
828
952
|
body.maxMembers = maxMembers;
|
|
829
953
|
}
|
|
@@ -837,7 +961,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
837
961
|
async function handleTeamDetails(args) {
|
|
838
962
|
const teamId = args.team_id;
|
|
839
963
|
if (!teamId || typeof teamId !== "string") {
|
|
840
|
-
return JSON.stringify({
|
|
964
|
+
return JSON.stringify({
|
|
965
|
+
error: "team_id is required and must be a string",
|
|
966
|
+
});
|
|
841
967
|
}
|
|
842
968
|
const result = await api("GET", `/api/teams/${encodeURIComponent(teamId)}`);
|
|
843
969
|
return JSON.stringify(result);
|
|
@@ -846,7 +972,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
846
972
|
const teamId = args.team_id;
|
|
847
973
|
const amountCents = args.amount_cents;
|
|
848
974
|
if (!teamId || typeof teamId !== "string") {
|
|
849
|
-
return JSON.stringify({
|
|
975
|
+
return JSON.stringify({
|
|
976
|
+
error: "team_id is required and must be a string",
|
|
977
|
+
});
|
|
850
978
|
}
|
|
851
979
|
if (!Number.isInteger(amountCents) ||
|
|
852
980
|
amountCents < 100 ||
|
|
@@ -862,16 +990,22 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
862
990
|
const teamId = args.team_id;
|
|
863
991
|
const label = args.label;
|
|
864
992
|
if (!teamId || typeof teamId !== "string") {
|
|
865
|
-
return JSON.stringify({
|
|
993
|
+
return JSON.stringify({
|
|
994
|
+
error: "team_id is required and must be a string",
|
|
995
|
+
});
|
|
866
996
|
}
|
|
867
997
|
if (!label || typeof label !== "string") {
|
|
868
|
-
return JSON.stringify({
|
|
998
|
+
return JSON.stringify({
|
|
999
|
+
error: "label is required and must be a string",
|
|
1000
|
+
});
|
|
869
1001
|
}
|
|
870
1002
|
if (label.length > 100) {
|
|
871
1003
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
872
1004
|
}
|
|
873
1005
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
874
|
-
return JSON.stringify({
|
|
1006
|
+
return JSON.stringify({
|
|
1007
|
+
error: "label contains invalid control characters",
|
|
1008
|
+
});
|
|
875
1009
|
}
|
|
876
1010
|
const result = await api("POST", `/api/teams/${encodeURIComponent(teamId)}/keys`, { label });
|
|
877
1011
|
return JSON.stringify(result);
|
|
@@ -879,13 +1013,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
879
1013
|
async function handleTeamUsage(args) {
|
|
880
1014
|
const teamId = args.team_id;
|
|
881
1015
|
if (!teamId || typeof teamId !== "string") {
|
|
882
|
-
return JSON.stringify({
|
|
1016
|
+
return JSON.stringify({
|
|
1017
|
+
error: "team_id is required and must be a string",
|
|
1018
|
+
});
|
|
883
1019
|
}
|
|
884
1020
|
const limit = args.limit;
|
|
885
1021
|
const params = new URLSearchParams();
|
|
886
1022
|
if (limit !== undefined) {
|
|
887
1023
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
888
|
-
return JSON.stringify({
|
|
1024
|
+
return JSON.stringify({
|
|
1025
|
+
error: "limit must be an integer between 1 and 100",
|
|
1026
|
+
});
|
|
889
1027
|
}
|
|
890
1028
|
params.set("limit", String(limit));
|
|
891
1029
|
}
|
|
@@ -896,7 +1034,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
896
1034
|
async function handleUpdateTeam(args) {
|
|
897
1035
|
const teamId = args.team_id;
|
|
898
1036
|
if (!teamId || typeof teamId !== "string") {
|
|
899
|
-
return JSON.stringify({
|
|
1037
|
+
return JSON.stringify({
|
|
1038
|
+
error: "team_id is required and must be a string",
|
|
1039
|
+
});
|
|
900
1040
|
}
|
|
901
1041
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
902
1042
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -908,22 +1048,30 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
908
1048
|
return JSON.stringify({ error: "name must be a non-empty string" });
|
|
909
1049
|
}
|
|
910
1050
|
if (name.length > 100) {
|
|
911
|
-
return JSON.stringify({
|
|
1051
|
+
return JSON.stringify({
|
|
1052
|
+
error: "name must be 100 characters or fewer",
|
|
1053
|
+
});
|
|
912
1054
|
}
|
|
913
1055
|
if (/[\x00-\x1f\x7f]/.test(name)) {
|
|
914
|
-
return JSON.stringify({
|
|
1056
|
+
return JSON.stringify({
|
|
1057
|
+
error: "name contains invalid control characters",
|
|
1058
|
+
});
|
|
915
1059
|
}
|
|
916
1060
|
body.name = name;
|
|
917
1061
|
}
|
|
918
1062
|
if (args.max_members !== undefined) {
|
|
919
1063
|
const maxMembers = Number(args.max_members);
|
|
920
1064
|
if (!Number.isInteger(maxMembers) || maxMembers < 1 || maxMembers > 100) {
|
|
921
|
-
return JSON.stringify({
|
|
1065
|
+
return JSON.stringify({
|
|
1066
|
+
error: "max_members must be an integer between 1 and 100",
|
|
1067
|
+
});
|
|
922
1068
|
}
|
|
923
1069
|
body.maxMembers = maxMembers;
|
|
924
1070
|
}
|
|
925
1071
|
if (Object.keys(body).length === 0) {
|
|
926
|
-
return JSON.stringify({
|
|
1072
|
+
return JSON.stringify({
|
|
1073
|
+
error: "At least one of name or max_members must be provided",
|
|
1074
|
+
});
|
|
927
1075
|
}
|
|
928
1076
|
const result = await api("PATCH", `/api/teams/${encodeURIComponent(teamId)}`, body);
|
|
929
1077
|
return JSON.stringify(result);
|
|
@@ -933,13 +1081,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
933
1081
|
const userId = args.user_id;
|
|
934
1082
|
const role = args.role;
|
|
935
1083
|
if (!teamId || typeof teamId !== "string") {
|
|
936
|
-
return JSON.stringify({
|
|
1084
|
+
return JSON.stringify({
|
|
1085
|
+
error: "team_id is required and must be a string",
|
|
1086
|
+
});
|
|
937
1087
|
}
|
|
938
1088
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
939
1089
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
940
1090
|
}
|
|
941
1091
|
if (!userId || typeof userId !== "string") {
|
|
942
|
-
return JSON.stringify({
|
|
1092
|
+
return JSON.stringify({
|
|
1093
|
+
error: "user_id is required and must be a string",
|
|
1094
|
+
});
|
|
943
1095
|
}
|
|
944
1096
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
945
1097
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -962,7 +1114,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
962
1114
|
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
963
1115
|
});
|
|
964
1116
|
}
|
|
965
|
-
const result = await api("POST", "/api/wallet/topup/paypal", {
|
|
1117
|
+
const result = await api("POST", "/api/wallet/topup/paypal", {
|
|
1118
|
+
amountCents,
|
|
1119
|
+
});
|
|
966
1120
|
return JSON.stringify(result);
|
|
967
1121
|
}
|
|
968
1122
|
async function handleTopupStripe(args) {
|
|
@@ -974,11 +1128,23 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
974
1128
|
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
975
1129
|
});
|
|
976
1130
|
}
|
|
977
|
-
const result = await api("POST", "/api/wallet/topup/stripe", {
|
|
1131
|
+
const result = await api("POST", "/api/wallet/topup/stripe", {
|
|
1132
|
+
amountCents,
|
|
1133
|
+
});
|
|
978
1134
|
return JSON.stringify(result);
|
|
979
1135
|
}
|
|
980
1136
|
const VALID_CRYPTO_CURRENCIES = new Set([
|
|
981
|
-
"btc",
|
|
1137
|
+
"btc",
|
|
1138
|
+
"eth",
|
|
1139
|
+
"ltc",
|
|
1140
|
+
"xmr",
|
|
1141
|
+
"zec",
|
|
1142
|
+
"usdc",
|
|
1143
|
+
"sol",
|
|
1144
|
+
"usdt",
|
|
1145
|
+
"dai",
|
|
1146
|
+
"bnb",
|
|
1147
|
+
"link",
|
|
982
1148
|
]);
|
|
983
1149
|
async function handleTopupCrypto(args) {
|
|
984
1150
|
const amountUsd = args.amount_usd;
|
|
@@ -1017,7 +1183,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1017
1183
|
if (args.limit !== undefined) {
|
|
1018
1184
|
const limit = Number(args.limit);
|
|
1019
1185
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
1020
|
-
return JSON.stringify({
|
|
1186
|
+
return JSON.stringify({
|
|
1187
|
+
error: "limit must be an integer between 1 and 100",
|
|
1188
|
+
});
|
|
1021
1189
|
}
|
|
1022
1190
|
params.set("limit", String(limit));
|
|
1023
1191
|
}
|
|
@@ -1032,10 +1200,14 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1032
1200
|
async function handleCheckPayment(args) {
|
|
1033
1201
|
const invoiceId = args.invoice_id;
|
|
1034
1202
|
if (!invoiceId || typeof invoiceId !== "string") {
|
|
1035
|
-
return JSON.stringify({
|
|
1203
|
+
return JSON.stringify({
|
|
1204
|
+
error: "invoice_id is required and must be a string",
|
|
1205
|
+
});
|
|
1036
1206
|
}
|
|
1037
1207
|
if (/[\x00-\x1f\x7f]/.test(invoiceId)) {
|
|
1038
|
-
return JSON.stringify({
|
|
1208
|
+
return JSON.stringify({
|
|
1209
|
+
error: "invoice_id contains invalid control characters",
|
|
1210
|
+
});
|
|
1039
1211
|
}
|
|
1040
1212
|
const result = await api("GET", `/api/wallet/topup/crypto/${encodeURIComponent(invoiceId)}/status`);
|
|
1041
1213
|
return JSON.stringify(result);
|
|
@@ -1048,7 +1220,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1048
1220
|
if (args.days !== undefined) {
|
|
1049
1221
|
const days = Number(args.days);
|
|
1050
1222
|
if (!Number.isInteger(days) || days < 1 || days > 90) {
|
|
1051
|
-
return JSON.stringify({
|
|
1223
|
+
return JSON.stringify({
|
|
1224
|
+
error: "days must be an integer between 1 and 90",
|
|
1225
|
+
});
|
|
1052
1226
|
}
|
|
1053
1227
|
params.set("days", String(days));
|
|
1054
1228
|
}
|
|
@@ -1061,7 +1235,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1061
1235
|
if (args.limit !== undefined) {
|
|
1062
1236
|
const limit = Number(args.limit);
|
|
1063
1237
|
if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
|
|
1064
|
-
return JSON.stringify({
|
|
1238
|
+
return JSON.stringify({
|
|
1239
|
+
error: "limit must be an integer between 1 and 50",
|
|
1240
|
+
});
|
|
1065
1241
|
}
|
|
1066
1242
|
params.set("limit", String(limit));
|
|
1067
1243
|
}
|
|
@@ -1076,19 +1252,27 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1076
1252
|
const email = args.email;
|
|
1077
1253
|
const password = args.password;
|
|
1078
1254
|
if (!email || typeof email !== "string") {
|
|
1079
|
-
return JSON.stringify({
|
|
1255
|
+
return JSON.stringify({
|
|
1256
|
+
error: "email is required and must be a string",
|
|
1257
|
+
});
|
|
1080
1258
|
}
|
|
1081
1259
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1082
1260
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1083
1261
|
}
|
|
1084
1262
|
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1085
|
-
return JSON.stringify({
|
|
1263
|
+
return JSON.stringify({
|
|
1264
|
+
error: "email contains invalid control characters",
|
|
1265
|
+
});
|
|
1086
1266
|
}
|
|
1087
1267
|
if (!password || typeof password !== "string") {
|
|
1088
|
-
return JSON.stringify({
|
|
1268
|
+
return JSON.stringify({
|
|
1269
|
+
error: "password is required and must be a string",
|
|
1270
|
+
});
|
|
1089
1271
|
}
|
|
1090
1272
|
if (password.length < 8 || password.length > 128) {
|
|
1091
|
-
return JSON.stringify({
|
|
1273
|
+
return JSON.stringify({
|
|
1274
|
+
error: "password must be between 8 and 128 characters",
|
|
1275
|
+
});
|
|
1092
1276
|
}
|
|
1093
1277
|
try {
|
|
1094
1278
|
const reqHeaders = {
|
|
@@ -1099,10 +1283,15 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1099
1283
|
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1100
1284
|
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1101
1285
|
}
|
|
1286
|
+
// Solve PoW for CAPTCHA-free registration
|
|
1287
|
+
const pow = await solvePoW(baseUrl);
|
|
1288
|
+
const regBody = { email, password };
|
|
1289
|
+
if (pow)
|
|
1290
|
+
regBody.pow = pow;
|
|
1102
1291
|
const response = await fetch(`${baseUrl}/api/auth/register`, {
|
|
1103
1292
|
method: "POST",
|
|
1104
1293
|
headers: reqHeaders,
|
|
1105
|
-
body: JSON.stringify(
|
|
1294
|
+
body: JSON.stringify(regBody),
|
|
1106
1295
|
signal: AbortSignal.timeout(timeoutMs),
|
|
1107
1296
|
redirect: "error",
|
|
1108
1297
|
});
|
|
@@ -1124,29 +1313,43 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1124
1313
|
return JSON.stringify({ error: sanitizeError(message) });
|
|
1125
1314
|
}
|
|
1126
1315
|
const data = safeJsonParse(responseText);
|
|
1127
|
-
return JSON.stringify({
|
|
1316
|
+
return JSON.stringify({
|
|
1317
|
+
userId: data.userId,
|
|
1318
|
+
email: data.email,
|
|
1319
|
+
message: data.message ?? "Registration successful",
|
|
1320
|
+
});
|
|
1128
1321
|
}
|
|
1129
1322
|
catch (err) {
|
|
1130
|
-
return JSON.stringify({
|
|
1323
|
+
return JSON.stringify({
|
|
1324
|
+
error: sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
1325
|
+
});
|
|
1131
1326
|
}
|
|
1132
1327
|
}
|
|
1133
1328
|
async function handleLogin(args) {
|
|
1134
1329
|
const email = args.email;
|
|
1135
1330
|
const password = args.password;
|
|
1136
1331
|
if (!email || typeof email !== "string") {
|
|
1137
|
-
return JSON.stringify({
|
|
1332
|
+
return JSON.stringify({
|
|
1333
|
+
error: "email is required and must be a string",
|
|
1334
|
+
});
|
|
1138
1335
|
}
|
|
1139
1336
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1140
1337
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1141
1338
|
}
|
|
1142
1339
|
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1143
|
-
return JSON.stringify({
|
|
1340
|
+
return JSON.stringify({
|
|
1341
|
+
error: "email contains invalid control characters",
|
|
1342
|
+
});
|
|
1144
1343
|
}
|
|
1145
1344
|
if (!password || typeof password !== "string") {
|
|
1146
|
-
return JSON.stringify({
|
|
1345
|
+
return JSON.stringify({
|
|
1346
|
+
error: "password is required and must be a string",
|
|
1347
|
+
});
|
|
1147
1348
|
}
|
|
1148
1349
|
if (password.length < 8 || password.length > 128) {
|
|
1149
|
-
return JSON.stringify({
|
|
1350
|
+
return JSON.stringify({
|
|
1351
|
+
error: "password must be between 8 and 128 characters",
|
|
1352
|
+
});
|
|
1150
1353
|
}
|
|
1151
1354
|
try {
|
|
1152
1355
|
const reqHeaders = {
|
|
@@ -1182,10 +1385,15 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1182
1385
|
return JSON.stringify({ error: sanitizeError(message) });
|
|
1183
1386
|
}
|
|
1184
1387
|
const data = safeJsonParse(responseText);
|
|
1185
|
-
return JSON.stringify({
|
|
1388
|
+
return JSON.stringify({
|
|
1389
|
+
token: data.token,
|
|
1390
|
+
message: data.message ?? "Login successful",
|
|
1391
|
+
});
|
|
1186
1392
|
}
|
|
1187
1393
|
catch (err) {
|
|
1188
|
-
return JSON.stringify({
|
|
1394
|
+
return JSON.stringify({
|
|
1395
|
+
error: sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
1396
|
+
});
|
|
1189
1397
|
}
|
|
1190
1398
|
}
|
|
1191
1399
|
async function handleGetAccountInfo() {
|
|
@@ -1195,10 +1403,14 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1195
1403
|
async function handleVerifyEmail(args) {
|
|
1196
1404
|
const token = args.token;
|
|
1197
1405
|
if (!token || typeof token !== "string") {
|
|
1198
|
-
return JSON.stringify({
|
|
1406
|
+
return JSON.stringify({
|
|
1407
|
+
error: "token is required and must be a string",
|
|
1408
|
+
});
|
|
1199
1409
|
}
|
|
1200
1410
|
if (/[\x00-\x1f\x7f]/.test(token)) {
|
|
1201
|
-
return JSON.stringify({
|
|
1411
|
+
return JSON.stringify({
|
|
1412
|
+
error: "token contains invalid control characters",
|
|
1413
|
+
});
|
|
1202
1414
|
}
|
|
1203
1415
|
try {
|
|
1204
1416
|
const reqHeaders = {
|
|
@@ -1237,7 +1449,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1237
1449
|
return JSON.stringify(data);
|
|
1238
1450
|
}
|
|
1239
1451
|
catch (err) {
|
|
1240
|
-
return JSON.stringify({
|
|
1452
|
+
return JSON.stringify({
|
|
1453
|
+
error: sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
1454
|
+
});
|
|
1241
1455
|
}
|
|
1242
1456
|
}
|
|
1243
1457
|
async function handleResendVerification() {
|
|
@@ -1248,16 +1462,24 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1248
1462
|
const currentPassword = args.current_password;
|
|
1249
1463
|
const newPassword = args.new_password;
|
|
1250
1464
|
if (!currentPassword || typeof currentPassword !== "string") {
|
|
1251
|
-
return JSON.stringify({
|
|
1465
|
+
return JSON.stringify({
|
|
1466
|
+
error: "current_password is required and must be a string",
|
|
1467
|
+
});
|
|
1252
1468
|
}
|
|
1253
1469
|
if (currentPassword.length < 8 || currentPassword.length > 128) {
|
|
1254
|
-
return JSON.stringify({
|
|
1470
|
+
return JSON.stringify({
|
|
1471
|
+
error: "current_password must be between 8 and 128 characters",
|
|
1472
|
+
});
|
|
1255
1473
|
}
|
|
1256
1474
|
if (!newPassword || typeof newPassword !== "string") {
|
|
1257
|
-
return JSON.stringify({
|
|
1475
|
+
return JSON.stringify({
|
|
1476
|
+
error: "new_password is required and must be a string",
|
|
1477
|
+
});
|
|
1258
1478
|
}
|
|
1259
1479
|
if (newPassword.length < 8 || newPassword.length > 128) {
|
|
1260
|
-
return JSON.stringify({
|
|
1480
|
+
return JSON.stringify({
|
|
1481
|
+
error: "new_password must be between 8 and 128 characters",
|
|
1482
|
+
});
|
|
1261
1483
|
}
|
|
1262
1484
|
const result = await api("POST", "/api/auth/change-password", {
|
|
1263
1485
|
currentPassword,
|
|
@@ -1275,13 +1497,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1275
1497
|
async function handleCreateKey(args) {
|
|
1276
1498
|
const label = args.label;
|
|
1277
1499
|
if (!label || typeof label !== "string") {
|
|
1278
|
-
return JSON.stringify({
|
|
1500
|
+
return JSON.stringify({
|
|
1501
|
+
error: "label is required and must be a string",
|
|
1502
|
+
});
|
|
1279
1503
|
}
|
|
1280
1504
|
if (label.length > 100) {
|
|
1281
1505
|
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
1282
1506
|
}
|
|
1283
1507
|
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
1284
|
-
return JSON.stringify({
|
|
1508
|
+
return JSON.stringify({
|
|
1509
|
+
error: "label contains invalid control characters",
|
|
1510
|
+
});
|
|
1285
1511
|
}
|
|
1286
1512
|
const result = await api("POST", "/api/keys", { label });
|
|
1287
1513
|
return JSON.stringify(result);
|
|
@@ -1289,10 +1515,14 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1289
1515
|
async function handleRevokeKey(args) {
|
|
1290
1516
|
const keyId = args.key_id;
|
|
1291
1517
|
if (!keyId || typeof keyId !== "string") {
|
|
1292
|
-
return JSON.stringify({
|
|
1518
|
+
return JSON.stringify({
|
|
1519
|
+
error: "key_id is required and must be a string",
|
|
1520
|
+
});
|
|
1293
1521
|
}
|
|
1294
1522
|
if (/[\x00-\x1f\x7f]/.test(keyId)) {
|
|
1295
|
-
return JSON.stringify({
|
|
1523
|
+
return JSON.stringify({
|
|
1524
|
+
error: "key_id contains invalid control characters",
|
|
1525
|
+
});
|
|
1296
1526
|
}
|
|
1297
1527
|
const result = await api("DELETE", `/api/keys/${encodeURIComponent(keyId)}`);
|
|
1298
1528
|
return JSON.stringify(result);
|
|
@@ -1311,10 +1541,14 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1311
1541
|
async function handleChangePlan(args) {
|
|
1312
1542
|
const planId = args.plan_id;
|
|
1313
1543
|
if (!planId || typeof planId !== "string") {
|
|
1314
|
-
return JSON.stringify({
|
|
1544
|
+
return JSON.stringify({
|
|
1545
|
+
error: "plan_id is required and must be a string",
|
|
1546
|
+
});
|
|
1315
1547
|
}
|
|
1316
1548
|
if (/[\x00-\x1f\x7f]/.test(planId)) {
|
|
1317
|
-
return JSON.stringify({
|
|
1549
|
+
return JSON.stringify({
|
|
1550
|
+
error: "plan_id contains invalid control characters",
|
|
1551
|
+
});
|
|
1318
1552
|
}
|
|
1319
1553
|
const result = await api("PUT", "/api/plans/user/plan", { planId });
|
|
1320
1554
|
return JSON.stringify(result);
|
|
@@ -1325,7 +1559,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1325
1559
|
async function handleTeamDelete(args) {
|
|
1326
1560
|
const teamId = args.team_id;
|
|
1327
1561
|
if (!teamId || typeof teamId !== "string") {
|
|
1328
|
-
return JSON.stringify({
|
|
1562
|
+
return JSON.stringify({
|
|
1563
|
+
error: "team_id is required and must be a string",
|
|
1564
|
+
});
|
|
1329
1565
|
}
|
|
1330
1566
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1331
1567
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1337,16 +1573,22 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1337
1573
|
const teamId = args.team_id;
|
|
1338
1574
|
const keyId = args.key_id;
|
|
1339
1575
|
if (!teamId || typeof teamId !== "string") {
|
|
1340
|
-
return JSON.stringify({
|
|
1576
|
+
return JSON.stringify({
|
|
1577
|
+
error: "team_id is required and must be a string",
|
|
1578
|
+
});
|
|
1341
1579
|
}
|
|
1342
1580
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1343
1581
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1344
1582
|
}
|
|
1345
1583
|
if (!keyId || typeof keyId !== "string") {
|
|
1346
|
-
return JSON.stringify({
|
|
1584
|
+
return JSON.stringify({
|
|
1585
|
+
error: "key_id is required and must be a string",
|
|
1586
|
+
});
|
|
1347
1587
|
}
|
|
1348
1588
|
if (/[\x00-\x1f\x7f]/.test(keyId)) {
|
|
1349
|
-
return JSON.stringify({
|
|
1589
|
+
return JSON.stringify({
|
|
1590
|
+
error: "key_id contains invalid control characters",
|
|
1591
|
+
});
|
|
1350
1592
|
}
|
|
1351
1593
|
const result = await api("DELETE", `/api/teams/${encodeURIComponent(teamId)}/keys/${encodeURIComponent(keyId)}`);
|
|
1352
1594
|
return JSON.stringify(result);
|
|
@@ -1354,7 +1596,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1354
1596
|
async function handleTeamListKeys(args) {
|
|
1355
1597
|
const teamId = args.team_id;
|
|
1356
1598
|
if (!teamId || typeof teamId !== "string") {
|
|
1357
|
-
return JSON.stringify({
|
|
1599
|
+
return JSON.stringify({
|
|
1600
|
+
error: "team_id is required and must be a string",
|
|
1601
|
+
});
|
|
1358
1602
|
}
|
|
1359
1603
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1360
1604
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1365,7 +1609,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1365
1609
|
async function handleTeamListMembers(args) {
|
|
1366
1610
|
const teamId = args.team_id;
|
|
1367
1611
|
if (!teamId || typeof teamId !== "string") {
|
|
1368
|
-
return JSON.stringify({
|
|
1612
|
+
return JSON.stringify({
|
|
1613
|
+
error: "team_id is required and must be a string",
|
|
1614
|
+
});
|
|
1369
1615
|
}
|
|
1370
1616
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1371
1617
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1377,13 +1623,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1377
1623
|
const teamId = args.team_id;
|
|
1378
1624
|
const userId = args.user_id;
|
|
1379
1625
|
if (!teamId || typeof teamId !== "string") {
|
|
1380
|
-
return JSON.stringify({
|
|
1626
|
+
return JSON.stringify({
|
|
1627
|
+
error: "team_id is required and must be a string",
|
|
1628
|
+
});
|
|
1381
1629
|
}
|
|
1382
1630
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1383
1631
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1384
1632
|
}
|
|
1385
1633
|
if (!userId || typeof userId !== "string") {
|
|
1386
|
-
return JSON.stringify({
|
|
1634
|
+
return JSON.stringify({
|
|
1635
|
+
error: "user_id is required and must be a string",
|
|
1636
|
+
});
|
|
1387
1637
|
}
|
|
1388
1638
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
1389
1639
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -1395,13 +1645,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1395
1645
|
const teamId = args.team_id;
|
|
1396
1646
|
const userId = args.user_id;
|
|
1397
1647
|
if (!teamId || typeof teamId !== "string") {
|
|
1398
|
-
return JSON.stringify({
|
|
1648
|
+
return JSON.stringify({
|
|
1649
|
+
error: "team_id is required and must be a string",
|
|
1650
|
+
});
|
|
1399
1651
|
}
|
|
1400
1652
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1401
1653
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1402
1654
|
}
|
|
1403
1655
|
if (!userId || typeof userId !== "string") {
|
|
1404
|
-
return JSON.stringify({
|
|
1656
|
+
return JSON.stringify({
|
|
1657
|
+
error: "user_id is required and must be a string",
|
|
1658
|
+
});
|
|
1405
1659
|
}
|
|
1406
1660
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)) {
|
|
1407
1661
|
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
@@ -1414,19 +1668,25 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1414
1668
|
const email = args.email;
|
|
1415
1669
|
const role = args.role ?? "member";
|
|
1416
1670
|
if (!teamId || typeof teamId !== "string") {
|
|
1417
|
-
return JSON.stringify({
|
|
1671
|
+
return JSON.stringify({
|
|
1672
|
+
error: "team_id is required and must be a string",
|
|
1673
|
+
});
|
|
1418
1674
|
}
|
|
1419
1675
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1420
1676
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1421
1677
|
}
|
|
1422
1678
|
if (!email || typeof email !== "string") {
|
|
1423
|
-
return JSON.stringify({
|
|
1679
|
+
return JSON.stringify({
|
|
1680
|
+
error: "email is required and must be a string",
|
|
1681
|
+
});
|
|
1424
1682
|
}
|
|
1425
1683
|
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1426
1684
|
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1427
1685
|
}
|
|
1428
1686
|
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1429
|
-
return JSON.stringify({
|
|
1687
|
+
return JSON.stringify({
|
|
1688
|
+
error: "email contains invalid control characters",
|
|
1689
|
+
});
|
|
1430
1690
|
}
|
|
1431
1691
|
if (role !== "member" && role !== "admin") {
|
|
1432
1692
|
return JSON.stringify({ error: "role must be 'member' or 'admin'" });
|
|
@@ -1437,7 +1697,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1437
1697
|
async function handleTeamListInvites(args) {
|
|
1438
1698
|
const teamId = args.team_id;
|
|
1439
1699
|
if (!teamId || typeof teamId !== "string") {
|
|
1440
|
-
return JSON.stringify({
|
|
1700
|
+
return JSON.stringify({
|
|
1701
|
+
error: "team_id is required and must be a string",
|
|
1702
|
+
});
|
|
1441
1703
|
}
|
|
1442
1704
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1443
1705
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
@@ -1449,13 +1711,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1449
1711
|
const teamId = args.team_id;
|
|
1450
1712
|
const inviteId = args.invite_id;
|
|
1451
1713
|
if (!teamId || typeof teamId !== "string") {
|
|
1452
|
-
return JSON.stringify({
|
|
1714
|
+
return JSON.stringify({
|
|
1715
|
+
error: "team_id is required and must be a string",
|
|
1716
|
+
});
|
|
1453
1717
|
}
|
|
1454
1718
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(teamId)) {
|
|
1455
1719
|
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1456
1720
|
}
|
|
1457
1721
|
if (!inviteId || typeof inviteId !== "string") {
|
|
1458
|
-
return JSON.stringify({
|
|
1722
|
+
return JSON.stringify({
|
|
1723
|
+
error: "invite_id is required and must be a string",
|
|
1724
|
+
});
|
|
1459
1725
|
}
|
|
1460
1726
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(inviteId)) {
|
|
1461
1727
|
return JSON.stringify({ error: "invite_id must be a valid UUID" });
|
|
@@ -1520,11 +1786,19 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1520
1786
|
dominusnode_topup_crypto: handleTopupCrypto,
|
|
1521
1787
|
dominusnode_x402_info: handleX402Info,
|
|
1522
1788
|
dominusnode_update_wallet_policy: handleUpdateWalletPolicy,
|
|
1789
|
+
// MPP (5)
|
|
1790
|
+
dominusnode_mpp_info: handleMppInfo,
|
|
1791
|
+
dominusnode_mpp_challenge: handleMppChallenge,
|
|
1792
|
+
dominusnode_pay_mpp: handlePayMpp,
|
|
1793
|
+
dominusnode_mpp_session_open: handleMppSessionOpen,
|
|
1794
|
+
dominusnode_mpp_session_close: handleMppSessionClose,
|
|
1523
1795
|
};
|
|
1524
1796
|
async function handleUpdateWalletPolicy(args) {
|
|
1525
1797
|
const walletId = args.wallet_id;
|
|
1526
1798
|
if (!walletId || typeof walletId !== "string") {
|
|
1527
|
-
return JSON.stringify({
|
|
1799
|
+
return JSON.stringify({
|
|
1800
|
+
error: "wallet_id is required and must be a string",
|
|
1801
|
+
});
|
|
1528
1802
|
}
|
|
1529
1803
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(walletId)) {
|
|
1530
1804
|
return JSON.stringify({ error: "wallet_id must be a valid UUID" });
|
|
@@ -1536,7 +1810,9 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1536
1810
|
}
|
|
1537
1811
|
else {
|
|
1538
1812
|
const dailyLimit = Number(args.daily_limit_cents);
|
|
1539
|
-
if (!Number.isInteger(dailyLimit) ||
|
|
1813
|
+
if (!Number.isInteger(dailyLimit) ||
|
|
1814
|
+
dailyLimit < 1 ||
|
|
1815
|
+
dailyLimit > 1_000_000) {
|
|
1540
1816
|
return JSON.stringify({
|
|
1541
1817
|
error: "daily_limit_cents must be a positive integer between 1 and 1,000,000, or null to clear",
|
|
1542
1818
|
});
|
|
@@ -1550,22 +1826,32 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1550
1826
|
}
|
|
1551
1827
|
else {
|
|
1552
1828
|
if (!Array.isArray(args.allowed_domains)) {
|
|
1553
|
-
return JSON.stringify({
|
|
1829
|
+
return JSON.stringify({
|
|
1830
|
+
error: "allowed_domains must be an array of domain strings, or null to clear",
|
|
1831
|
+
});
|
|
1554
1832
|
}
|
|
1555
1833
|
if (args.allowed_domains.length > 100) {
|
|
1556
|
-
return JSON.stringify({
|
|
1834
|
+
return JSON.stringify({
|
|
1835
|
+
error: "allowed_domains must have at most 100 entries",
|
|
1836
|
+
});
|
|
1557
1837
|
}
|
|
1558
1838
|
const domainRe = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
1559
1839
|
for (let i = 0; i < args.allowed_domains.length; i++) {
|
|
1560
1840
|
const d = args.allowed_domains[i];
|
|
1561
1841
|
if (typeof d !== "string") {
|
|
1562
|
-
return JSON.stringify({
|
|
1842
|
+
return JSON.stringify({
|
|
1843
|
+
error: `allowed_domains[${i}] must be a string`,
|
|
1844
|
+
});
|
|
1563
1845
|
}
|
|
1564
1846
|
if (d.length > 253) {
|
|
1565
|
-
return JSON.stringify({
|
|
1847
|
+
return JSON.stringify({
|
|
1848
|
+
error: `allowed_domains[${i}] exceeds 253 characters`,
|
|
1849
|
+
});
|
|
1566
1850
|
}
|
|
1567
1851
|
if (!domainRe.test(d)) {
|
|
1568
|
-
return JSON.stringify({
|
|
1852
|
+
return JSON.stringify({
|
|
1853
|
+
error: `allowed_domains[${i}] is not a valid domain: ${d}`,
|
|
1854
|
+
});
|
|
1569
1855
|
}
|
|
1570
1856
|
}
|
|
1571
1857
|
body.allowedDomains = args.allowed_domains;
|
|
@@ -1584,6 +1870,121 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
1584
1870
|
return JSON.stringify(result);
|
|
1585
1871
|
}
|
|
1586
1872
|
// -----------------------------------------------------------------------
|
|
1873
|
+
// MPP (Machine Payment Protocol) handlers
|
|
1874
|
+
// -----------------------------------------------------------------------
|
|
1875
|
+
async function handleMppInfo() {
|
|
1876
|
+
// MPP info is public (no auth required), but we use the authenticated path
|
|
1877
|
+
// for simplicity since the handler is already authenticated.
|
|
1878
|
+
const result = await api("GET", "/api/mpp/info");
|
|
1879
|
+
return JSON.stringify(result);
|
|
1880
|
+
}
|
|
1881
|
+
async function handleMppChallenge(args) {
|
|
1882
|
+
const poolType = String(args.pool_type ?? "dc");
|
|
1883
|
+
if (poolType !== "dc" && poolType !== "residential") {
|
|
1884
|
+
return JSON.stringify({
|
|
1885
|
+
error: "pool_type must be 'dc' or 'residential'",
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
// This is a public endpoint -- no auth required
|
|
1889
|
+
try {
|
|
1890
|
+
const reqHeaders = {
|
|
1891
|
+
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
1892
|
+
"Content-Type": "application/json",
|
|
1893
|
+
};
|
|
1894
|
+
if (agentSecret) {
|
|
1895
|
+
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1896
|
+
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1897
|
+
}
|
|
1898
|
+
const response = await fetch(`${baseUrl}/api/mpp/challenge`, {
|
|
1899
|
+
method: "POST",
|
|
1900
|
+
headers: reqHeaders,
|
|
1901
|
+
body: JSON.stringify({ poolType }),
|
|
1902
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1903
|
+
redirect: "error",
|
|
1904
|
+
});
|
|
1905
|
+
const responseText = await response.text();
|
|
1906
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
1907
|
+
return JSON.stringify({ error: "Response body exceeds size limit" });
|
|
1908
|
+
}
|
|
1909
|
+
if (!response.ok) {
|
|
1910
|
+
let message;
|
|
1911
|
+
try {
|
|
1912
|
+
const parsed = JSON.parse(responseText);
|
|
1913
|
+
message = parsed.error ?? parsed.message ?? responseText;
|
|
1914
|
+
}
|
|
1915
|
+
catch {
|
|
1916
|
+
message = responseText;
|
|
1917
|
+
}
|
|
1918
|
+
if (message.length > 500)
|
|
1919
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
1920
|
+
return JSON.stringify({
|
|
1921
|
+
error: `MPP challenge failed: ${sanitizeError(message)}`,
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
const data = safeJsonParse(responseText);
|
|
1925
|
+
return JSON.stringify(data);
|
|
1926
|
+
}
|
|
1927
|
+
catch (err) {
|
|
1928
|
+
return JSON.stringify({
|
|
1929
|
+
error: `MPP challenge failed: ${sanitizeError(err instanceof Error ? err.message : String(err))}`,
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
async function handlePayMpp(args) {
|
|
1934
|
+
const amountCents = args.amount_cents;
|
|
1935
|
+
const method = String(args.method ?? "");
|
|
1936
|
+
if (!Number.isInteger(amountCents) ||
|
|
1937
|
+
amountCents < 500 ||
|
|
1938
|
+
amountCents > 100_000) {
|
|
1939
|
+
return JSON.stringify({
|
|
1940
|
+
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
if (!["tempo", "stripe_spt", "lightning"].includes(method)) {
|
|
1944
|
+
return JSON.stringify({
|
|
1945
|
+
error: "method must be one of: tempo, stripe_spt, lightning",
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
const result = await api("POST", "/api/mpp/topup", { amountCents, method });
|
|
1949
|
+
return JSON.stringify(result);
|
|
1950
|
+
}
|
|
1951
|
+
async function handleMppSessionOpen(args) {
|
|
1952
|
+
const maxDepositCents = args.max_deposit_cents;
|
|
1953
|
+
const method = String(args.method ?? "");
|
|
1954
|
+
const poolType = String(args.pool_type ?? "dc");
|
|
1955
|
+
if (!Number.isInteger(maxDepositCents) ||
|
|
1956
|
+
maxDepositCents < 500 ||
|
|
1957
|
+
maxDepositCents > 100_000) {
|
|
1958
|
+
return JSON.stringify({
|
|
1959
|
+
error: "max_deposit_cents must be an integer between 500 and 100,000",
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
if (!["tempo", "stripe_spt", "lightning"].includes(method)) {
|
|
1963
|
+
return JSON.stringify({
|
|
1964
|
+
error: "method must be one of: tempo, stripe_spt, lightning",
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
if (!["dc", "residential"].includes(poolType)) {
|
|
1968
|
+
return JSON.stringify({
|
|
1969
|
+
error: "pool_type must be one of: dc, residential",
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
const result = await api("POST", "/api/mpp/session/open", {
|
|
1973
|
+
maxDepositCents,
|
|
1974
|
+
method,
|
|
1975
|
+
poolType,
|
|
1976
|
+
});
|
|
1977
|
+
return JSON.stringify(result);
|
|
1978
|
+
}
|
|
1979
|
+
async function handleMppSessionClose(args) {
|
|
1980
|
+
const channelId = String(args.channel_id ?? "");
|
|
1981
|
+
if (!channelId) {
|
|
1982
|
+
return JSON.stringify({ error: "channel_id is required" });
|
|
1983
|
+
}
|
|
1984
|
+
const result = await api("POST", "/api/mpp/session/close", { channelId });
|
|
1985
|
+
return JSON.stringify(result);
|
|
1986
|
+
}
|
|
1987
|
+
// -----------------------------------------------------------------------
|
|
1587
1988
|
// Main handler
|
|
1588
1989
|
// -----------------------------------------------------------------------
|
|
1589
1990
|
return async function handler(name, args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dominusnode/gemini-functions",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Dominus Node function declarations and handlers for Google Gemini / Vertex AI",
|
|
5
5
|
"main": "dist/handler.js",
|
|
6
6
|
"types": "dist/handler.d.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc",
|
|
16
|
+
"prepare": "npm run build",
|
|
16
17
|
"test": "vitest run",
|
|
17
18
|
"test:watch": "vitest",
|
|
18
19
|
"test:py": "python -m pytest test_handler.py -v"
|