n8n-nodes-dominusnode 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/CHANGELOG.md +1 -0
- package/README.md +13 -10
- package/dist/credentials/DominusNodeApi.credentials.js +1 -1
- package/dist/nodes/DominusNodeAccount/DominusNodeAccount.node.js +132 -9
- package/dist/nodes/DominusNodeAccount/DominusNodeAccount.node.js.map +1 -1
- package/dist/nodes/DominusNodeKeys/DominusNodeKeys.node.js +21 -4
- package/dist/nodes/DominusNodeKeys/DominusNodeKeys.node.js.map +1 -1
- package/dist/nodes/DominusNodePlans/DominusNodePlans.node.js +24 -5
- package/dist/nodes/DominusNodePlans/DominusNodePlans.node.js.map +1 -1
- package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js +21 -8
- package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js.map +1 -1
- package/dist/nodes/DominusNodeTeams/DominusNodeTeams.node.js +63 -12
- package/dist/nodes/DominusNodeTeams/DominusNodeTeams.node.js.map +1 -1
- package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js.map +1 -1
- package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js +320 -40
- package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js.map +1 -1
- package/dist/shared/auth.js +1 -1
- package/dist/shared/auth.js.map +1 -1
- package/dist/shared/ssrf.js.map +1 -1
- package/package.json +2 -1
- package/src/credentials/DominusNodeApi.credentials.ts +0 -48
- package/src/index.ts +0 -8
- package/src/nodes/DominusNodeAccount/DominusNodeAccount.node.ts +0 -283
- package/src/nodes/DominusNodeKeys/DominusNodeKeys.node.ts +0 -192
- package/src/nodes/DominusNodePlans/DominusNodePlans.node.ts +0 -154
- package/src/nodes/DominusNodeProxy/DominusNodeProxy.node.ts +0 -470
- package/src/nodes/DominusNodeTeams/DominusNodeTeams.node.ts +0 -351
- package/src/nodes/DominusNodeUsage/DominusNodeUsage.node.ts +0 -183
- package/src/nodes/DominusNodeWallet/DominusNodeWallet.node.ts +0 -950
- package/src/shared/auth.ts +0 -287
- package/src/shared/constants.ts +0 -11
- package/src/shared/ssrf.ts +0 -257
- package/tests/DominusNodeProxy.test.ts +0 -281
- package/tests/DominusNodeUsage.test.ts +0 -250
- package/tests/DominusNodeWallet.test.ts +0 -591
- package/tests/ssrf.test.ts +0 -238
- package/tsconfig.json +0 -18
- package/vitest.config.ts +0 -8
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dominus Node Teams n8n community node.
|
|
3
|
-
*
|
|
4
|
-
* Operations (9 tools):
|
|
5
|
-
* - Delete Team: Delete a team
|
|
6
|
-
* - Revoke Team Key: Revoke a team API key
|
|
7
|
-
* - List Team Keys: List all API keys for a team
|
|
8
|
-
* - List Team Members: List all members of a team
|
|
9
|
-
* - Add Team Member: Add a user to a team
|
|
10
|
-
* - Remove Team Member: Remove a user from a team
|
|
11
|
-
* - Invite Team Member: Send an email invitation to join a team
|
|
12
|
-
* - List Team Invites: List pending invitations for a team
|
|
13
|
-
* - Cancel Team Invite: Cancel a pending team invitation
|
|
14
|
-
*
|
|
15
|
-
* Security:
|
|
16
|
-
* - UUID validation for team/user/key/invite IDs
|
|
17
|
-
* - Email validation for invitations
|
|
18
|
-
* - Control character rejection
|
|
19
|
-
* - Credential sanitization in error messages
|
|
20
|
-
*
|
|
21
|
-
* @module
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
IDataObject,
|
|
26
|
-
IExecuteFunctions,
|
|
27
|
-
INodeExecutionData,
|
|
28
|
-
INodeType,
|
|
29
|
-
INodeTypeDescription,
|
|
30
|
-
NodeOperationError,
|
|
31
|
-
} from "n8n-workflow";
|
|
32
|
-
|
|
33
|
-
import { DominusNodeAuth, sanitizeError } from "../../shared/auth";
|
|
34
|
-
|
|
35
|
-
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
36
|
-
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
37
|
-
|
|
38
|
-
export class DominusNodeTeams implements INodeType {
|
|
39
|
-
description: INodeTypeDescription = {
|
|
40
|
-
displayName: "Dominus Node Teams",
|
|
41
|
-
name: "dominusNodeTeams",
|
|
42
|
-
icon: "file:dominusnode.svg",
|
|
43
|
-
group: ["transform"],
|
|
44
|
-
version: 1,
|
|
45
|
-
subtitle: '={{$parameter["operation"]}}',
|
|
46
|
-
description: "Manage Dominus Node team members, keys, and invitations",
|
|
47
|
-
defaults: { name: "Dominus Node Teams" },
|
|
48
|
-
inputs: ["main"],
|
|
49
|
-
outputs: ["main"],
|
|
50
|
-
credentials: [{ name: "dominusNodeApi", required: true }],
|
|
51
|
-
properties: [
|
|
52
|
-
{
|
|
53
|
-
displayName: "Operation",
|
|
54
|
-
name: "operation",
|
|
55
|
-
type: "options",
|
|
56
|
-
noDataExpression: true,
|
|
57
|
-
options: [
|
|
58
|
-
{ name: "Delete Team", value: "teamDelete", description: "Delete a team", action: "Delete team" },
|
|
59
|
-
{ name: "Revoke Team Key", value: "teamRevokeKey", description: "Revoke a team API key", action: "Revoke team key" },
|
|
60
|
-
{ name: "List Team Keys", value: "teamListKeys", description: "List all API keys for a team", action: "List team keys" },
|
|
61
|
-
{ name: "List Team Members", value: "teamListMembers", description: "List all members of a team", action: "List team members" },
|
|
62
|
-
{ name: "Add Team Member", value: "teamAddMember", description: "Add a user to a team", action: "Add team member" },
|
|
63
|
-
{ name: "Remove Team Member", value: "teamRemoveMember", description: "Remove a user from a team", action: "Remove team member" },
|
|
64
|
-
{ name: "Invite Team Member", value: "teamInviteMember", description: "Send an email invitation to join a team", action: "Invite team member" },
|
|
65
|
-
{ name: "List Team Invites", value: "teamListInvites", description: "List pending invitations for a team", action: "List team invites" },
|
|
66
|
-
{ name: "Cancel Team Invite", value: "teamCancelInvite", description: "Cancel a pending team invitation", action: "Cancel team invite" },
|
|
67
|
-
],
|
|
68
|
-
default: "teamListMembers",
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
// --- Team ID (shared) ---
|
|
72
|
-
{
|
|
73
|
-
displayName: "Team ID",
|
|
74
|
-
name: "teamId",
|
|
75
|
-
type: "string",
|
|
76
|
-
default: "",
|
|
77
|
-
required: true,
|
|
78
|
-
description: "Team UUID",
|
|
79
|
-
displayOptions: {
|
|
80
|
-
show: {
|
|
81
|
-
operation: [
|
|
82
|
-
"teamDelete",
|
|
83
|
-
"teamRevokeKey",
|
|
84
|
-
"teamListKeys",
|
|
85
|
-
"teamListMembers",
|
|
86
|
-
"teamAddMember",
|
|
87
|
-
"teamRemoveMember",
|
|
88
|
-
"teamInviteMember",
|
|
89
|
-
"teamListInvites",
|
|
90
|
-
"teamCancelInvite",
|
|
91
|
-
],
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
// --- Key ID for revoke ---
|
|
97
|
-
{
|
|
98
|
-
displayName: "Key ID",
|
|
99
|
-
name: "keyId",
|
|
100
|
-
type: "string",
|
|
101
|
-
default: "",
|
|
102
|
-
required: true,
|
|
103
|
-
description: "UUID of the team API key to revoke",
|
|
104
|
-
displayOptions: { show: { operation: ["teamRevokeKey"] } },
|
|
105
|
-
},
|
|
106
|
-
|
|
107
|
-
// --- User ID for add/remove member ---
|
|
108
|
-
{
|
|
109
|
-
displayName: "User ID",
|
|
110
|
-
name: "userId",
|
|
111
|
-
type: "string",
|
|
112
|
-
default: "",
|
|
113
|
-
required: true,
|
|
114
|
-
description: "UUID of the user to add or remove",
|
|
115
|
-
displayOptions: { show: { operation: ["teamAddMember", "teamRemoveMember"] } },
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
// --- Role for add member / invite ---
|
|
119
|
-
{
|
|
120
|
-
displayName: "Role",
|
|
121
|
-
name: "role",
|
|
122
|
-
type: "options",
|
|
123
|
-
options: [
|
|
124
|
-
{ name: "Admin", value: "admin" },
|
|
125
|
-
{ name: "Member", value: "member" },
|
|
126
|
-
],
|
|
127
|
-
default: "member",
|
|
128
|
-
description: "Role for the team member",
|
|
129
|
-
displayOptions: { show: { operation: ["teamAddMember", "teamInviteMember"] } },
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
// --- Invite email ---
|
|
133
|
-
{
|
|
134
|
-
displayName: "Email",
|
|
135
|
-
name: "inviteEmail",
|
|
136
|
-
type: "string",
|
|
137
|
-
default: "",
|
|
138
|
-
required: true,
|
|
139
|
-
description: "Email address to send the invitation to",
|
|
140
|
-
displayOptions: { show: { operation: ["teamInviteMember"] } },
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// --- Invite ID for cancel ---
|
|
144
|
-
{
|
|
145
|
-
displayName: "Invite ID",
|
|
146
|
-
name: "inviteId",
|
|
147
|
-
type: "string",
|
|
148
|
-
default: "",
|
|
149
|
-
required: true,
|
|
150
|
-
description: "UUID of the invitation to cancel",
|
|
151
|
-
displayOptions: { show: { operation: ["teamCancelInvite"] } },
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
157
|
-
const items = this.getInputData();
|
|
158
|
-
const returnData: INodeExecutionData[] = [];
|
|
159
|
-
const credentials = await this.getCredentials("dominusNodeApi");
|
|
160
|
-
|
|
161
|
-
const apiKey = credentials.apiKey as string;
|
|
162
|
-
const baseUrl = (credentials.baseUrl as string) || "https://api.dominusnode.com";
|
|
163
|
-
|
|
164
|
-
if (!apiKey) {
|
|
165
|
-
throw new NodeOperationError(this.getNode(), "API Key is required");
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const agentSecret = (credentials.agentSecret as string) || undefined;
|
|
169
|
-
const auth = new DominusNodeAuth(apiKey, baseUrl, 30000, agentSecret);
|
|
170
|
-
const operation = this.getNodeParameter("operation", 0) as string;
|
|
171
|
-
|
|
172
|
-
for (let i = 0; i < items.length; i++) {
|
|
173
|
-
try {
|
|
174
|
-
let result: unknown;
|
|
175
|
-
|
|
176
|
-
// All operations require teamId
|
|
177
|
-
const teamId = this.getNodeParameter("teamId", i) as string;
|
|
178
|
-
validateUuid(this, teamId, "teamId", i);
|
|
179
|
-
|
|
180
|
-
switch (operation) {
|
|
181
|
-
case "teamDelete": {
|
|
182
|
-
result = await auth.apiRequest(
|
|
183
|
-
"DELETE",
|
|
184
|
-
`/api/teams/${encodeURIComponent(teamId)}`,
|
|
185
|
-
);
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
case "teamRevokeKey": {
|
|
190
|
-
const keyId = this.getNodeParameter("keyId", i) as string;
|
|
191
|
-
validateUuid(this, keyId, "keyId", i);
|
|
192
|
-
result = await auth.apiRequest(
|
|
193
|
-
"DELETE",
|
|
194
|
-
`/api/teams/${encodeURIComponent(teamId)}/keys/${encodeURIComponent(keyId)}`,
|
|
195
|
-
);
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
case "teamListKeys": {
|
|
200
|
-
result = await auth.apiRequest(
|
|
201
|
-
"GET",
|
|
202
|
-
`/api/teams/${encodeURIComponent(teamId)}/keys`,
|
|
203
|
-
);
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
case "teamListMembers": {
|
|
208
|
-
result = await auth.apiRequest(
|
|
209
|
-
"GET",
|
|
210
|
-
`/api/teams/${encodeURIComponent(teamId)}/members`,
|
|
211
|
-
);
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
case "teamAddMember": {
|
|
216
|
-
const userId = this.getNodeParameter("userId", i) as string;
|
|
217
|
-
const role = this.getNodeParameter("role", i, "member") as string;
|
|
218
|
-
validateUuid(this, userId, "userId", i);
|
|
219
|
-
if (role !== "member" && role !== "admin") {
|
|
220
|
-
throw new NodeOperationError(
|
|
221
|
-
this.getNode(),
|
|
222
|
-
"Role must be 'member' or 'admin'",
|
|
223
|
-
{ itemIndex: i },
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
result = await auth.apiRequest(
|
|
227
|
-
"POST",
|
|
228
|
-
`/api/teams/${encodeURIComponent(teamId)}/members`,
|
|
229
|
-
{ userId, role },
|
|
230
|
-
);
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
case "teamRemoveMember": {
|
|
235
|
-
const userId = this.getNodeParameter("userId", i) as string;
|
|
236
|
-
validateUuid(this, userId, "userId", i);
|
|
237
|
-
result = await auth.apiRequest(
|
|
238
|
-
"DELETE",
|
|
239
|
-
`/api/teams/${encodeURIComponent(teamId)}/members/${encodeURIComponent(userId)}`,
|
|
240
|
-
);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
case "teamInviteMember": {
|
|
245
|
-
const email = this.getNodeParameter("inviteEmail", i) as string;
|
|
246
|
-
const role = this.getNodeParameter("role", i, "member") as string;
|
|
247
|
-
const safeEmail = validateEmail(this, email, i);
|
|
248
|
-
if (role !== "member" && role !== "admin") {
|
|
249
|
-
throw new NodeOperationError(
|
|
250
|
-
this.getNode(),
|
|
251
|
-
"Role must be 'member' or 'admin'",
|
|
252
|
-
{ itemIndex: i },
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
result = await auth.apiRequest(
|
|
256
|
-
"POST",
|
|
257
|
-
`/api/teams/${encodeURIComponent(teamId)}/invites`,
|
|
258
|
-
{ email: safeEmail, role },
|
|
259
|
-
);
|
|
260
|
-
break;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
case "teamListInvites": {
|
|
264
|
-
result = await auth.apiRequest(
|
|
265
|
-
"GET",
|
|
266
|
-
`/api/teams/${encodeURIComponent(teamId)}/invites`,
|
|
267
|
-
);
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
case "teamCancelInvite": {
|
|
272
|
-
const inviteId = this.getNodeParameter("inviteId", i) as string;
|
|
273
|
-
validateUuid(this, inviteId, "inviteId", i);
|
|
274
|
-
result = await auth.apiRequest(
|
|
275
|
-
"DELETE",
|
|
276
|
-
`/api/teams/${encodeURIComponent(teamId)}/invites/${encodeURIComponent(inviteId)}`,
|
|
277
|
-
);
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
default:
|
|
282
|
-
throw new NodeOperationError(
|
|
283
|
-
this.getNode(),
|
|
284
|
-
`Unknown operation: ${operation}`,
|
|
285
|
-
{ itemIndex: i },
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
returnData.push({ json: (result ?? {}) as IDataObject });
|
|
290
|
-
} catch (err) {
|
|
291
|
-
if (this.continueOnFail()) {
|
|
292
|
-
returnData.push({
|
|
293
|
-
json: {
|
|
294
|
-
error: sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
295
|
-
},
|
|
296
|
-
});
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
if (err instanceof NodeOperationError) throw err;
|
|
300
|
-
throw new NodeOperationError(
|
|
301
|
-
this.getNode(),
|
|
302
|
-
sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
303
|
-
{ itemIndex: i },
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return [returnData];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// ---------------------------------------------------------------------------
|
|
313
|
-
// Validation helpers
|
|
314
|
-
// ---------------------------------------------------------------------------
|
|
315
|
-
|
|
316
|
-
function validateUuid(
|
|
317
|
-
ctx: IExecuteFunctions,
|
|
318
|
-
value: string,
|
|
319
|
-
fieldName: string,
|
|
320
|
-
itemIndex: number,
|
|
321
|
-
): void {
|
|
322
|
-
if (!value || typeof value !== "string") {
|
|
323
|
-
throw new NodeOperationError(ctx.getNode(), `${fieldName} is required`, { itemIndex });
|
|
324
|
-
}
|
|
325
|
-
if (!UUID_RE.test(value)) {
|
|
326
|
-
throw new NodeOperationError(ctx.getNode(), `${fieldName} must be a valid UUID`, { itemIndex });
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
function validateEmail(
|
|
331
|
-
ctx: IExecuteFunctions,
|
|
332
|
-
email: string,
|
|
333
|
-
itemIndex: number,
|
|
334
|
-
): string {
|
|
335
|
-
const trimmed = (email ?? "").trim();
|
|
336
|
-
if (!trimmed || !EMAIL_RE.test(trimmed)) {
|
|
337
|
-
throw new NodeOperationError(
|
|
338
|
-
ctx.getNode(),
|
|
339
|
-
"A valid email address is required",
|
|
340
|
-
{ itemIndex },
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
if (trimmed.length > 254) {
|
|
344
|
-
throw new NodeOperationError(
|
|
345
|
-
ctx.getNode(),
|
|
346
|
-
"Email address too long (max 254 characters)",
|
|
347
|
-
{ itemIndex },
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
return trimmed;
|
|
351
|
-
}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dominus Node Usage n8n community node.
|
|
3
|
-
*
|
|
4
|
-
* Operations (3 tools):
|
|
5
|
-
* - Check Usage: Get proxy usage statistics for a given period
|
|
6
|
-
* - Get Daily Usage: Get daily usage breakdown for the last N days
|
|
7
|
-
* - Get Top Hosts: Get top accessed hosts by bandwidth
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
IDataObject,
|
|
14
|
-
IExecuteFunctions,
|
|
15
|
-
INodeExecutionData,
|
|
16
|
-
INodeType,
|
|
17
|
-
INodeTypeDescription,
|
|
18
|
-
NodeOperationError,
|
|
19
|
-
} from "n8n-workflow";
|
|
20
|
-
|
|
21
|
-
import { DominusNodeAuth, sanitizeError, periodToDateRange } from "../../shared/auth";
|
|
22
|
-
|
|
23
|
-
const VALID_PERIODS = new Set(["day", "week", "month"]);
|
|
24
|
-
|
|
25
|
-
export class DominusNodeUsage implements INodeType {
|
|
26
|
-
description: INodeTypeDescription = {
|
|
27
|
-
displayName: "Dominus Node Usage",
|
|
28
|
-
name: "dominusNodeUsage",
|
|
29
|
-
icon: "file:dominusnode.svg",
|
|
30
|
-
group: ["transform"],
|
|
31
|
-
version: 1,
|
|
32
|
-
subtitle: '={{$parameter["operation"]}}',
|
|
33
|
-
description: "Check Dominus Node proxy usage statistics",
|
|
34
|
-
defaults: { name: "Dominus Node Usage" },
|
|
35
|
-
inputs: ["main"],
|
|
36
|
-
outputs: ["main"],
|
|
37
|
-
credentials: [{ name: "dominusNodeApi", required: true }],
|
|
38
|
-
properties: [
|
|
39
|
-
{
|
|
40
|
-
displayName: "Operation",
|
|
41
|
-
name: "operation",
|
|
42
|
-
type: "options",
|
|
43
|
-
noDataExpression: true,
|
|
44
|
-
options: [
|
|
45
|
-
{
|
|
46
|
-
name: "Check Usage",
|
|
47
|
-
value: "checkUsage",
|
|
48
|
-
description: "Get proxy usage statistics for a given period",
|
|
49
|
-
action: "Check usage",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: "Get Daily Usage",
|
|
53
|
-
value: "getDailyUsage",
|
|
54
|
-
description: "Get daily usage breakdown for the last N days",
|
|
55
|
-
action: "Get daily usage",
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: "Get Top Hosts",
|
|
59
|
-
value: "getTopHosts",
|
|
60
|
-
description: "Get top accessed hosts by bandwidth",
|
|
61
|
-
action: "Get top hosts",
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
default: "checkUsage",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
displayName: "Period",
|
|
68
|
-
name: "period",
|
|
69
|
-
type: "options",
|
|
70
|
-
options: [
|
|
71
|
-
{ name: "Day", value: "day" },
|
|
72
|
-
{ name: "Week", value: "week" },
|
|
73
|
-
{ name: "Month", value: "month" },
|
|
74
|
-
],
|
|
75
|
-
default: "month",
|
|
76
|
-
description: "Time period for usage statistics",
|
|
77
|
-
displayOptions: { show: { operation: ["checkUsage"] } },
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
displayName: "Days",
|
|
81
|
-
name: "days",
|
|
82
|
-
type: "number",
|
|
83
|
-
default: 7,
|
|
84
|
-
description: "Number of days of daily usage to return (1-365)",
|
|
85
|
-
displayOptions: { show: { operation: ["getDailyUsage"] } },
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
displayName: "Limit",
|
|
89
|
-
name: "topHostsLimit",
|
|
90
|
-
type: "number",
|
|
91
|
-
default: 10,
|
|
92
|
-
description: "Number of top hosts to return (1-100)",
|
|
93
|
-
displayOptions: { show: { operation: ["getTopHosts"] } },
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
99
|
-
const items = this.getInputData();
|
|
100
|
-
const returnData: INodeExecutionData[] = [];
|
|
101
|
-
const credentials = await this.getCredentials("dominusNodeApi");
|
|
102
|
-
|
|
103
|
-
const apiKey = credentials.apiKey as string;
|
|
104
|
-
const baseUrl = (credentials.baseUrl as string) || "https://api.dominusnode.com";
|
|
105
|
-
|
|
106
|
-
if (!apiKey) {
|
|
107
|
-
throw new NodeOperationError(this.getNode(), "API Key is required");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const agentSecret = (credentials.agentSecret as string) || undefined;
|
|
111
|
-
const auth = new DominusNodeAuth(apiKey, baseUrl, 30000, agentSecret);
|
|
112
|
-
|
|
113
|
-
for (let i = 0; i < items.length; i++) {
|
|
114
|
-
try {
|
|
115
|
-
const operation = this.getNodeParameter("operation", i) as string;
|
|
116
|
-
|
|
117
|
-
if (operation === "checkUsage") {
|
|
118
|
-
const period = this.getNodeParameter("period", i, "month") as string;
|
|
119
|
-
|
|
120
|
-
if (!VALID_PERIODS.has(period)) {
|
|
121
|
-
throw new NodeOperationError(
|
|
122
|
-
this.getNode(),
|
|
123
|
-
`Invalid period '${period}'. Must be one of: day, week, month`,
|
|
124
|
-
{ itemIndex: i },
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Backend expects since/until ISO dates, NOT a days integer
|
|
129
|
-
const { since, until } = periodToDateRange(period);
|
|
130
|
-
const params = new URLSearchParams({ since, until });
|
|
131
|
-
const result = await auth.apiRequest("GET", `/api/usage?${params.toString()}`);
|
|
132
|
-
|
|
133
|
-
returnData.push({ json: (result ?? {}) as IDataObject });
|
|
134
|
-
} else if (operation === "getDailyUsage") {
|
|
135
|
-
const days = this.getNodeParameter("days", i, 7) as number;
|
|
136
|
-
if (!Number.isInteger(days) || days < 1 || days > 365) {
|
|
137
|
-
throw new NodeOperationError(
|
|
138
|
-
this.getNode(),
|
|
139
|
-
"Days must be an integer between 1 and 365",
|
|
140
|
-
{ itemIndex: i },
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
const result = await auth.apiRequest("GET", `/api/usage/daily?days=${days}`);
|
|
144
|
-
returnData.push({ json: (result ?? {}) as IDataObject });
|
|
145
|
-
} else if (operation === "getTopHosts") {
|
|
146
|
-
const limit = this.getNodeParameter("topHostsLimit", i, 10) as number;
|
|
147
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
148
|
-
throw new NodeOperationError(
|
|
149
|
-
this.getNode(),
|
|
150
|
-
"Limit must be an integer between 1 and 100",
|
|
151
|
-
{ itemIndex: i },
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
const result = await auth.apiRequest("GET", `/api/usage/top-hosts?limit=${limit}`);
|
|
155
|
-
returnData.push({ json: (result ?? {}) as IDataObject });
|
|
156
|
-
} else {
|
|
157
|
-
throw new NodeOperationError(
|
|
158
|
-
this.getNode(),
|
|
159
|
-
`Unknown operation: ${operation}`,
|
|
160
|
-
{ itemIndex: i },
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
} catch (err) {
|
|
164
|
-
if (this.continueOnFail()) {
|
|
165
|
-
returnData.push({
|
|
166
|
-
json: {
|
|
167
|
-
error: sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (err instanceof NodeOperationError) throw err;
|
|
173
|
-
throw new NodeOperationError(
|
|
174
|
-
this.getNode(),
|
|
175
|
-
sanitizeError(err instanceof Error ? err.message : String(err)),
|
|
176
|
-
{ itemIndex: i },
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return [returnData];
|
|
182
|
-
}
|
|
183
|
-
}
|