@dominusnode/gemini-functions 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/handler.d.ts +4 -0
- package/dist/handler.js +544 -5
- package/functions.json +34 -2
- package/package.json +14 -3
package/dist/handler.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node Gemini / Vertex AI function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
+
* 53 tools for AI agents to interact with the Dominus Node REST API.
|
|
5
|
+
*
|
|
4
6
|
* Provides a factory function that creates a handler for dispatching
|
|
5
7
|
* Google Gemini function calls to the Dominus Node REST API. Works with
|
|
6
8
|
* Gemini, Vertex AI, or any system that uses Gemini-format function
|
|
@@ -46,6 +48,8 @@ export interface DominusNodeFunctionConfig {
|
|
|
46
48
|
baseUrl?: string;
|
|
47
49
|
/** Request timeout in milliseconds. Defaults to 30000. */
|
|
48
50
|
timeoutMs?: number;
|
|
51
|
+
/** Optional agent secret for MCP agent auto-verification (bypasses reCAPTCHA). */
|
|
52
|
+
agentSecret?: string;
|
|
49
53
|
}
|
|
50
54
|
/**
|
|
51
55
|
* Handler function type returned by createDominusNodeFunctionHandler.
|
package/dist/handler.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dominus Node Gemini / Vertex AI function calling handler (TypeScript).
|
|
3
3
|
*
|
|
4
|
+
* 53 tools for AI agents to interact with the Dominus Node REST API.
|
|
5
|
+
*
|
|
4
6
|
* Provides a factory function that creates a handler for dispatching
|
|
5
7
|
* Google Gemini function calls to the Dominus Node REST API. Works with
|
|
6
8
|
* Gemini, Vertex AI, or any system that uses Gemini-format function
|
|
@@ -325,6 +327,10 @@ async function apiRequest(config, method, path, body) {
|
|
|
325
327
|
"Content-Type": "application/json",
|
|
326
328
|
Authorization: `Bearer ${config.token}`,
|
|
327
329
|
};
|
|
330
|
+
if (config.agentSecret) {
|
|
331
|
+
headers["X-DominusNode-Agent"] = "mcp";
|
|
332
|
+
headers["X-DominusNode-Agent-Secret"] = config.agentSecret;
|
|
333
|
+
}
|
|
328
334
|
const response = await fetch(url, {
|
|
329
335
|
method,
|
|
330
336
|
headers,
|
|
@@ -405,6 +411,7 @@ export { isPrivateIp, validateUrl, normalizeIpv4, sanitizeError, stripDangerousK
|
|
|
405
411
|
export function createDominusNodeFunctionHandler(config) {
|
|
406
412
|
const baseUrl = config.baseUrl ?? "https://api.dominusnode.com";
|
|
407
413
|
const timeoutMs = config.timeoutMs ?? 30_000;
|
|
414
|
+
const agentSecret = config.agentSecret || process.env.DOMINUSNODE_AGENT_SECRET;
|
|
408
415
|
if (!config.apiKey || typeof config.apiKey !== "string") {
|
|
409
416
|
throw new Error("apiKey is required and must be a non-empty string");
|
|
410
417
|
}
|
|
@@ -412,12 +419,17 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
412
419
|
let authToken = null;
|
|
413
420
|
let authPromise = null;
|
|
414
421
|
async function authenticate() {
|
|
422
|
+
const authHeaders = {
|
|
423
|
+
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
424
|
+
"Content-Type": "application/json",
|
|
425
|
+
};
|
|
426
|
+
if (agentSecret) {
|
|
427
|
+
authHeaders["X-DominusNode-Agent"] = "mcp";
|
|
428
|
+
authHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
429
|
+
}
|
|
415
430
|
const response = await fetch(`${baseUrl}/api/auth/verify-key`, {
|
|
416
431
|
method: "POST",
|
|
417
|
-
headers:
|
|
418
|
-
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
419
|
-
"Content-Type": "application/json",
|
|
420
|
-
},
|
|
432
|
+
headers: authHeaders,
|
|
421
433
|
body: JSON.stringify({ apiKey: config.apiKey }),
|
|
422
434
|
signal: AbortSignal.timeout(timeoutMs),
|
|
423
435
|
redirect: "error",
|
|
@@ -445,7 +457,7 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
445
457
|
function api(method, path, body) {
|
|
446
458
|
if (!authToken)
|
|
447
459
|
throw new Error("Not authenticated");
|
|
448
|
-
return apiRequest({ baseUrl, timeoutMs, token: authToken }, method, path, body);
|
|
460
|
+
return apiRequest({ baseUrl, timeoutMs, token: authToken, agentSecret }, method, path, body);
|
|
449
461
|
}
|
|
450
462
|
// -----------------------------------------------------------------------
|
|
451
463
|
// Function handlers
|
|
@@ -953,6 +965,504 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
953
965
|
const result = await api("POST", "/api/wallet/topup/paypal", { amountCents });
|
|
954
966
|
return JSON.stringify(result);
|
|
955
967
|
}
|
|
968
|
+
async function handleTopupStripe(args) {
|
|
969
|
+
const amountCents = args.amount_cents;
|
|
970
|
+
if (!Number.isInteger(amountCents) ||
|
|
971
|
+
amountCents < 500 ||
|
|
972
|
+
amountCents > 100_000) {
|
|
973
|
+
return JSON.stringify({
|
|
974
|
+
error: "amount_cents must be an integer between 500 ($5) and 100,000 ($1,000)",
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
const result = await api("POST", "/api/wallet/topup/stripe", { amountCents });
|
|
978
|
+
return JSON.stringify(result);
|
|
979
|
+
}
|
|
980
|
+
const VALID_CRYPTO_CURRENCIES = new Set([
|
|
981
|
+
"btc", "eth", "ltc", "xmr", "zec", "usdc", "sol", "usdt", "dai", "bnb", "link",
|
|
982
|
+
]);
|
|
983
|
+
async function handleTopupCrypto(args) {
|
|
984
|
+
const amountUsd = args.amount_usd;
|
|
985
|
+
const currency = String(args.currency ?? "").toLowerCase();
|
|
986
|
+
if (typeof amountUsd !== "number" ||
|
|
987
|
+
!Number.isFinite(amountUsd) ||
|
|
988
|
+
amountUsd < 5 ||
|
|
989
|
+
amountUsd > 1_000) {
|
|
990
|
+
return JSON.stringify({
|
|
991
|
+
error: "amount_usd must be a number between 5 and 1,000",
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
if (!VALID_CRYPTO_CURRENCIES.has(currency)) {
|
|
995
|
+
return JSON.stringify({
|
|
996
|
+
error: `currency must be one of: ${[...VALID_CRYPTO_CURRENCIES].join(", ")}`,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
const result = await api("POST", "/api/wallet/topup/crypto", {
|
|
1000
|
+
amountUsd,
|
|
1001
|
+
currency,
|
|
1002
|
+
});
|
|
1003
|
+
return JSON.stringify(result);
|
|
1004
|
+
}
|
|
1005
|
+
// -----------------------------------------------------------------------
|
|
1006
|
+
// Proxy extended
|
|
1007
|
+
// -----------------------------------------------------------------------
|
|
1008
|
+
async function handleGetProxyStatus() {
|
|
1009
|
+
const result = await api("GET", "/api/proxy/status");
|
|
1010
|
+
return JSON.stringify(result);
|
|
1011
|
+
}
|
|
1012
|
+
// -----------------------------------------------------------------------
|
|
1013
|
+
// Wallet extended
|
|
1014
|
+
// -----------------------------------------------------------------------
|
|
1015
|
+
async function handleGetTransactions(args) {
|
|
1016
|
+
const params = new URLSearchParams();
|
|
1017
|
+
if (args.limit !== undefined) {
|
|
1018
|
+
const limit = Number(args.limit);
|
|
1019
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
1020
|
+
return JSON.stringify({ error: "limit must be an integer between 1 and 100" });
|
|
1021
|
+
}
|
|
1022
|
+
params.set("limit", String(limit));
|
|
1023
|
+
}
|
|
1024
|
+
const qs = params.toString();
|
|
1025
|
+
const result = await api("GET", `/api/wallet/transactions${qs ? `?${qs}` : ""}`);
|
|
1026
|
+
return JSON.stringify(result);
|
|
1027
|
+
}
|
|
1028
|
+
async function handleGetForecast() {
|
|
1029
|
+
const result = await api("GET", "/api/wallet/forecast");
|
|
1030
|
+
return JSON.stringify(result);
|
|
1031
|
+
}
|
|
1032
|
+
async function handleCheckPayment(args) {
|
|
1033
|
+
const invoiceId = args.invoice_id;
|
|
1034
|
+
if (!invoiceId || typeof invoiceId !== "string") {
|
|
1035
|
+
return JSON.stringify({ error: "invoice_id is required and must be a string" });
|
|
1036
|
+
}
|
|
1037
|
+
if (/[\x00-\x1f\x7f]/.test(invoiceId)) {
|
|
1038
|
+
return JSON.stringify({ error: "invoice_id contains invalid control characters" });
|
|
1039
|
+
}
|
|
1040
|
+
const result = await api("GET", `/api/wallet/topup/crypto/${encodeURIComponent(invoiceId)}/status`);
|
|
1041
|
+
return JSON.stringify(result);
|
|
1042
|
+
}
|
|
1043
|
+
// -----------------------------------------------------------------------
|
|
1044
|
+
// Usage extended
|
|
1045
|
+
// -----------------------------------------------------------------------
|
|
1046
|
+
async function handleGetDailyUsage(args) {
|
|
1047
|
+
const params = new URLSearchParams();
|
|
1048
|
+
if (args.days !== undefined) {
|
|
1049
|
+
const days = Number(args.days);
|
|
1050
|
+
if (!Number.isInteger(days) || days < 1 || days > 90) {
|
|
1051
|
+
return JSON.stringify({ error: "days must be an integer between 1 and 90" });
|
|
1052
|
+
}
|
|
1053
|
+
params.set("days", String(days));
|
|
1054
|
+
}
|
|
1055
|
+
const qs = params.toString();
|
|
1056
|
+
const result = await api("GET", `/api/usage/daily${qs ? `?${qs}` : ""}`);
|
|
1057
|
+
return JSON.stringify(result);
|
|
1058
|
+
}
|
|
1059
|
+
async function handleGetTopHosts(args) {
|
|
1060
|
+
const params = new URLSearchParams();
|
|
1061
|
+
if (args.limit !== undefined) {
|
|
1062
|
+
const limit = Number(args.limit);
|
|
1063
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
|
|
1064
|
+
return JSON.stringify({ error: "limit must be an integer between 1 and 50" });
|
|
1065
|
+
}
|
|
1066
|
+
params.set("limit", String(limit));
|
|
1067
|
+
}
|
|
1068
|
+
const qs = params.toString();
|
|
1069
|
+
const result = await api("GET", `/api/usage/top-hosts${qs ? `?${qs}` : ""}`);
|
|
1070
|
+
return JSON.stringify(result);
|
|
1071
|
+
}
|
|
1072
|
+
// -----------------------------------------------------------------------
|
|
1073
|
+
// Account lifecycle
|
|
1074
|
+
// -----------------------------------------------------------------------
|
|
1075
|
+
async function handleRegister(args) {
|
|
1076
|
+
const email = args.email;
|
|
1077
|
+
const password = args.password;
|
|
1078
|
+
if (!email || typeof email !== "string") {
|
|
1079
|
+
return JSON.stringify({ error: "email is required and must be a string" });
|
|
1080
|
+
}
|
|
1081
|
+
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1082
|
+
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1083
|
+
}
|
|
1084
|
+
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1085
|
+
return JSON.stringify({ error: "email contains invalid control characters" });
|
|
1086
|
+
}
|
|
1087
|
+
if (!password || typeof password !== "string") {
|
|
1088
|
+
return JSON.stringify({ error: "password is required and must be a string" });
|
|
1089
|
+
}
|
|
1090
|
+
if (password.length < 8 || password.length > 128) {
|
|
1091
|
+
return JSON.stringify({ error: "password must be between 8 and 128 characters" });
|
|
1092
|
+
}
|
|
1093
|
+
try {
|
|
1094
|
+
const reqHeaders = {
|
|
1095
|
+
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
1096
|
+
"Content-Type": "application/json",
|
|
1097
|
+
};
|
|
1098
|
+
if (agentSecret) {
|
|
1099
|
+
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1100
|
+
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1101
|
+
}
|
|
1102
|
+
const response = await fetch(`${baseUrl}/api/auth/register`, {
|
|
1103
|
+
method: "POST",
|
|
1104
|
+
headers: reqHeaders,
|
|
1105
|
+
body: JSON.stringify({ email, password }),
|
|
1106
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1107
|
+
redirect: "error",
|
|
1108
|
+
});
|
|
1109
|
+
const responseText = await response.text();
|
|
1110
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
1111
|
+
return JSON.stringify({ error: "Response body exceeds size limit" });
|
|
1112
|
+
}
|
|
1113
|
+
if (!response.ok) {
|
|
1114
|
+
let message;
|
|
1115
|
+
try {
|
|
1116
|
+
const parsed = JSON.parse(responseText);
|
|
1117
|
+
message = parsed.error ?? parsed.message ?? responseText;
|
|
1118
|
+
}
|
|
1119
|
+
catch {
|
|
1120
|
+
message = responseText;
|
|
1121
|
+
}
|
|
1122
|
+
if (message.length > 500)
|
|
1123
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
1124
|
+
return JSON.stringify({ error: sanitizeError(message) });
|
|
1125
|
+
}
|
|
1126
|
+
const data = safeJsonParse(responseText);
|
|
1127
|
+
return JSON.stringify({ userId: data.userId, email: data.email, message: data.message ?? "Registration successful" });
|
|
1128
|
+
}
|
|
1129
|
+
catch (err) {
|
|
1130
|
+
return JSON.stringify({ error: sanitizeError(err instanceof Error ? err.message : String(err)) });
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async function handleLogin(args) {
|
|
1134
|
+
const email = args.email;
|
|
1135
|
+
const password = args.password;
|
|
1136
|
+
if (!email || typeof email !== "string") {
|
|
1137
|
+
return JSON.stringify({ error: "email is required and must be a string" });
|
|
1138
|
+
}
|
|
1139
|
+
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1140
|
+
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1141
|
+
}
|
|
1142
|
+
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1143
|
+
return JSON.stringify({ error: "email contains invalid control characters" });
|
|
1144
|
+
}
|
|
1145
|
+
if (!password || typeof password !== "string") {
|
|
1146
|
+
return JSON.stringify({ error: "password is required and must be a string" });
|
|
1147
|
+
}
|
|
1148
|
+
if (password.length < 8 || password.length > 128) {
|
|
1149
|
+
return JSON.stringify({ error: "password must be between 8 and 128 characters" });
|
|
1150
|
+
}
|
|
1151
|
+
try {
|
|
1152
|
+
const reqHeaders = {
|
|
1153
|
+
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
1154
|
+
"Content-Type": "application/json",
|
|
1155
|
+
};
|
|
1156
|
+
if (agentSecret) {
|
|
1157
|
+
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1158
|
+
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1159
|
+
}
|
|
1160
|
+
const response = await fetch(`${baseUrl}/api/auth/login`, {
|
|
1161
|
+
method: "POST",
|
|
1162
|
+
headers: reqHeaders,
|
|
1163
|
+
body: JSON.stringify({ email, password }),
|
|
1164
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1165
|
+
redirect: "error",
|
|
1166
|
+
});
|
|
1167
|
+
const responseText = await response.text();
|
|
1168
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
1169
|
+
return JSON.stringify({ error: "Response body exceeds size limit" });
|
|
1170
|
+
}
|
|
1171
|
+
if (!response.ok) {
|
|
1172
|
+
let message;
|
|
1173
|
+
try {
|
|
1174
|
+
const parsed = JSON.parse(responseText);
|
|
1175
|
+
message = parsed.error ?? parsed.message ?? responseText;
|
|
1176
|
+
}
|
|
1177
|
+
catch {
|
|
1178
|
+
message = responseText;
|
|
1179
|
+
}
|
|
1180
|
+
if (message.length > 500)
|
|
1181
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
1182
|
+
return JSON.stringify({ error: sanitizeError(message) });
|
|
1183
|
+
}
|
|
1184
|
+
const data = safeJsonParse(responseText);
|
|
1185
|
+
return JSON.stringify({ token: data.token, message: data.message ?? "Login successful" });
|
|
1186
|
+
}
|
|
1187
|
+
catch (err) {
|
|
1188
|
+
return JSON.stringify({ error: sanitizeError(err instanceof Error ? err.message : String(err)) });
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
async function handleGetAccountInfo() {
|
|
1192
|
+
const result = await api("GET", "/api/auth/me");
|
|
1193
|
+
return JSON.stringify(result);
|
|
1194
|
+
}
|
|
1195
|
+
async function handleVerifyEmail(args) {
|
|
1196
|
+
const token = args.token;
|
|
1197
|
+
if (!token || typeof token !== "string") {
|
|
1198
|
+
return JSON.stringify({ error: "token is required and must be a string" });
|
|
1199
|
+
}
|
|
1200
|
+
if (/[\x00-\x1f\x7f]/.test(token)) {
|
|
1201
|
+
return JSON.stringify({ error: "token contains invalid control characters" });
|
|
1202
|
+
}
|
|
1203
|
+
try {
|
|
1204
|
+
const reqHeaders = {
|
|
1205
|
+
"User-Agent": "dominusnode-gemini/1.0.0",
|
|
1206
|
+
"Content-Type": "application/json",
|
|
1207
|
+
};
|
|
1208
|
+
if (agentSecret) {
|
|
1209
|
+
reqHeaders["X-DominusNode-Agent"] = "mcp";
|
|
1210
|
+
reqHeaders["X-DominusNode-Agent-Secret"] = agentSecret;
|
|
1211
|
+
}
|
|
1212
|
+
const response = await fetch(`${baseUrl}/api/auth/verify-email`, {
|
|
1213
|
+
method: "POST",
|
|
1214
|
+
headers: reqHeaders,
|
|
1215
|
+
body: JSON.stringify({ token }),
|
|
1216
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1217
|
+
redirect: "error",
|
|
1218
|
+
});
|
|
1219
|
+
const responseText = await response.text();
|
|
1220
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
1221
|
+
return JSON.stringify({ error: "Response body exceeds size limit" });
|
|
1222
|
+
}
|
|
1223
|
+
if (!response.ok) {
|
|
1224
|
+
let message;
|
|
1225
|
+
try {
|
|
1226
|
+
const parsed = JSON.parse(responseText);
|
|
1227
|
+
message = parsed.error ?? parsed.message ?? responseText;
|
|
1228
|
+
}
|
|
1229
|
+
catch {
|
|
1230
|
+
message = responseText;
|
|
1231
|
+
}
|
|
1232
|
+
if (message.length > 500)
|
|
1233
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
1234
|
+
return JSON.stringify({ error: sanitizeError(message) });
|
|
1235
|
+
}
|
|
1236
|
+
const data = safeJsonParse(responseText);
|
|
1237
|
+
return JSON.stringify(data);
|
|
1238
|
+
}
|
|
1239
|
+
catch (err) {
|
|
1240
|
+
return JSON.stringify({ error: sanitizeError(err instanceof Error ? err.message : String(err)) });
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
async function handleResendVerification() {
|
|
1244
|
+
const result = await api("POST", "/api/auth/resend-verification");
|
|
1245
|
+
return JSON.stringify(result);
|
|
1246
|
+
}
|
|
1247
|
+
async function handleUpdatePassword(args) {
|
|
1248
|
+
const currentPassword = args.current_password;
|
|
1249
|
+
const newPassword = args.new_password;
|
|
1250
|
+
if (!currentPassword || typeof currentPassword !== "string") {
|
|
1251
|
+
return JSON.stringify({ error: "current_password is required and must be a string" });
|
|
1252
|
+
}
|
|
1253
|
+
if (currentPassword.length < 8 || currentPassword.length > 128) {
|
|
1254
|
+
return JSON.stringify({ error: "current_password must be between 8 and 128 characters" });
|
|
1255
|
+
}
|
|
1256
|
+
if (!newPassword || typeof newPassword !== "string") {
|
|
1257
|
+
return JSON.stringify({ error: "new_password is required and must be a string" });
|
|
1258
|
+
}
|
|
1259
|
+
if (newPassword.length < 8 || newPassword.length > 128) {
|
|
1260
|
+
return JSON.stringify({ error: "new_password must be between 8 and 128 characters" });
|
|
1261
|
+
}
|
|
1262
|
+
const result = await api("POST", "/api/auth/change-password", {
|
|
1263
|
+
currentPassword,
|
|
1264
|
+
newPassword,
|
|
1265
|
+
});
|
|
1266
|
+
return JSON.stringify(result);
|
|
1267
|
+
}
|
|
1268
|
+
// -----------------------------------------------------------------------
|
|
1269
|
+
// API Keys
|
|
1270
|
+
// -----------------------------------------------------------------------
|
|
1271
|
+
async function handleListKeys() {
|
|
1272
|
+
const result = await api("GET", "/api/keys");
|
|
1273
|
+
return JSON.stringify(result);
|
|
1274
|
+
}
|
|
1275
|
+
async function handleCreateKey(args) {
|
|
1276
|
+
const label = args.label;
|
|
1277
|
+
if (!label || typeof label !== "string") {
|
|
1278
|
+
return JSON.stringify({ error: "label is required and must be a string" });
|
|
1279
|
+
}
|
|
1280
|
+
if (label.length > 100) {
|
|
1281
|
+
return JSON.stringify({ error: "label must be 100 characters or fewer" });
|
|
1282
|
+
}
|
|
1283
|
+
if (/[\x00-\x1f\x7f]/.test(label)) {
|
|
1284
|
+
return JSON.stringify({ error: "label contains invalid control characters" });
|
|
1285
|
+
}
|
|
1286
|
+
const result = await api("POST", "/api/keys", { label });
|
|
1287
|
+
return JSON.stringify(result);
|
|
1288
|
+
}
|
|
1289
|
+
async function handleRevokeKey(args) {
|
|
1290
|
+
const keyId = args.key_id;
|
|
1291
|
+
if (!keyId || typeof keyId !== "string") {
|
|
1292
|
+
return JSON.stringify({ error: "key_id is required and must be a string" });
|
|
1293
|
+
}
|
|
1294
|
+
if (/[\x00-\x1f\x7f]/.test(keyId)) {
|
|
1295
|
+
return JSON.stringify({ error: "key_id contains invalid control characters" });
|
|
1296
|
+
}
|
|
1297
|
+
const result = await api("DELETE", `/api/keys/${encodeURIComponent(keyId)}`);
|
|
1298
|
+
return JSON.stringify(result);
|
|
1299
|
+
}
|
|
1300
|
+
// -----------------------------------------------------------------------
|
|
1301
|
+
// Plans
|
|
1302
|
+
// -----------------------------------------------------------------------
|
|
1303
|
+
async function handleGetPlan() {
|
|
1304
|
+
const result = await api("GET", "/api/plans/user/plan");
|
|
1305
|
+
return JSON.stringify(result);
|
|
1306
|
+
}
|
|
1307
|
+
async function handleListPlans() {
|
|
1308
|
+
const result = await api("GET", "/api/plans");
|
|
1309
|
+
return JSON.stringify(result);
|
|
1310
|
+
}
|
|
1311
|
+
async function handleChangePlan(args) {
|
|
1312
|
+
const planId = args.plan_id;
|
|
1313
|
+
if (!planId || typeof planId !== "string") {
|
|
1314
|
+
return JSON.stringify({ error: "plan_id is required and must be a string" });
|
|
1315
|
+
}
|
|
1316
|
+
if (/[\x00-\x1f\x7f]/.test(planId)) {
|
|
1317
|
+
return JSON.stringify({ error: "plan_id contains invalid control characters" });
|
|
1318
|
+
}
|
|
1319
|
+
const result = await api("PUT", "/api/plans/user/plan", { planId });
|
|
1320
|
+
return JSON.stringify(result);
|
|
1321
|
+
}
|
|
1322
|
+
// -----------------------------------------------------------------------
|
|
1323
|
+
// Teams extended
|
|
1324
|
+
// -----------------------------------------------------------------------
|
|
1325
|
+
async function handleTeamDelete(args) {
|
|
1326
|
+
const teamId = args.team_id;
|
|
1327
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1328
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1329
|
+
}
|
|
1330
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1332
|
+
}
|
|
1333
|
+
const result = await api("DELETE", `/api/teams/${encodeURIComponent(teamId)}`);
|
|
1334
|
+
return JSON.stringify(result);
|
|
1335
|
+
}
|
|
1336
|
+
async function handleTeamRevokeKey(args) {
|
|
1337
|
+
const teamId = args.team_id;
|
|
1338
|
+
const keyId = args.key_id;
|
|
1339
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1340
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1341
|
+
}
|
|
1342
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1344
|
+
}
|
|
1345
|
+
if (!keyId || typeof keyId !== "string") {
|
|
1346
|
+
return JSON.stringify({ error: "key_id is required and must be a string" });
|
|
1347
|
+
}
|
|
1348
|
+
if (/[\x00-\x1f\x7f]/.test(keyId)) {
|
|
1349
|
+
return JSON.stringify({ error: "key_id contains invalid control characters" });
|
|
1350
|
+
}
|
|
1351
|
+
const result = await api("DELETE", `/api/teams/${encodeURIComponent(teamId)}/keys/${encodeURIComponent(keyId)}`);
|
|
1352
|
+
return JSON.stringify(result);
|
|
1353
|
+
}
|
|
1354
|
+
async function handleTeamListKeys(args) {
|
|
1355
|
+
const teamId = args.team_id;
|
|
1356
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1357
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1358
|
+
}
|
|
1359
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1361
|
+
}
|
|
1362
|
+
const result = await api("GET", `/api/teams/${encodeURIComponent(teamId)}/keys`);
|
|
1363
|
+
return JSON.stringify(result);
|
|
1364
|
+
}
|
|
1365
|
+
async function handleTeamListMembers(args) {
|
|
1366
|
+
const teamId = args.team_id;
|
|
1367
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1368
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1369
|
+
}
|
|
1370
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1372
|
+
}
|
|
1373
|
+
const result = await api("GET", `/api/teams/${encodeURIComponent(teamId)}/members`);
|
|
1374
|
+
return JSON.stringify(result);
|
|
1375
|
+
}
|
|
1376
|
+
async function handleTeamAddMember(args) {
|
|
1377
|
+
const teamId = args.team_id;
|
|
1378
|
+
const userId = args.user_id;
|
|
1379
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1380
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1381
|
+
}
|
|
1382
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1384
|
+
}
|
|
1385
|
+
if (!userId || typeof userId !== "string") {
|
|
1386
|
+
return JSON.stringify({ error: "user_id is required and must be a string" });
|
|
1387
|
+
}
|
|
1388
|
+
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
|
+
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
1390
|
+
}
|
|
1391
|
+
const result = await api("POST", `/api/teams/${encodeURIComponent(teamId)}/members`, { userId });
|
|
1392
|
+
return JSON.stringify(result);
|
|
1393
|
+
}
|
|
1394
|
+
async function handleTeamRemoveMember(args) {
|
|
1395
|
+
const teamId = args.team_id;
|
|
1396
|
+
const userId = args.user_id;
|
|
1397
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1398
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1399
|
+
}
|
|
1400
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1402
|
+
}
|
|
1403
|
+
if (!userId || typeof userId !== "string") {
|
|
1404
|
+
return JSON.stringify({ error: "user_id is required and must be a string" });
|
|
1405
|
+
}
|
|
1406
|
+
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
|
+
return JSON.stringify({ error: "user_id must be a valid UUID" });
|
|
1408
|
+
}
|
|
1409
|
+
const result = await api("DELETE", `/api/teams/${encodeURIComponent(teamId)}/members/${encodeURIComponent(userId)}`);
|
|
1410
|
+
return JSON.stringify(result);
|
|
1411
|
+
}
|
|
1412
|
+
async function handleTeamInviteMember(args) {
|
|
1413
|
+
const teamId = args.team_id;
|
|
1414
|
+
const email = args.email;
|
|
1415
|
+
const role = args.role ?? "member";
|
|
1416
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1417
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1418
|
+
}
|
|
1419
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1421
|
+
}
|
|
1422
|
+
if (!email || typeof email !== "string") {
|
|
1423
|
+
return JSON.stringify({ error: "email is required and must be a string" });
|
|
1424
|
+
}
|
|
1425
|
+
if (!/^[^@]+@[^@]+\.[^@]+$/.test(email)) {
|
|
1426
|
+
return JSON.stringify({ error: "email must be a valid email address" });
|
|
1427
|
+
}
|
|
1428
|
+
if (/[\x00-\x1f\x7f]/.test(email)) {
|
|
1429
|
+
return JSON.stringify({ error: "email contains invalid control characters" });
|
|
1430
|
+
}
|
|
1431
|
+
if (role !== "member" && role !== "admin") {
|
|
1432
|
+
return JSON.stringify({ error: "role must be 'member' or 'admin'" });
|
|
1433
|
+
}
|
|
1434
|
+
const result = await api("POST", `/api/teams/${encodeURIComponent(teamId)}/invites`, { email, role });
|
|
1435
|
+
return JSON.stringify(result);
|
|
1436
|
+
}
|
|
1437
|
+
async function handleTeamListInvites(args) {
|
|
1438
|
+
const teamId = args.team_id;
|
|
1439
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1440
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1441
|
+
}
|
|
1442
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1444
|
+
}
|
|
1445
|
+
const result = await api("GET", `/api/teams/${encodeURIComponent(teamId)}/invites`);
|
|
1446
|
+
return JSON.stringify(result);
|
|
1447
|
+
}
|
|
1448
|
+
async function handleTeamCancelInvite(args) {
|
|
1449
|
+
const teamId = args.team_id;
|
|
1450
|
+
const inviteId = args.invite_id;
|
|
1451
|
+
if (!teamId || typeof teamId !== "string") {
|
|
1452
|
+
return JSON.stringify({ error: "team_id is required and must be a string" });
|
|
1453
|
+
}
|
|
1454
|
+
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
|
+
return JSON.stringify({ error: "team_id must be a valid UUID" });
|
|
1456
|
+
}
|
|
1457
|
+
if (!inviteId || typeof inviteId !== "string") {
|
|
1458
|
+
return JSON.stringify({ error: "invite_id is required and must be a string" });
|
|
1459
|
+
}
|
|
1460
|
+
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
|
+
return JSON.stringify({ error: "invite_id must be a valid UUID" });
|
|
1462
|
+
}
|
|
1463
|
+
const result = await api("DELETE", `/api/teams/${encodeURIComponent(teamId)}/invites/${encodeURIComponent(inviteId)}`);
|
|
1464
|
+
return JSON.stringify(result);
|
|
1465
|
+
}
|
|
956
1466
|
// -----------------------------------------------------------------------
|
|
957
1467
|
// Dispatch table
|
|
958
1468
|
// -----------------------------------------------------------------------
|
|
@@ -961,6 +1471,7 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
961
1471
|
dominusnode_check_balance: handleCheckBalance,
|
|
962
1472
|
dominusnode_check_usage: handleCheckUsage,
|
|
963
1473
|
dominusnode_get_proxy_config: handleGetProxyConfig,
|
|
1474
|
+
dominusnode_get_proxy_status: handleGetProxyStatus,
|
|
964
1475
|
dominusnode_list_sessions: handleListSessions,
|
|
965
1476
|
dominusnode_create_agentic_wallet: handleCreateAgenticWallet,
|
|
966
1477
|
dominusnode_fund_agentic_wallet: handleFundAgenticWallet,
|
|
@@ -970,6 +1481,23 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
970
1481
|
dominusnode_freeze_agentic_wallet: handleFreezeAgenticWallet,
|
|
971
1482
|
dominusnode_unfreeze_agentic_wallet: handleUnfreezeAgenticWallet,
|
|
972
1483
|
dominusnode_delete_agentic_wallet: handleDeleteAgenticWallet,
|
|
1484
|
+
dominusnode_get_transactions: handleGetTransactions,
|
|
1485
|
+
dominusnode_get_forecast: handleGetForecast,
|
|
1486
|
+
dominusnode_check_payment: handleCheckPayment,
|
|
1487
|
+
dominusnode_get_daily_usage: handleGetDailyUsage,
|
|
1488
|
+
dominusnode_get_top_hosts: handleGetTopHosts,
|
|
1489
|
+
dominusnode_register: handleRegister,
|
|
1490
|
+
dominusnode_login: handleLogin,
|
|
1491
|
+
dominusnode_get_account_info: handleGetAccountInfo,
|
|
1492
|
+
dominusnode_verify_email: handleVerifyEmail,
|
|
1493
|
+
dominusnode_resend_verification: handleResendVerification,
|
|
1494
|
+
dominusnode_update_password: handleUpdatePassword,
|
|
1495
|
+
dominusnode_list_keys: handleListKeys,
|
|
1496
|
+
dominusnode_create_key: handleCreateKey,
|
|
1497
|
+
dominusnode_revoke_key: handleRevokeKey,
|
|
1498
|
+
dominusnode_get_plan: handleGetPlan,
|
|
1499
|
+
dominusnode_list_plans: handleListPlans,
|
|
1500
|
+
dominusnode_change_plan: handleChangePlan,
|
|
973
1501
|
dominusnode_create_team: handleCreateTeam,
|
|
974
1502
|
dominusnode_list_teams: handleListTeams,
|
|
975
1503
|
dominusnode_team_details: handleTeamDetails,
|
|
@@ -978,7 +1506,18 @@ export function createDominusNodeFunctionHandler(config) {
|
|
|
978
1506
|
dominusnode_team_usage: handleTeamUsage,
|
|
979
1507
|
dominusnode_update_team: handleUpdateTeam,
|
|
980
1508
|
dominusnode_update_team_member_role: handleUpdateTeamMemberRole,
|
|
1509
|
+
dominusnode_team_delete: handleTeamDelete,
|
|
1510
|
+
dominusnode_team_revoke_key: handleTeamRevokeKey,
|
|
1511
|
+
dominusnode_team_list_keys: handleTeamListKeys,
|
|
1512
|
+
dominusnode_team_list_members: handleTeamListMembers,
|
|
1513
|
+
dominusnode_team_add_member: handleTeamAddMember,
|
|
1514
|
+
dominusnode_team_remove_member: handleTeamRemoveMember,
|
|
1515
|
+
dominusnode_team_invite_member: handleTeamInviteMember,
|
|
1516
|
+
dominusnode_team_list_invites: handleTeamListInvites,
|
|
1517
|
+
dominusnode_team_cancel_invite: handleTeamCancelInvite,
|
|
981
1518
|
dominusnode_topup_paypal: handleTopupPaypal,
|
|
1519
|
+
dominusnode_topup_stripe: handleTopupStripe,
|
|
1520
|
+
dominusnode_topup_crypto: handleTopupCrypto,
|
|
982
1521
|
dominusnode_x402_info: handleX402Info,
|
|
983
1522
|
dominusnode_update_wallet_policy: handleUpdateWalletPolicy,
|
|
984
1523
|
};
|
package/functions.json
CHANGED
|
@@ -362,16 +362,48 @@
|
|
|
362
362
|
},
|
|
363
363
|
{
|
|
364
364
|
"name": "dominusnode_topup_paypal",
|
|
365
|
-
"description": "Create a PayPal wallet top-up session. Initiates a PayPal payment for the specified amount to add funds to your Dominus Node wallet. Returns a PayPal approval URL to complete the payment.",
|
|
365
|
+
"description": "Create a PayPal wallet top-up session. Initiates a PayPal payment for the specified amount to add funds to your Dominus Node wallet. Returns a PayPal approval URL to complete the payment. Minimum $5 (500 cents), maximum $1,000 (100000 cents).",
|
|
366
366
|
"parameters": {
|
|
367
367
|
"type": "OBJECT",
|
|
368
368
|
"properties": {
|
|
369
369
|
"amount_cents": {
|
|
370
370
|
"type": "INTEGER",
|
|
371
|
-
"description": "Amount to top up in cents. Must be
|
|
371
|
+
"description": "Amount to top up in cents. Must be an integer between 500 ($5) and 100000 ($1,000). Example: 1000 = $10.00."
|
|
372
372
|
}
|
|
373
373
|
},
|
|
374
374
|
"required": ["amount_cents"]
|
|
375
375
|
}
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"name": "dominusnode_topup_stripe",
|
|
379
|
+
"description": "Create a Stripe wallet top-up checkout session. Initiates a Stripe payment for the specified amount to add funds to your Dominus Node wallet. Returns a Stripe checkout URL to complete the payment. Minimum $5 (500 cents), maximum $1,000 (100000 cents).",
|
|
380
|
+
"parameters": {
|
|
381
|
+
"type": "OBJECT",
|
|
382
|
+
"properties": {
|
|
383
|
+
"amount_cents": {
|
|
384
|
+
"type": "INTEGER",
|
|
385
|
+
"description": "Amount to top up in cents. Must be an integer between 500 ($5) and 100000 ($1,000). Example: 1000 = $10.00."
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
"required": ["amount_cents"]
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "dominusnode_topup_crypto",
|
|
393
|
+
"description": "Create a cryptocurrency wallet top-up invoice. Initiates a crypto payment for the specified amount to add funds to your Dominus Node wallet. Returns payment address and amount. Minimum $5, maximum $1,000. Supported currencies: BTC, ETH, LTC, XMR, ZEC, USDC, SOL, USDT, DAI, BNB, LINK.",
|
|
394
|
+
"parameters": {
|
|
395
|
+
"type": "OBJECT",
|
|
396
|
+
"properties": {
|
|
397
|
+
"amount_usd": {
|
|
398
|
+
"type": "NUMBER",
|
|
399
|
+
"description": "Amount to top up in USD. Must be between 5 and 1000."
|
|
400
|
+
},
|
|
401
|
+
"currency": {
|
|
402
|
+
"type": "STRING",
|
|
403
|
+
"description": "Cryptocurrency to pay with. One of: btc, eth, ltc, xmr, zec, usdc, sol, usdt, dai, bnb, link."
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
"required": ["amount_usd", "currency"]
|
|
407
|
+
}
|
|
376
408
|
}
|
|
377
409
|
]
|
package/package.json
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dominusnode/gemini-functions",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"files": [
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"functions.json",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
9
14
|
"scripts": {
|
|
10
15
|
"build": "tsc",
|
|
11
16
|
"test": "vitest run",
|
|
12
17
|
"test:watch": "vitest",
|
|
13
18
|
"test:py": "python -m pytest test_handler.py -v"
|
|
14
19
|
},
|
|
15
|
-
"keywords": [
|
|
20
|
+
"keywords": [
|
|
21
|
+
"dominusnode",
|
|
22
|
+
"gemini",
|
|
23
|
+
"vertex-ai",
|
|
24
|
+
"proxy",
|
|
25
|
+
"function-calling"
|
|
26
|
+
],
|
|
16
27
|
"license": "MIT",
|
|
17
28
|
"repository": {
|
|
18
29
|
"type": "git",
|