n8n-nodes-dominusnode 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.
Files changed (43) hide show
  1. package/dist/credentials/DominusNodeApi.credentials.js +8 -0
  2. package/dist/credentials/DominusNodeApi.credentials.js.map +1 -1
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.js +9 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/nodes/DominusNodeAccount/DominusNodeAccount.node.d.ts +23 -0
  7. package/dist/nodes/DominusNodeAccount/DominusNodeAccount.node.js +223 -0
  8. package/dist/nodes/DominusNodeAccount/DominusNodeAccount.node.js.map +1 -0
  9. package/dist/nodes/DominusNodeKeys/DominusNodeKeys.node.d.ts +20 -0
  10. package/dist/nodes/DominusNodeKeys/DominusNodeKeys.node.js +145 -0
  11. package/dist/nodes/DominusNodeKeys/DominusNodeKeys.node.js.map +1 -0
  12. package/dist/nodes/DominusNodePlans/DominusNodePlans.node.d.ts +19 -0
  13. package/dist/nodes/DominusNodePlans/DominusNodePlans.node.js +123 -0
  14. package/dist/nodes/DominusNodePlans/DominusNodePlans.node.js.map +1 -0
  15. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.d.ts +2 -1
  16. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js +14 -2
  17. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js.map +1 -1
  18. package/dist/nodes/DominusNodeTeams/DominusNodeTeams.node.d.ts +27 -0
  19. package/dist/nodes/DominusNodeTeams/DominusNodeTeams.node.js +258 -0
  20. package/dist/nodes/DominusNodeTeams/DominusNodeTeams.node.js.map +1 -0
  21. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.d.ts +3 -1
  22. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js +49 -2
  23. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js.map +1 -1
  24. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.d.ts +5 -1
  25. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js +46 -2
  26. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js.map +1 -1
  27. package/dist/shared/auth.d.ts +2 -1
  28. package/dist/shared/auth.js +16 -5
  29. package/dist/shared/auth.js.map +1 -1
  30. package/package.json +7 -3
  31. package/src/credentials/DominusNodeApi.credentials.ts +9 -0
  32. package/src/index.ts +4 -0
  33. package/src/nodes/DominusNodeAccount/DominusNodeAccount.node.ts +283 -0
  34. package/src/nodes/DominusNodeKeys/DominusNodeKeys.node.ts +192 -0
  35. package/src/nodes/DominusNodePlans/DominusNodePlans.node.ts +154 -0
  36. package/src/nodes/DominusNodeProxy/DominusNodeProxy.node.ts +13 -2
  37. package/src/nodes/DominusNodeTeams/DominusNodeTeams.node.ts +351 -0
  38. package/src/nodes/DominusNodeUsage/DominusNodeUsage.node.ts +55 -2
  39. package/src/nodes/DominusNodeWallet/DominusNodeWallet.node.ts +54 -2
  40. package/src/shared/auth.ts +19 -4
  41. package/tests/DominusNodeProxy.test.ts +2 -2
  42. package/tests/DominusNodeUsage.test.ts +2 -2
  43. package/tests/DominusNodeWallet.test.ts +2 -2
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Dominus Node Keys n8n community node.
3
+ *
4
+ * Operations (3 tools):
5
+ * - List Keys: List all API keys
6
+ * - Create Key: Create a new API key
7
+ * - Revoke Key: Revoke an existing API key
8
+ *
9
+ * Security:
10
+ * - UUID validation for key IDs
11
+ * - Control character rejection in labels
12
+ * - Credential sanitization in error messages
13
+ *
14
+ * @module
15
+ */
16
+
17
+ import {
18
+ IDataObject,
19
+ IExecuteFunctions,
20
+ INodeExecutionData,
21
+ INodeType,
22
+ INodeTypeDescription,
23
+ NodeOperationError,
24
+ } from "n8n-workflow";
25
+
26
+ import { DominusNodeAuth, sanitizeError } from "../../shared/auth";
27
+
28
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
29
+ const CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/;
30
+
31
+ export class DominusNodeKeys implements INodeType {
32
+ description: INodeTypeDescription = {
33
+ displayName: "Dominus Node Keys",
34
+ name: "dominusNodeKeys",
35
+ icon: "file:dominusnode.svg",
36
+ group: ["transform"],
37
+ version: 1,
38
+ subtitle: '={{$parameter["operation"]}}',
39
+ description: "Manage Dominus Node API keys",
40
+ defaults: { name: "Dominus Node Keys" },
41
+ inputs: ["main"],
42
+ outputs: ["main"],
43
+ credentials: [{ name: "dominusNodeApi", required: true }],
44
+ properties: [
45
+ {
46
+ displayName: "Operation",
47
+ name: "operation",
48
+ type: "options",
49
+ noDataExpression: true,
50
+ options: [
51
+ { name: "List Keys", value: "listKeys", description: "List all API keys", action: "List keys" },
52
+ { name: "Create Key", value: "createKey", description: "Create a new API key", action: "Create key" },
53
+ { name: "Revoke Key", value: "revokeKey", description: "Revoke an existing API key", action: "Revoke key" },
54
+ ],
55
+ default: "listKeys",
56
+ },
57
+
58
+ // --- Create Key ---
59
+ {
60
+ displayName: "Label",
61
+ name: "keyLabel",
62
+ type: "string",
63
+ default: "",
64
+ required: true,
65
+ description: "Label for the new API key (max 100 chars)",
66
+ displayOptions: { show: { operation: ["createKey"] } },
67
+ },
68
+
69
+ // --- Revoke Key ---
70
+ {
71
+ displayName: "Key ID",
72
+ name: "keyId",
73
+ type: "string",
74
+ default: "",
75
+ required: true,
76
+ description: "UUID of the API key to revoke",
77
+ displayOptions: { show: { operation: ["revokeKey"] } },
78
+ },
79
+ ],
80
+ };
81
+
82
+ async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
83
+ const items = this.getInputData();
84
+ const returnData: INodeExecutionData[] = [];
85
+ const credentials = await this.getCredentials("dominusNodeApi");
86
+
87
+ const apiKey = credentials.apiKey as string;
88
+ const baseUrl = (credentials.baseUrl as string) || "https://api.dominusnode.com";
89
+
90
+ if (!apiKey) {
91
+ throw new NodeOperationError(this.getNode(), "API Key is required");
92
+ }
93
+
94
+ const agentSecret = (credentials.agentSecret as string) || undefined;
95
+ const auth = new DominusNodeAuth(apiKey, baseUrl, 30000, agentSecret);
96
+ const operation = this.getNodeParameter("operation", 0) as string;
97
+
98
+ for (let i = 0; i < items.length; i++) {
99
+ try {
100
+ let result: unknown;
101
+
102
+ switch (operation) {
103
+ case "listKeys": {
104
+ result = await auth.apiRequest("GET", "/api/keys");
105
+ break;
106
+ }
107
+
108
+ case "createKey": {
109
+ const label = this.getNodeParameter("keyLabel", i) as string;
110
+ if (!label || typeof label !== "string" || label.length === 0) {
111
+ throw new NodeOperationError(
112
+ this.getNode(),
113
+ "Key label is required",
114
+ { itemIndex: i },
115
+ );
116
+ }
117
+ if (label.length > 100) {
118
+ throw new NodeOperationError(
119
+ this.getNode(),
120
+ "Key label must be 100 characters or fewer",
121
+ { itemIndex: i },
122
+ );
123
+ }
124
+ if (CONTROL_CHAR_RE.test(label)) {
125
+ throw new NodeOperationError(
126
+ this.getNode(),
127
+ "Key label contains invalid control characters",
128
+ { itemIndex: i },
129
+ );
130
+ }
131
+ result = await auth.apiRequest("POST", "/api/keys", { label });
132
+ break;
133
+ }
134
+
135
+ case "revokeKey": {
136
+ const keyId = this.getNodeParameter("keyId", i) as string;
137
+ validateUuid(this, keyId, "keyId", i);
138
+ result = await auth.apiRequest(
139
+ "DELETE",
140
+ `/api/keys/${encodeURIComponent(keyId)}`,
141
+ );
142
+ break;
143
+ }
144
+
145
+ default:
146
+ throw new NodeOperationError(
147
+ this.getNode(),
148
+ `Unknown operation: ${operation}`,
149
+ { itemIndex: i },
150
+ );
151
+ }
152
+
153
+ returnData.push({ json: (result ?? {}) as IDataObject });
154
+ } catch (err) {
155
+ if (this.continueOnFail()) {
156
+ returnData.push({
157
+ json: {
158
+ error: sanitizeError(err instanceof Error ? err.message : String(err)),
159
+ },
160
+ });
161
+ continue;
162
+ }
163
+ if (err instanceof NodeOperationError) throw err;
164
+ throw new NodeOperationError(
165
+ this.getNode(),
166
+ sanitizeError(err instanceof Error ? err.message : String(err)),
167
+ { itemIndex: i },
168
+ );
169
+ }
170
+ }
171
+
172
+ return [returnData];
173
+ }
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Validation helpers
178
+ // ---------------------------------------------------------------------------
179
+
180
+ function validateUuid(
181
+ ctx: IExecuteFunctions,
182
+ value: string,
183
+ fieldName: string,
184
+ itemIndex: number,
185
+ ): void {
186
+ if (!value || typeof value !== "string") {
187
+ throw new NodeOperationError(ctx.getNode(), `${fieldName} is required`, { itemIndex });
188
+ }
189
+ if (!UUID_RE.test(value)) {
190
+ throw new NodeOperationError(ctx.getNode(), `${fieldName} must be a valid UUID`, { itemIndex });
191
+ }
192
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Dominus Node Plans n8n community node.
3
+ *
4
+ * Operations (3 tools):
5
+ * - Get Plan: Get current user plan
6
+ * - List Plans: List all available plans
7
+ * - Change Plan: Switch to a different plan
8
+ *
9
+ * Security:
10
+ * - UUID validation for plan IDs
11
+ * - Credential sanitization in error messages
12
+ *
13
+ * @module
14
+ */
15
+
16
+ import {
17
+ IDataObject,
18
+ IExecuteFunctions,
19
+ INodeExecutionData,
20
+ INodeType,
21
+ INodeTypeDescription,
22
+ NodeOperationError,
23
+ } from "n8n-workflow";
24
+
25
+ import { DominusNodeAuth, sanitizeError } from "../../shared/auth";
26
+
27
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
28
+
29
+ export class DominusNodePlans implements INodeType {
30
+ description: INodeTypeDescription = {
31
+ displayName: "Dominus Node Plans",
32
+ name: "dominusNodePlans",
33
+ icon: "file:dominusnode.svg",
34
+ group: ["transform"],
35
+ version: 1,
36
+ subtitle: '={{$parameter["operation"]}}',
37
+ description: "Manage Dominus Node subscription plans",
38
+ defaults: { name: "Dominus Node Plans" },
39
+ inputs: ["main"],
40
+ outputs: ["main"],
41
+ credentials: [{ name: "dominusNodeApi", required: true }],
42
+ properties: [
43
+ {
44
+ displayName: "Operation",
45
+ name: "operation",
46
+ type: "options",
47
+ noDataExpression: true,
48
+ options: [
49
+ { name: "Get Plan", value: "getPlan", description: "Get current user plan", action: "Get plan" },
50
+ { name: "List Plans", value: "listPlans", description: "List all available plans", action: "List plans" },
51
+ { name: "Change Plan", value: "changePlan", description: "Switch to a different plan", action: "Change plan" },
52
+ ],
53
+ default: "getPlan",
54
+ },
55
+
56
+ // --- Change Plan ---
57
+ {
58
+ displayName: "Plan ID",
59
+ name: "planId",
60
+ type: "string",
61
+ default: "",
62
+ required: true,
63
+ description: "UUID of the plan to switch to",
64
+ displayOptions: { show: { operation: ["changePlan"] } },
65
+ },
66
+ ],
67
+ };
68
+
69
+ async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
70
+ const items = this.getInputData();
71
+ const returnData: INodeExecutionData[] = [];
72
+ const credentials = await this.getCredentials("dominusNodeApi");
73
+
74
+ const apiKey = credentials.apiKey as string;
75
+ const baseUrl = (credentials.baseUrl as string) || "https://api.dominusnode.com";
76
+
77
+ if (!apiKey) {
78
+ throw new NodeOperationError(this.getNode(), "API Key is required");
79
+ }
80
+
81
+ const agentSecret = (credentials.agentSecret as string) || undefined;
82
+ const auth = new DominusNodeAuth(apiKey, baseUrl, 30000, agentSecret);
83
+ const operation = this.getNodeParameter("operation", 0) as string;
84
+
85
+ for (let i = 0; i < items.length; i++) {
86
+ try {
87
+ let result: unknown;
88
+
89
+ switch (operation) {
90
+ case "getPlan": {
91
+ result = await auth.apiRequest("GET", "/api/plans/user/plan");
92
+ break;
93
+ }
94
+
95
+ case "listPlans": {
96
+ result = await auth.apiRequest("GET", "/api/plans");
97
+ break;
98
+ }
99
+
100
+ case "changePlan": {
101
+ const planId = this.getNodeParameter("planId", i) as string;
102
+ validateUuid(this, planId, "planId", i);
103
+ result = await auth.apiRequest("PUT", "/api/plans/user/plan", { planId });
104
+ break;
105
+ }
106
+
107
+ default:
108
+ throw new NodeOperationError(
109
+ this.getNode(),
110
+ `Unknown operation: ${operation}`,
111
+ { itemIndex: i },
112
+ );
113
+ }
114
+
115
+ returnData.push({ json: (result ?? {}) as IDataObject });
116
+ } catch (err) {
117
+ if (this.continueOnFail()) {
118
+ returnData.push({
119
+ json: {
120
+ error: sanitizeError(err instanceof Error ? err.message : String(err)),
121
+ },
122
+ });
123
+ continue;
124
+ }
125
+ if (err instanceof NodeOperationError) throw err;
126
+ throw new NodeOperationError(
127
+ this.getNode(),
128
+ sanitizeError(err instanceof Error ? err.message : String(err)),
129
+ { itemIndex: i },
130
+ );
131
+ }
132
+ }
133
+
134
+ return [returnData];
135
+ }
136
+ }
137
+
138
+ // ---------------------------------------------------------------------------
139
+ // Validation helpers
140
+ // ---------------------------------------------------------------------------
141
+
142
+ function validateUuid(
143
+ ctx: IExecuteFunctions,
144
+ value: string,
145
+ fieldName: string,
146
+ itemIndex: number,
147
+ ): void {
148
+ if (!value || typeof value !== "string") {
149
+ throw new NodeOperationError(ctx.getNode(), `${fieldName} is required`, { itemIndex });
150
+ }
151
+ if (!UUID_RE.test(value)) {
152
+ throw new NodeOperationError(ctx.getNode(), `${fieldName} must be a valid UUID`, { itemIndex });
153
+ }
154
+ }
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Dominus Node Proxy n8n community node.
3
3
  *
