n8n-nodes-dominusnode 1.0.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 (42) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +99 -0
  4. package/dist/credentials/DominusNodeApi.credentials.d.ts +7 -0
  5. package/dist/credentials/DominusNodeApi.credentials.js +42 -0
  6. package/dist/credentials/DominusNodeApi.credentials.js.map +1 -0
  7. package/dist/index.d.ts +4 -0
  8. package/dist/index.js +12 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.d.ts +24 -0
  11. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js +436 -0
  12. package/dist/nodes/DominusNodeProxy/DominusNodeProxy.node.js.map +1 -0
  13. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.d.ts +13 -0
  14. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js +105 -0
  15. package/dist/nodes/DominusNodeUsage/DominusNodeUsage.node.js.map +1 -0
  16. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.d.ts +33 -0
  17. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js +656 -0
  18. package/dist/nodes/DominusNodeWallet/DominusNodeWallet.node.js.map +1 -0
  19. package/dist/shared/auth.d.ts +74 -0
  20. package/dist/shared/auth.js +264 -0
  21. package/dist/shared/auth.js.map +1 -0
  22. package/dist/shared/constants.d.ts +9 -0
  23. package/dist/shared/constants.js +13 -0
  24. package/dist/shared/constants.js.map +1 -0
  25. package/dist/shared/ssrf.d.ts +42 -0
  26. package/dist/shared/ssrf.js +252 -0
  27. package/dist/shared/ssrf.js.map +1 -0
  28. package/package.json +41 -0
  29. package/src/credentials/DominusNodeApi.credentials.ts +39 -0
  30. package/src/index.ts +4 -0
  31. package/src/nodes/DominusNodeProxy/DominusNodeProxy.node.ts +459 -0
  32. package/src/nodes/DominusNodeUsage/DominusNodeUsage.node.ts +130 -0
  33. package/src/nodes/DominusNodeWallet/DominusNodeWallet.node.ts +898 -0
  34. package/src/shared/auth.ts +272 -0
  35. package/src/shared/constants.ts +11 -0
  36. package/src/shared/ssrf.ts +257 -0
  37. package/tests/DominusNodeProxy.test.ts +281 -0
  38. package/tests/DominusNodeUsage.test.ts +250 -0
  39. package/tests/DominusNodeWallet.test.ts +591 -0
  40. package/tests/ssrf.test.ts +238 -0
  41. package/tsconfig.json +18 -0
  42. package/vitest.config.ts +8 -0
