@tadnt2003/n8n-nodes-infisical 0.2.0 → 0.3.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.
@@ -2,22 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Infisical = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
- async function getInfisicalToken(helpers, credentials) {
6
- const apiUrl = credentials.apiUrl.replace(/\/$/, '');
7
- const authType = credentials.authType || 'serviceToken';
8
- if (authType === 'universalAuth') {
9
- const clientId = credentials.clientId;
10
- const clientSecret = credentials.clientSecret;
11
- const tokenResponse = await helpers.httpRequest({
12
- method: 'POST',
13
- url: `${apiUrl}/v1/auth/universal-auth/login`,
14
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
15
- body: `clientId=${encodeURIComponent(clientId)}&clientSecret=${encodeURIComponent(clientSecret)}`,
16
- });
17
- return { apiUrl, accessToken: tokenResponse.accessToken };
18
- }
19
- return { apiUrl, accessToken: credentials.apiKey };
20
- }
5
+ const secretOperations_1 = require("../../utils/secretOperations");
6
+ const projectOperations_1 = require("../../utils/projectOperations");
7
+ const folderOperations_1 = require("../../utils/folderOperations");
8
+ const auth_1 = require("../../utils/auth");
21
9
  class Infisical {
22
10
  constructor() {
23
11
  this.description = {
@@ -48,8 +36,9 @@ class Infisical {
48
36
  type: 'options',
49
37
  noDataExpression: true,
50
38
  options: [
39
+ { name: 'Folder', value: 'folder' },
40
+ { name: 'Project', value: 'project' },
51
41
  { name: 'Secret', value: 'secret' },
52
- { name: 'Workspace', value: 'workspace' },
53
42
  ],
54
43
  default: 'secret',
55
44
  },
@@ -79,6 +68,12 @@ class Infisical {
79
68
  description: 'Delete a secret',
80
69
  action: 'Delete a secret',
81
70
  },
71
+ {
72
+ name: 'Delete Many',
73
+ value: 'deleteMany',
74
+ description: 'Delete multiple secrets in one request',
75
+ action: 'Delete many secrets',
76
+ },
82
77
  {
83
78
  name: 'Get',
84
79
  value: 'get',
@@ -106,32 +101,375 @@ class Infisical {
106
101
  ],
107
102
  default: 'get',
108
103
  },
109
- // ─── Workspace operations ────────────────────────────────────────────────
104
+ // ─── Project operations ────────────────────────────────────────────────
110
105
  {
111
106
  displayName: 'Operation',
112
107
  name: 'operation',
113
108
  type: 'options',
114
109
  noDataExpression: true,
115
- displayOptions: { show: { resource: ['workspace'] } },
110
+ displayOptions: { show: { resource: ['project'] } },
116
111
  options: [
112
+ {
113
+ name: 'Get',
114
+ value: 'get',
115
+ description: 'Get a project by ID',
116
+ action: 'Get a project',
117
+ },
118
+ {
119
+ name: 'Get By Slug',
120
+ value: 'getBySlug',
121
+ description: 'Get a project by slug',
122
+ action: 'Get a project by slug',
123
+ },
117
124
  {
118
125
  name: 'Get Many',
119
126
  value: 'getAll',
120
- description: 'List all accessible workspaces',
121
- action: 'Get many workspaces',
127
+ description: 'List all accessible projects',
128
+ action: 'Get many projects',
129
+ },
130
+ {
131
+ name: 'Get Secret Snapshots',
132
+ value: 'getSecretSnapshots',
133
+ description: 'List secret snapshots for a project environment',
134
+ action: 'Get secret snapshots',
135
+ },
136
+ {
137
+ name: 'Get User By Username',
138
+ value: 'getUserByUsername',
139
+ description: 'Get a project member by username',
140
+ action: 'Get user by username',
141
+ },
142
+ {
143
+ name: 'Get User Memberships',
144
+ value: 'getUserMemberships',
145
+ description: 'List all user memberships in a project',
146
+ action: 'Get user memberships',
122
147
  },
123
148
  ],
124
149
  default: 'getAll',
125
150
  },
151
+ // ─── Project fields ───────────────────────────────
152
+ {
153
+ displayName: 'Project ID',
154
+ name: 'projectId',
155
+ type: 'string',
156
+ required: true,
157
+ displayOptions: {
158
+ show: {
159
+ resource: ['project'],
160
+ operation: ['get', 'getSecretSnapshots', 'getUserMemberships', 'getUserByUsername'],
161
+ },
162
+ },
163
+ default: '',
164
+ description: 'The ID of the Infisical project',
165
+ },
166
+ {
167
+ displayName: 'Slug',
168
+ name: 'slug',
169
+ type: 'string',
170
+ required: true,
171
+ displayOptions: {
172
+ show: {
173
+ resource: ['project'],
174
+ operation: ['getBySlug'],
175
+ },
176
+ },
177
+ default: '',
178
+ description: 'The slug of the Infisical project',
179
+ },
180
+ {
181
+ displayName: 'Environment',
182
+ name: 'snapshotEnvironment',
183
+ type: 'string',
184
+ required: true,
185
+ displayOptions: {
186
+ show: {
187
+ resource: ['project'],
188
+ operation: ['getSecretSnapshots'],
189
+ },
190
+ },
191
+ default: 'dev',
192
+ description: 'The environment slug to retrieve snapshots for (e.g., dev, staging, prod)',
193
+ },
194
+ {
195
+ displayName: 'Username',
196
+ name: 'username',
197
+ type: 'string',
198
+ required: true,
199
+ displayOptions: {
200
+ show: {
201
+ resource: ['project'],
202
+ operation: ['getUserByUsername'],
203
+ },
204
+ },
205
+ default: '',
206
+ description: 'The username of the project member to retrieve',
207
+ },
208
+ {
209
+ displayName: 'Additional Fields',
210
+ name: 'snapshotOptions',
211
+ type: 'collection',
212
+ placeholder: 'Add Field',
213
+ default: {},
214
+ displayOptions: {
215
+ show: {
216
+ resource: ['project'],
217
+ operation: ['getSecretSnapshots'],
218
+ },
219
+ },
220
+ options: [
221
+ {
222
+ displayName: 'Limit',
223
+ name: 'limit',
224
+ type: 'number',
225
+ default: 20,
226
+ description: 'Maximum number of snapshots to return',
227
+ },
228
+ {
229
+ displayName: 'Offset',
230
+ name: 'offset',
231
+ type: 'number',
232
+ default: 0,
233
+ description: 'Number of snapshots to skip (pagination)',
234
+ },
235
+ {
236
+ displayName: 'Secret Path',
237
+ name: 'secretPath',
238
+ type: 'string',
239
+ default: '/',
240
+ description: 'Folder path to filter snapshots (default: /)',
241
+ },
242
+ ],
243
+ },
244
+ // ─── Folder operations ──────────────────────────────────────────────────
245
+ {
246
+ displayName: 'Operation',
247
+ name: 'operation',
248
+ type: 'options',
249
+ noDataExpression: true,
250
+ displayOptions: { show: { resource: ['folder'] } },
251
+ options: [
252
+ {
253
+ name: 'Create',
254
+ value: 'createFolder',
255
+ description: 'Create a new folder',
256
+ action: 'Create a folder',
257
+ },
258
+ {
259
+ name: 'Delete',
260
+ value: 'deleteFolder',
261
+ description: 'Delete a folder by ID or name',
262
+ action: 'Delete a folder',
263
+ },
264
+ {
265
+ name: 'Get',
266
+ value: 'getFolderById',
267
+ description: 'Get a folder by ID',
268
+ action: 'Get a folder',
269
+ },
270
+ {
271
+ name: 'List',
272
+ value: 'listFolders',
273
+ description: 'List all folders at a path',
274
+ action: 'List folders',
275
+ },
276
+ {
277
+ name: 'Update',
278
+ value: 'updateFolder',
279
+ description: 'Update the name or description of a folder',
280
+ action: 'Update a folder',
281
+ },
282
+ ],
283
+ default: 'listFolders',
284
+ },
285
+ // ─── Folder fields ──────────────────────────────────────────────────────
286
+ {
287
+ displayName: 'Project ID',
288
+ name: 'projectId',
289
+ type: 'string',
290
+ required: true,
291
+ displayOptions: {
292
+ show: {
293
+ resource: ['folder'],
294
+ operation: ['listFolders', 'createFolder', 'updateFolder', 'deleteFolder'],
295
+ },
296
+ },
297
+ default: '',
298
+ description: 'The ID of the Infisical project',
299
+ },
300
+ {
301
+ displayName: 'Environment',
302
+ name: 'environment',
303
+ type: 'string',
304
+ required: true,
305
+ displayOptions: {
306
+ show: {
307
+ resource: ['folder'],
308
+ operation: ['listFolders', 'createFolder', 'updateFolder', 'deleteFolder'],
309
+ },
310
+ },
311
+ default: 'dev',
312
+ description: 'The environment slug (e.g., dev, staging, prod)',
313
+ },
314
+ {
315
+ displayName: 'Folder Path',
316
+ name: 'folderPath',
317
+ type: 'string',
318
+ displayOptions: {
319
+ show: {
320
+ resource: ['folder'],
321
+ operation: ['listFolders', 'createFolder', 'updateFolder', 'deleteFolder'],
322
+ },
323
+ },
324
+ default: '/',
325
+ description: 'The path to list from or the parent path for create/update/delete (default: /)',
326
+ },
327
+ {
328
+ displayName: 'Folder ID',
329
+ name: 'folderId',
330
+ type: 'string',
331
+ required: true,
332
+ displayOptions: {
333
+ show: {
334
+ resource: ['folder'],
335
+ operation: ['getFolderById', 'updateFolder'],
336
+ },
337
+ },
338
+ default: '',
339
+ description: 'The ID of the folder',
340
+ },
341
+ {
342
+ displayName: 'Folder ID or Name',
343
+ name: 'folderIdOrName',
344
+ type: 'string',
345
+ required: true,
346
+ displayOptions: {
347
+ show: {
348
+ resource: ['folder'],
349
+ operation: ['deleteFolder'],
350
+ },
351
+ },
352
+ default: '',
353
+ description: 'The ID or name of the folder to delete',
354
+ },
355
+ {
356
+ displayName: 'Folder Name',
357
+ name: 'folderName',
358
+ type: 'string',
359
+ required: true,
360
+ displayOptions: {
361
+ show: {
362
+ resource: ['folder'],
363
+ operation: ['createFolder', 'updateFolder'],
364
+ },
365
+ },
366
+ default: '',
367
+ description: 'The name of the folder',
368
+ },
369
+ {
370
+ displayName: 'Additional Fields',
371
+ name: 'listFolderOptions',
372
+ type: 'collection',
373
+ placeholder: 'Add Field',
374
+ default: {},
375
+ displayOptions: {
376
+ show: {
377
+ resource: ['folder'],
378
+ operation: ['listFolders'],
379
+ },
380
+ },
381
+ options: [
382
+ {
383
+ displayName: 'Last Secret Modified',
384
+ name: 'lastSecretModified',
385
+ type: 'string',
386
+ default: '',
387
+ description: 'Filter folders modified after this ISO 8601 datetime',
388
+ },
389
+ {
390
+ displayName: 'Recursive',
391
+ name: 'recursive',
392
+ type: 'boolean',
393
+ default: false,
394
+ description: 'Whether to include subdirectories in the listing',
395
+ },
396
+ ],
397
+ },
398
+ {
399
+ displayName: 'Additional Fields',
400
+ name: 'createFolderOptions',
401
+ type: 'collection',
402
+ placeholder: 'Add Field',
403
+ default: {},
404
+ displayOptions: {
405
+ show: {
406
+ resource: ['folder'],
407
+ operation: ['createFolder'],
408
+ },
409
+ },
410
+ options: [
411
+ {
412
+ displayName: 'Description',
413
+ name: 'description',
414
+ type: 'string',
415
+ default: '',
416
+ description: 'An optional label for the folder',
417
+ },
418
+ ],
419
+ },
420
+ {
421
+ displayName: 'Additional Fields',
422
+ name: 'updateFolderOptions',
423
+ type: 'collection',
424
+ placeholder: 'Add Field',
425
+ default: {},
426
+ displayOptions: {
427
+ show: {
428
+ resource: ['folder'],
429
+ operation: ['updateFolder'],
430
+ },
431
+ },
432
+ options: [
433
+ {
434
+ displayName: 'Description',
435
+ name: 'description',
436
+ type: 'string',
437
+ default: '',
438
+ description: 'An updated label for the folder',
439
+ },
440
+ ],
441
+ },
442
+ {
443
+ displayName: 'Additional Fields',
444
+ name: 'deleteFolderOptions',
445
+ type: 'collection',
446
+ placeholder: 'Add Field',
447
+ default: {},
448
+ displayOptions: {
449
+ show: {
450
+ resource: ['folder'],
451
+ operation: ['deleteFolder'],
452
+ },
453
+ },
454
+ options: [
455
+ {
456
+ displayName: 'Force Delete',
457
+ name: 'forceDelete',
458
+ type: 'boolean',
459
+ default: false,
460
+ description: 'Whether to force delete the folder even if it contains secrets or sub-folders',
461
+ },
462
+ ],
463
+ },
126
464
  // ─── Shared secret fields ────────────────────────────────────────────────
127
465
  {
128
466
  displayName: 'Project ID',
129
- name: 'workspaceId',
467
+ name: 'projectId',
130
468
  type: 'string',
131
469
  required: true,
132
470
  displayOptions: { show: { resource: ['secret'] } },
133
471
  default: '',
134
- description: 'The ID of the Infisical project (workspace)',
472
+ description: 'The ID of the Infisical project',
135
473
  },
136
474
  {
137
475
  displayName: 'Environment',
@@ -221,6 +559,44 @@ class Infisical {
221
559
  },
222
560
  ],
223
561
  },
562
+ {
563
+ displayName: 'Secret Metadata',
564
+ name: 'secretMetadata',
565
+ type: 'fixedCollection',
566
+ typeOptions: { multipleValues: true },
567
+ placeholder: 'Add Metadata Entry',
568
+ default: {},
569
+ displayOptions: {
570
+ show: {
571
+ resource: ['secret'],
572
+ operation: ['create'],
573
+ },
574
+ },
575
+ description: 'Key/value metadata tags to attach to the secret',
576
+ options: [
577
+ {
578
+ displayName: 'Metadata Entry',
579
+ name: 'values',
580
+ values: [
581
+ {
582
+ displayName: 'Key',
583
+ name: 'key',
584
+ type: 'string',
585
+ required: true,
586
+ default: '',
587
+ description: 'Metadata key',
588
+ },
589
+ {
590
+ displayName: 'Value',
591
+ name: 'value',
592
+ type: 'string',
593
+ default: '',
594
+ description: 'Metadata value',
595
+ },
596
+ ],
597
+ },
598
+ ],
599
+ },
224
600
  // ─── Update: all fields optional ─────────────────────────────────────────
225
601
  {
226
602
  displayName: 'Additional Fields',
@@ -277,6 +653,44 @@ class Infisical {
277
653
  },
278
654
  ],
279
655
  },
656
+ {
657
+ displayName: 'Secret Metadata',
658
+ name: 'secretMetadata',
659
+ type: 'fixedCollection',
660
+ typeOptions: { multipleValues: true },
661
+ placeholder: 'Add Metadata Entry',
662
+ default: {},
663
+ displayOptions: {
664
+ show: {
665
+ resource: ['secret'],
666
+ operation: ['update'],
667
+ },
668
+ },
669
+ description: 'Key/value metadata tags to attach to the secret',
670
+ options: [
671
+ {
672
+ displayName: 'Metadata Entry',
673
+ name: 'values',
674
+ values: [
675
+ {
676
+ displayName: 'Key',
677
+ name: 'key',
678
+ type: 'string',
679
+ required: true,
680
+ default: '',
681
+ description: 'Metadata key',
682
+ },
683
+ {
684
+ displayName: 'Value',
685
+ name: 'value',
686
+ type: 'string',
687
+ default: '',
688
+ description: 'Metadata value',
689
+ },
690
+ ],
691
+ },
692
+ ],
693
+ },
280
694
  // ─── Create Many: secrets fixedCollection ─────────────────────────────────
281
695
  {
282
696
  displayName: 'Secrets',
@@ -327,6 +741,38 @@ class Infisical {
327
741
  default: false,
328
742
  description: 'Whether to disable multiline encoding for this secret value',
329
743
  },
744
+ {
745
+ displayName: 'Secret Metadata',
746
+ name: 'secretMetadata',
747
+ type: 'fixedCollection',
748
+ typeOptions: { multipleValues: true },
749
+ placeholder: 'Add Metadata Entry',
750
+ default: {},
751
+ description: 'Key/value metadata tags to attach to this secret',
752
+ options: [
753
+ {
754
+ displayName: 'Metadata Entry',
755
+ name: 'values',
756
+ values: [
757
+ {
758
+ displayName: 'Key',
759
+ name: 'key',
760
+ type: 'string',
761
+ required: true,
762
+ default: '',
763
+ description: 'Metadata key',
764
+ },
765
+ {
766
+ displayName: 'Value',
767
+ name: 'value',
768
+ type: 'string',
769
+ default: '',
770
+ description: 'Metadata value',
771
+ },
772
+ ],
773
+ },
774
+ ],
775
+ },
330
776
  ],
331
777
  },