4
- * Operations:
4
+ * Operations (4 tools):
5
5
  * - Proxied Fetch: Make HTTP requests through Dominus Node's rotating proxy network
6
6
  * - Get Proxy Config: Retrieve proxy endpoint configuration
7
7
  * - List Active Sessions: List currently active proxy sessions
8
+ * - Get Proxy Status: Get proxy pool health and availability status
8
9
  *
9
10
  * Security:
10
11
  * - Full SSRF prevention (private IPs, hex/octal/decimal, IPv6 variants,
@@ -86,6 +87,12 @@ export class DominusNodeProxy implements INodeType {
86
87
  description: "List currently active proxy sessions",
87
88
  action: "List active sessions",
88
89
  },
90
+ {
91
+ name: "Get Proxy Status",
92
+ value: "getProxyStatus",
93
+ description: "Get proxy pool health and availability status",
94
+ action: "Get proxy status",
95
+ },
89
96
  ],
90
97
  default: "proxiedFetch",
91
98
  },
@@ -179,7 +186,8 @@ export class DominusNodeProxy implements INodeType {
179
186
  throw new NodeOperationError(this.getNode(), "API Key is required");
180
187
  }
181
188
 
182
- const auth = new DominusNodeAuth(apiKey, baseUrl);
189
+ const agentSecret = (credentials.agentSecret as string) || undefined;
190
+ const auth = new DominusNodeAuth(apiKey, baseUrl, 30000, agentSecret);
183
191
  const operation = this.getNodeParameter("operation", 0) as string;
184
192
 
185
193
  for (let i = 0; i < items.length; i++) {
@@ -436,6 +444,9 @@ export class DominusNodeProxy implements INodeType {
436
444
  } else if (operation === "listActiveSessions") {
437
445
  const result = await auth.apiRequest("GET", "/api/sessions/active");
438
446
  returnData.push({ json: result as IDataObject });
447
+ } else if (operation === "getProxyStatus") {
448
+ const result = await auth.apiRequest("GET", "/api/proxy/status");
449
+ returnData.push({ json: result as IDataObject });
439
450
  }
440
451
  } catch (err) {
441
452
  if (this.continueOnFail()) {