@@ -0,0 +1,591 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Mock n8n-workflow
5
+ // ---------------------------------------------------------------------------
6
+
7
+ vi.mock("n8n-workflow", () => ({
8
+ NodeOperationError: class NodeOperationError extends Error {
9
+ constructor(node: unknown, message: string, extra?: unknown) {
10
+ super(message);
11
+ this.name = "NodeOperationError";
12
+ }
13
+ },
14
+ }));
15
+
16
+ import { DominusNodeWallet } from "../src/nodes/DominusNodeWallet/DominusNodeWallet.node";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Helpers — mock IExecuteFunctions
20
+ // ---------------------------------------------------------------------------
21
+
22
+ function createMockExecuteFunctions(overrides: {
23
+ operation: string;
24
+ params?: Record<string, unknown>;
25
+ credentials?: Record<string, unknown>;
26
+ continueOnFail?: boolean;
27
+ mockApiResponse?: unknown;
28
+ }) {
29
+ const params: Record<string, unknown> = {
30
+ operation: overrides.operation,
31
+ ...overrides.params,
32
+ };
33
+
34
+ const creds = {
35
+ apiKey: "dn_test_abc123",
36
+ baseUrl: "http://localhost:3000",
37
+ ...overrides.credentials,
38
+ };
39
+
40
+ return {
41
+ getInputData: () => [{ json: {} }],
42
+ getNodeParameter: (name: string, _index: number, fallback?: unknown) => {
43
+ return params[name] ?? fallback;
44
+ },
45
+ getCredentials: vi.fn().mockResolvedValue(creds),
46
+ getNode: () => ({ name: "DomiNode Wallet" }),
47
+ continueOnFail: () => overrides.continueOnFail ?? false,
48
+ };
49
+ }
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Mocked fetch for API calls
53
+ // ---------------------------------------------------------------------------
54
+
55
+ let originalFetch: typeof globalThis.fetch;
56
+
57
+ beforeEach(() => {
58
+ originalFetch = globalThis.fetch;
59
+ globalThis.fetch = vi.fn().mockImplementation((url: string) => {
60
+ if (typeof url === "string" && url.includes("/api/auth/verify-key")) {
61
+ return Promise.resolve({
62
+ ok: true,
63
+ status: 200,
64
+ text: () => Promise.resolve('{"token": "jwt-mock-token"}'),
65
+ headers: new Headers({ "content-length": "30" }),
66
+ });
67
+ }
68
+ // Default: mock API call success
69
+ return Promise.resolve({
70
+ ok: true,
71
+ status: 200,
72
+ text: () => Promise.resolve('{"success": true}'),
73
+ headers: new Headers({ "content-length": "20" }),
74
+ });
75
+ });
76
+ });
77
+
78
+ afterEach(() => {
79
+ globalThis.fetch = originalFetch;
80
+ });
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Tests
84
+ // ---------------------------------------------------------------------------
85
+
86
+ describe("DominusNodeWallet - metadata", () => {
87
+ it("has correct description metadata", () => {
88
+ const node = new DominusNodeWallet();
89
+ expect(node.description.name).toBe("dominusNodeWallet");
90
+ expect(node.description.displayName).toBe("DomiNode Wallet");
91
+ expect(node.description.credentials).toEqual([
92
+ { name: "dominusNodeApi", required: true },
93
+ ]);
94
+ });
95
+
96
+ it("has 22 operations", () => {
97
+ const node = new DominusNodeWallet();
98
+ const opProp = node.description.properties.find((p) => p.name === "operation");
99
+ expect(opProp).toBeDefined();
100
+ expect((opProp as any).options).toHaveLength(22);
101
+ });
102
+ });
103
+
104
+ describe("DominusNodeWallet.execute - checkBalance", () => {
105
+ it("returns balance on success", async () => {
106
+ const node = new DominusNodeWallet();
107
+ const mockFns = createMockExecuteFunctions({ operation: "checkBalance" });
108
+
109
+ const result = await node.execute.call(mockFns as any);
110
+ expect(result[0]).toHaveLength(1);
111
+ expect(result[0][0].json).toHaveProperty("success", true);
112
+ });
113
+ });
114
+
115
+ describe("DominusNodeWallet.execute - topUpStripe validation", () => {
116
+ it("rejects amountCents below 100", async () => {
117
+ const node = new DominusNodeWallet();
118
+ const mockFns = createMockExecuteFunctions({
119
+ operation: "topUpStripe",
120
+ params: { amountCents: 50 },
121
+ });
122
+
123
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountCents/);
124
+ });
125
+
126
+ it("rejects amountCents above 1,000,000", async () => {
127
+ const node = new DominusNodeWallet();
128
+ const mockFns = createMockExecuteFunctions({
129
+ operation: "topUpStripe",
130
+ params: { amountCents: 1_000_001 },
131
+ });
132
+
133
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountCents/);
134
+ });
135
+
136
+ it("accepts valid amountCents", async () => {
137
+ const node = new DominusNodeWallet();
138
+ const mockFns = createMockExecuteFunctions({
139
+ operation: "topUpStripe",
140
+ params: { amountCents: 500 },
141
+ });
142
+
143
+ const result = await node.execute.call(mockFns as any);
144
+ expect(result[0][0].json).toHaveProperty("success", true);
145
+ });
146
+ });
147
+
148
+ describe("DominusNodeWallet.execute - topUpCrypto validation", () => {
149
+ it("rejects amountUsd below $5", async () => {
150
+ const node = new DominusNodeWallet();
151
+ const mockFns = createMockExecuteFunctions({
152
+ operation: "topUpCrypto",
153
+ params: { amountUsd: 3, currency: "btc" },
154
+ });
155
+
156
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountUsd/);
157
+ });
158
+
159
+ it("rejects invalid cryptocurrency", async () => {
160
+ const node = new DominusNodeWallet();
161
+ const mockFns = createMockExecuteFunctions({
162
+ operation: "topUpCrypto",
163
+ params: { amountUsd: 10, currency: "doge" },
164
+ });
165
+
166
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Invalid currency/);
167
+ });
168
+
169
+ it("accepts valid crypto top-up", async () => {
170
+ const node = new DominusNodeWallet();
171
+ const mockFns = createMockExecuteFunctions({
172
+ operation: "topUpCrypto",
173
+ params: { amountUsd: 10, currency: "eth" },
174
+ });
175
+
176
+ const result = await node.execute.call(mockFns as any);
177
+ expect(result[0][0].json).toHaveProperty("success", true);
178
+ });
179
+ });
180
+
181
+ describe("DominusNodeWallet.execute - topUpPaypal validation", () => {
182
+ it("rejects amountCents below 100", async () => {
183
+ const node = new DominusNodeWallet();
184
+ const mockFns = createMockExecuteFunctions({
185
+ operation: "topUpPaypal",
186
+ params: { amountCents: 50 },
187
+ });
188
+
189
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountCents/);
190
+ });
191
+
192
+ it("accepts valid PayPal top-up", async () => {
193
+ const node = new DominusNodeWallet();
194
+ const mockFns = createMockExecuteFunctions({
195
+ operation: "topUpPaypal",
196
+ params: { amountCents: 1000 },
197
+ });
198
+
199
+ const result = await node.execute.call(mockFns as any);
200
+ expect(result[0][0].json).toHaveProperty("success", true);
201
+ });
202
+ });
203
+
204
+ describe("DominusNodeWallet.execute - agentic wallet validation", () => {
205
+ it("createAgenticWallet rejects missing label", async () => {
206
+ const node = new DominusNodeWallet();
207
+ const mockFns = createMockExecuteFunctions({
208
+ operation: "createAgenticWallet",
209
+ params: { agenticLabel: "", spendingLimitCents: 100 },
210
+ });
211
+
212
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Label is required/);
213
+ });
214
+
215
+ it("createAgenticWallet rejects label over 100 chars", async () => {
216
+ const node = new DominusNodeWallet();
217
+ const mockFns = createMockExecuteFunctions({
218
+ operation: "createAgenticWallet",
219
+ params: { agenticLabel: "a".repeat(101), spendingLimitCents: 100 },
220
+ });
221
+
222
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/100 characters/);
223
+ });
224
+
225
+ it("createAgenticWallet rejects control characters in label", async () => {
226
+ const node = new DominusNodeWallet();
227
+ const mockFns = createMockExecuteFunctions({
228
+ operation: "createAgenticWallet",
229
+ params: { agenticLabel: "test\x00label", spendingLimitCents: 100 },
230
+ });
231
+
232
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/control characters/);
233
+ });
234
+
235
+ it("createAgenticWallet rejects invalid spending limit", async () => {
236
+ const node = new DominusNodeWallet();
237
+ const mockFns = createMockExecuteFunctions({
238
+ operation: "createAgenticWallet",
239
+ params: { agenticLabel: "test", spendingLimitCents: -5 },
240
+ });
241
+
242
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/positive integer/);
243
+ });
244
+
245
+ it("fundAgenticWallet rejects invalid UUID", async () => {
246
+ const node = new DominusNodeWallet();
247
+ const mockFns = createMockExecuteFunctions({
248
+ operation: "fundAgenticWallet",
249
+ params: { walletId: "not-a-uuid", fundAmountCents: 100 },
250
+ });
251
+
252
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/valid UUID/);
253
+ });
254
+
255
+ it("fundAgenticWallet rejects negative amount", async () => {
256
+ const node = new DominusNodeWallet();
257
+ const mockFns = createMockExecuteFunctions({
258
+ operation: "fundAgenticWallet",
259
+ params: {
260
+ walletId: "550e8400-e29b-41d4-a716-446655440000",
261
+ fundAmountCents: -100,
262
+ },
263
+ });
264
+
265
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/positive integer/);
266
+ });
267
+ });
268
+
269
+ describe("DominusNodeWallet.execute - team validation", () => {
270
+ it("createTeam rejects missing name", async () => {
271
+ const node = new DominusNodeWallet();
272
+ const mockFns = createMockExecuteFunctions({
273
+ operation: "createTeam",
274
+ params: { teamName: "", maxMembers: 10 },
275
+ });
276
+
277
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Team name is required/);
278
+ });
279
+
280
+ it("createTeam rejects name over 100 chars", async () => {
281
+ const node = new DominusNodeWallet();
282
+ const mockFns = createMockExecuteFunctions({
283
+ operation: "createTeam",
284
+ params: { teamName: "a".repeat(101), maxMembers: 10 },
285
+ });
286
+
287
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/100 characters/);
288
+ });
289
+
290
+ it("createTeam rejects control chars in name", async () => {
291
+ const node = new DominusNodeWallet();
292
+ const mockFns = createMockExecuteFunctions({
293
+ operation: "createTeam",
294
+ params: { teamName: "team\x07name", maxMembers: 10 },
295
+ });
296
+
297
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/control characters/);
298
+ });
299
+
300
+ it("fundTeam rejects amount below 100", async () => {
301
+ const node = new DominusNodeWallet();
302
+ const mockFns = createMockExecuteFunctions({
303
+ operation: "fundTeam",
304
+ params: {
305
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
306
+ teamFundAmountCents: 50,
307
+ },
308
+ });
309
+
310
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountCents/);
311
+ });
312
+
313
+ it("fundTeam rejects amount above 1,000,000", async () => {
314
+ const node = new DominusNodeWallet();
315
+ const mockFns = createMockExecuteFunctions({
316
+ operation: "fundTeam",
317
+ params: {
318
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
319
+ teamFundAmountCents: 1_000_001,
320
+ },
321
+ });
322
+
323
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/amountCents/);
324
+ });
325
+
326
+ it("createTeamKey rejects missing label", async () => {
327
+ const node = new DominusNodeWallet();
328
+ const mockFns = createMockExecuteFunctions({
329
+ operation: "createTeamKey",
330
+ params: {
331
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
332
+ keyLabel: "",
333
+ },
334
+ });
335
+
336
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Key label is required/);
337
+ });
338
+
339
+ it("createTeamKey rejects control chars in label", async () => {
340
+ const node = new DominusNodeWallet();
341
+ const mockFns = createMockExecuteFunctions({
342
+ operation: "createTeamKey",
343
+ params: {
344
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
345
+ keyLabel: "key\x01label",
346
+ },
347
+ });
348
+
349
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/control characters/);
350
+ });
351
+
352
+ it("updateTeam rejects when no fields provided", async () => {
353
+ const node = new DominusNodeWallet();
354
+ const mockFns = createMockExecuteFunctions({
355
+ operation: "updateTeam",
356
+ params: {
357
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
358
+ updateTeamName: "",
359
+ updateMaxMembers: 0,
360
+ },
361
+ });
362
+
363
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/At least one/);
364
+ });
365
+
366
+ it("updateTeamMemberRole rejects invalid role", async () => {
367
+ const node = new DominusNodeWallet();
368
+ const mockFns = createMockExecuteFunctions({
369
+ operation: "updateTeamMemberRole",
370
+ params: {
371
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
372
+ userId: "660e8400-e29b-41d4-a716-446655440000",
373
+ role: "owner",
374
+ },
375
+ });
376
+
377
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/member.*admin/);
378
+ });
379
+
380
+ it("updateTeamMemberRole rejects invalid userId UUID", async () => {
381
+ const node = new DominusNodeWallet();
382
+ const mockFns = createMockExecuteFunctions({
383
+ operation: "updateTeamMemberRole",
384
+ params: {
385
+ teamId: "550e8400-e29b-41d4-a716-446655440000",
386
+ userId: "not-a-uuid",
387
+ role: "admin",
388
+ },
389
+ });
390
+
391
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/valid UUID/);
392
+ });
393
+ });
394
+
395
+ describe("DominusNodeWallet.execute - createAgenticWallet with policy fields", () => {
396
+ it("accepts dailyLimitCents in create", async () => {
397
+ const node = new DominusNodeWallet();
398
+ const mockFns = createMockExecuteFunctions({
399
+ operation: "createAgenticWallet",
400
+ params: {
401
+ agenticLabel: "test-wallet",
402
+ spendingLimitCents: 5000,
403
+ dailyLimitCents: 10000,
404
+ allowedDomains: "",
405
+ },
406
+ });
407
+
408
+ const result = await node.execute.call(mockFns as any);
409
+ expect(result[0][0].json).toHaveProperty("success", true);
410
+ });
411
+
412
+ it("accepts allowedDomains in create", async () => {
413
+ const node = new DominusNodeWallet();
414
+ const mockFns = createMockExecuteFunctions({
415
+ operation: "createAgenticWallet",
416
+ params: {
417
+ agenticLabel: "test-wallet",
418
+ spendingLimitCents: 5000,
419
+ dailyLimitCents: 0,
420
+ allowedDomains: "example.com,api.example.org",
421
+ },
422
+ });
423
+
424
+ const result = await node.execute.call(mockFns as any);
425
+ expect(result[0][0].json).toHaveProperty("success", true);
426
+ });
427
+
428
+ it("rejects dailyLimitCents above 1,000,000", async () => {
429
+ const node = new DominusNodeWallet();
430
+ const mockFns = createMockExecuteFunctions({
431
+ operation: "createAgenticWallet",
432
+ params: {
433
+ agenticLabel: "test-wallet",
434
+ spendingLimitCents: 5000,
435
+ dailyLimitCents: 1_000_001,
436
+ allowedDomains: "",
437
+ },
438
+ });
439
+
440
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/dailyLimitCents/);
441
+ });
442
+
443
+ it("rejects more than 100 allowed domains", async () => {
444
+ const node = new DominusNodeWallet();
445
+ const domains = Array.from({ length: 101 }, (_, i) => `d${i}.example.com`).join(",");
446
+ const mockFns = createMockExecuteFunctions({
447
+ operation: "createAgenticWallet",
448
+ params: {
449
+ agenticLabel: "test-wallet",
450
+ spendingLimitCents: 5000,
451
+ dailyLimitCents: 0,
452
+ allowedDomains: domains,
453
+ },
454
+ });
455
+
456
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/at most 100/);
457
+ });
458
+
459
+ it("rejects invalid domain format", async () => {
460
+ const node = new DominusNodeWallet();
461
+ const mockFns = createMockExecuteFunctions({
462
+ operation: "createAgenticWallet",
463
+ params: {
464
+ agenticLabel: "test-wallet",
465
+ spendingLimitCents: 5000,
466
+ dailyLimitCents: 0,
467
+ allowedDomains: "not a valid domain!",
468
+ },
469
+ });
470
+
471
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Invalid domain/);
472
+ });
473
+ });
474
+
475
+ describe("DominusNodeWallet.execute - updateWalletPolicy", () => {
476
+ it("accepts valid dailyLimitCents", async () => {
477
+ const node = new DominusNodeWallet();
478
+ const mockFns = createMockExecuteFunctions({
479
+ operation: "updateWalletPolicy",
480
+ params: {
481
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
482
+ policyDailyLimitCents: 50000,
483
+ policyAllowedDomains: "",
484
+ },
485
+ });
486
+
487
+ const result = await node.execute.call(mockFns as any);
488
+ expect(result[0][0].json).toHaveProperty("success", true);
489
+ });
490
+
491
+ it("accepts allowedDomains", async () => {
492
+ const node = new DominusNodeWallet();
493
+ const mockFns = createMockExecuteFunctions({
494
+ operation: "updateWalletPolicy",
495
+ params: {
496
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
497
+ policyDailyLimitCents: 0,
498
+ policyAllowedDomains: "example.com,test.org",
499
+ },
500
+ });
501
+
502
+ const result = await node.execute.call(mockFns as any);
503
+ expect(result[0][0].json).toHaveProperty("success", true);
504
+ });
505
+
506
+ it("accepts null dailyLimitCents via -1", async () => {
507
+ const node = new DominusNodeWallet();
508
+ const mockFns = createMockExecuteFunctions({
509
+ operation: "updateWalletPolicy",
510
+ params: {
511
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
512
+ policyDailyLimitCents: -1,
513
+ policyAllowedDomains: "",
514
+ },
515
+ });
516
+
517
+ const result = await node.execute.call(mockFns as any);
518
+ expect(result[0][0].json).toHaveProperty("success", true);
519
+ });
520
+
521
+ it("accepts null allowedDomains via '*'", async () => {
522
+ const node = new DominusNodeWallet();
523
+ const mockFns = createMockExecuteFunctions({
524
+ operation: "updateWalletPolicy",
525
+ params: {
526
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
527
+ policyDailyLimitCents: 0,
528
+ policyAllowedDomains: "*",
529
+ },
530
+ });
531
+
532
+ const result = await node.execute.call(mockFns as any);
533
+ expect(result[0][0].json).toHaveProperty("success", true);
534
+ });
535
+
536
+ it("rejects invalid walletId UUID", async () => {
537
+ const node = new DominusNodeWallet();
538
+ const mockFns = createMockExecuteFunctions({
539
+ operation: "updateWalletPolicy",
540
+ params: {
541
+ policyWalletId: "not-a-uuid",
542
+ policyDailyLimitCents: 5000,
543
+ policyAllowedDomains: "",
544
+ },
545
+ });
546
+
547
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/valid UUID/);
548
+ });
549
+
550
+ it("rejects when no fields provided", async () => {
551
+ const node = new DominusNodeWallet();
552
+ const mockFns = createMockExecuteFunctions({
553
+ operation: "updateWalletPolicy",
554
+ params: {
555
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
556
+ policyDailyLimitCents: 0,
557
+ policyAllowedDomains: "",
558
+ },
559
+ });
560
+
561
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/At least one/);
562
+ });
563
+
564
+ it("rejects dailyLimitCents above 1,000,000", async () => {
565
+ const node = new DominusNodeWallet();
566
+ const mockFns = createMockExecuteFunctions({
567
+ operation: "updateWalletPolicy",
568
+ params: {
569
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
570
+ policyDailyLimitCents: 1_000_001,
571
+ policyAllowedDomains: "",
572
+ },
573
+ });
574
+
575
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/dailyLimitCents/);
576
+ });
577
+
578
+ it("rejects invalid domain in allowedDomains", async () => {
579
+ const node = new DominusNodeWallet();
580
+ const mockFns = createMockExecuteFunctions({
581
+ operation: "updateWalletPolicy",
582
+ params: {
583
+ policyWalletId: "550e8400-e29b-41d4-a716-446655440000",
584
+ policyDailyLimitCents: 0,
585
+ policyAllowedDomains: "valid.com,inv@lid!",
586
+ },
587
+ });
588
+
589
+ await expect(node.execute.call(mockFns as any)).rejects.toThrow(/Invalid domain/);
590
+ });
591
+ });