332
778
  ],
@@ -409,6 +855,38 @@ class Infisical {
409
855
  default: false,
410
856
  description: 'Whether to disable multiline encoding for this secret value',
411
857
  },
858
+ {
859
+ displayName: 'Secret Metadata',
860
+ name: 'secretMetadata',
861
+ type: 'fixedCollection',
862
+ typeOptions: { multipleValues: true },
863
+ placeholder: 'Add Metadata Entry',
864
+ default: {},
865
+ description: 'Key/value metadata tags to attach to this secret',
866
+ options: [
867
+ {
868
+ displayName: 'Metadata Entry',
869
+ name: 'values',
870
+ values: [
871
+ {
872
+ displayName: 'Key',
873
+ name: 'key',
874
+ type: 'string',
875
+ required: true,
876
+ default: '',
877
+ description: 'Metadata key',
878
+ },
879
+ {
880
+ displayName: 'Value',
881
+ name: 'value',
882
+ type: 'string',
883
+ default: '',
884
+ description: 'Metadata value',
885
+ },
886
+ ],
887
+ },
888
+ ],
889
+ },
412
890
  ],
413
891
  },
414
892
  ],
@@ -459,6 +937,70 @@ class Infisical {
459
937
  },
460
938
  ],
461
939
  },
940
+ // ─── Delete Many: secrets fixedCollection ─────────────────────────────────
941
+ {
942
+ displayName: 'Secrets',
943
+ name: 'secretsToDelete',
944
+ type: 'fixedCollection',
945
+ typeOptions: { multipleValues: true },
946
+ required: true,
947
+ default: {},
948
+ displayOptions: {
949
+ show: {
950
+ resource: ['secret'],
951
+ operation: ['deleteMany'],
952
+ },
953
+ },
954
+ options: [
955
+ {
956
+ displayName: 'Secret',
957
+ name: 'values',
958
+ values: [
959
+ {
960
+ displayName: 'Secret Key',
961
+ name: 'secretKey',
962
+ type: 'string',
963
+ required: true,
964
+ default: '',
965
+ description: 'The name of the secret to delete',
966
+ },
967
+ {
968
+ displayName: 'Type',
969
+ name: 'type',
970
+ type: 'options',
971
+ options: [
972
+ { name: 'Shared', value: 'shared' },
973
+ { name: 'Personal', value: 'personal' },
974
+ ],
975
+ default: 'shared',
976
+ description: 'Whether to delete the shared or personal variant of the secret',
977
+ },
978
+ ],
979
+ },
980
+ ],
981
+ },
982
+ {
983
+ displayName: 'Additional Fields',
984
+ name: 'deleteManyOptions',
985
+ type: 'collection',
986
+ placeholder: 'Add Field',
987
+ default: {},
988
+ displayOptions: {
989
+ show: {
990
+ resource: ['secret'],
991
+ operation: ['deleteMany'],
992
+ },
993
+ },
994
+ options: [
995
+ {
996
+ displayName: 'Secret Path Override',
997
+ name: 'secretPath',
998
+ type: 'string',
999
+ default: '/',
1000
+ description: 'Override the top-level Secret Path for this batch request',
1001
+ },
1002
+ ],
1003
+ },
462
1004
  ],
463
1005
  };
464
1006
  this.methods = {
@@ -470,13 +1012,17 @@ class Infisical {
470
1012
  try {
471
1013
  let accessToken;
472
1014
  if (authType === 'universalAuth') {
1015
+ const loginForm = {
1016
+ clientId: creds.clientId,
1017
+ clientSecret: creds.clientSecret,
1018
+ };
1019
+ if (creds.organizationSlug) {
1020
+ loginForm.organizationSlug = creds.organizationSlug;
1021
+ }
473
1022
  const tokenResponse = await this.helpers.request({
474
1023
  method: 'POST',
475
1024
  uri: `${apiUrl}/v1/auth/universal-auth/login`,
476
- form: {
477
- clientId: creds.clientId,
478
- clientSecret: creds.clientSecret,
479
- },
1025
+ form: loginForm,
480
1026
  json: true,
481
1027
  });
482
1028
  accessToken = tokenResponse.accessToken;
@@ -506,13 +1052,12 @@ class Infisical {
506
1052
  };
507
1053
  }
508
1054
  async execute() {
509
- var _a, _b, _c;
510
1055
  const items = this.getInputData();
511
1056
  const returnData = [];
512
1057
  const resource = this.getNodeParameter('resource', 0);
513
1058
  const operation = this.getNodeParameter('operation', 0);
514
1059
  const credentials = await this.getCredentials('infisicalApi');
515
- const { apiUrl, accessToken } = await getInfisicalToken(this.helpers, credentials);
1060
+ const { apiUrl, accessToken } = await (0, auth_1.getInfisicalToken)(this.helpers, credentials);
516
1061
  const baseHeaders = {
517
1062
  Authorization: `Bearer ${accessToken}`,
518
1063
  Accept: 'application/json',
@@ -522,205 +1067,18 @@ class Infisical {
522
1067
  try {
523
1068
  // ── Secret resource ─────────────────────────────────────────────────────
524
1069
  if (resource === 'secret') {
525
- const workspaceId = this.getNodeParameter('workspaceId', i);
526
- const environment = this.getNodeParameter('environment', i);
527
- const secretPath = this.getNodeParameter('secretPath', i);
528
- // ── get ───────────────────────────────────────────────────────────────
529
- if (operation === 'get') {
530
- const secretKey = this.getNodeParameter('secretKey', i);
531
- const response = await this.helpers.httpRequest({
532
- method: 'GET',
533
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
534
- headers: baseHeaders,
535
- qs: { workspaceId, environment, secretPath },
536
- });
537
- returnData.push({ json: response, pairedItem: { item: i } });
538
- // ── getAll ────────────────────────────────────────────────────────────
539
- }
540
- else if (operation === 'getAll') {
541
- const response = await this.helpers.httpRequest({
542
- method: 'GET',
543
- url: `${apiUrl}/v3/secrets/raw`,
544
- headers: baseHeaders,
545
- qs: { workspaceId, environment, secretPath },
546
- });
547
- const secrets = response.secrets;
548
- for (const secret of secrets) {
549
- returnData.push({ json: secret, pairedItem: { item: i } });
550
- }
551
- // ── create ────────────────────────────────────────────────────────────
552
- }
553
- else if (operation === 'create') {
554
- const secretKey = this.getNodeParameter('secretKey', i);
555
- const secretValue = this.getNodeParameter('secretValue', i);
556
- const createOptions = this.getNodeParameter('createOptions', i, {});
557
- const body = {
558
- workspaceId,
559
- environment,
560
- secretName: secretKey,
561
- secretValue,
562
- secretPath,
563
- type: (_a = createOptions.type) !== null && _a !== void 0 ? _a : 'shared',
564
- };
565
- if (createOptions.secretComment)
566
- body.secretComment = createOptions.secretComment;
567
- if (createOptions.skipMultilineEncoding) {
568
- body.skipMultilineEncoding = createOptions.skipMultilineEncoding;
569
- }
570
- const response = await this.helpers.httpRequest({
571
- method: 'POST',
572
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
573
- headers: baseHeaders,
574
- body: JSON.stringify(body),
575
- });
576
- returnData.push({ json: response, pairedItem: { item: i } });
577
- // ── update (v4) ───────────────────────────────────────────────────────
578
- }
579
- else if (operation === 'update') {
580
- const secretKey = this.getNodeParameter('secretKey', i);
581
- const updateOptions = this.getNodeParameter('updateOptions', i, {});
582
- const body = {
583
- projectId: workspaceId,
584
- environment,
585
- secretPath,
586
- };
587
- // Spread only non-empty optional fields
588
- if (updateOptions.secretValue !== undefined && updateOptions.secretValue !== '') {
589
- body.secretValue = updateOptions.secretValue;
590
- }
591
- if (updateOptions.newSecretName)
592
- body.newSecretName = updateOptions.newSecretName;
593
- if (updateOptions.secretComment !== undefined)
594
- body.secretComment = updateOptions.secretComment;
595
- if (updateOptions.type)
596
- body.type = updateOptions.type;
597
- if (updateOptions.skipMultilineEncoding) {
598
- body.skipMultilineEncoding = updateOptions.skipMultilineEncoding;
599
- }
600
- const response = await this.helpers.httpRequest({
601
- method: 'PATCH',
602
- url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
603
- headers: baseHeaders,
604
- body: JSON.stringify(body),
605
- });
606
- returnData.push({ json: response, pairedItem: { item: i } });
607
- // ── delete ────────────────────────────────────────────────────────────
608
- }
609
- else if (operation === 'delete') {
610
- const secretKey = this.getNodeParameter('secretKey', i);
611
- const response = await this.helpers.httpRequest({
612
- method: 'DELETE',
613
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
614
- headers: baseHeaders,
615
- qs: { workspaceId, environment, secretPath },
616
- });
617
- returnData.push({ json: response, pairedItem: { item: i } });
618
- // ── createMany (v4 batch POST) ────────────────────────────────────────
619
- }
620
- else if (operation === 'createMany') {
621
- const secretsParam = this.getNodeParameter('secrets', i, {});
622
- const secretItems = (_b = secretsParam.values) !== null && _b !== void 0 ? _b : [];
623
- if (secretItems.length === 0) {
624
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one secret must be added in the Secrets list', { itemIndex: i });
625
- }
626
- const createManyOptions = this.getNodeParameter('createManyOptions', i, {});
627
- const effectivePath = createManyOptions.secretPath || secretPath;
628
- const secrets = secretItems.map((item) => {
629
- const s = {
630
- secretKey: item.secretKey,
631
- secretValue: item.secretValue,
632
- };
633
- if (item.secretComment)
634
- s.secretComment = item.secretComment;
635
- if (item.skipMultilineEncoding)
636
- s.skipMultilineEncoding = item.skipMultilineEncoding;
637
- return s;
638
- });
639
- const body = {
640
- projectId: workspaceId,
641
- environment,
642
- secretPath: effectivePath,
643
- secrets,
644
- };
645
- const response = await this.helpers.httpRequest({
646
- method: 'POST',
647
- url: `${apiUrl}/v4/secrets/batch`,
648
- headers: baseHeaders,
649
- body: JSON.stringify(body),
650
- });
651
- const responseData = response;
652
- if (Array.isArray(responseData.secrets)) {
653
- for (const secret of responseData.secrets) {
654
- returnData.push({ json: secret, pairedItem: { item: i } });
655
- }
656
- }
657
- else {
658
- // Approval / policy-gated response
659
- returnData.push({ json: responseData, pairedItem: { item: i } });
660
- }
661
- // ── updateMany (v4 batch PATCH) ───────────────────────────────────────
662
- }
663
- else if (operation === 'updateMany') {
664
- const secretsToUpdateParam = this.getNodeParameter('secretsToUpdate', i, {});
665
- const secretItems = (_c = secretsToUpdateParam.values) !== null && _c !== void 0 ? _c : [];
666
- if (secretItems.length === 0) {
667
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one secret must be added in the Secrets list', { itemIndex: i });
668
- }
669
- const updateManyOptions = this.getNodeParameter('updateManyOptions', i, {});
670
- const effectivePath = updateManyOptions.secretPath || secretPath;
671
- const secrets = secretItems.map((item) => {
672
- const s = { secretKey: item.secretKey };
673
- if (item.secretValue !== undefined && item.secretValue !== '') {
674
- s.secretValue = item.secretValue;
675
- }
676
- if (item.newSecretName)
677
- s.newSecretName = item.newSecretName;
678
- if (item.secretComment !== undefined && item.secretComment !== '') {
679
- s.secretComment = item.secretComment;
680
- }
681
- if (item.skipMultilineEncoding)
682
- s.skipMultilineEncoding = item.skipMultilineEncoding;
683
- return s;
684
- });
685
- const body = {
686
- projectId: workspaceId,
687
- environment,
688
- secretPath: effectivePath,
689
- secrets,
690
- };
691
- if (updateManyOptions.mode)
692
- body.mode = updateManyOptions.mode;
693
- const response = await this.helpers.httpRequest({
694
- method: 'PATCH',
695
- url: `${apiUrl}/v4/secrets/batch`,
696
- headers: baseHeaders,
697
- body: JSON.stringify(body),
698
- });
699
- const responseData = response;
700
- if (Array.isArray(responseData.secrets)) {
701
- for (const secret of responseData.secrets) {
702
- returnData.push({ json: secret, pairedItem: { item: i } });
703
- }
704
- }
705
- else {
706
- // Approval / policy-gated response
707
- returnData.push({ json: responseData, pairedItem: { item: i } });
708
- }
709
- }
710
- // ── Workspace resource ──────────────────────────────────────────────────
1070
+ const results = await (0, secretOperations_1.executeSecretOperation)(this, apiUrl, baseHeaders, operation, i);
1071
+ returnData.push(...results);
1072
+ // ── Project resource ──────────────────────────────────────────────────
711
1073
  }
712
- else if (resource === 'workspace') {
713
- if (operation === 'getAll') {
714
- const response = await this.helpers.httpRequest({
715
- method: 'GET',
716
- url: `${apiUrl}/v1/workspace`,
717
- headers: baseHeaders,
718
- });
719
- const workspaces = response.workspaces;
720
- for (const workspace of workspaces) {
721
- returnData.push({ json: workspace, pairedItem: { item: i } });
722
- }
723
- }
1074
+ else if (resource === 'project') {
1075
+ const results = await (0, projectOperations_1.executeProjectOperation)(this, apiUrl, baseHeaders, operation, i);
1076
+ returnData.push(...results);
1077
+ // ── Folder resource ──────────────────────────────────────────────────
1078
+ }
1079
+ else if (resource === 'folder') {
1080
+ const results = await (0, folderOperations_1.executeFolderOperation)(this, apiUrl, baseHeaders, operation, i);
1081
+ returnData.push(...results);
724
1082
  }
725
1083
  }
726
1084
  catch (error) {