@tadnt2003/n8n-nodes-infisical 0.3.0 → 0.3.6
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/LICENSE
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Kennis AI
|
|
4
|
-
Copyright (c) 2026 Nguyen Thanh Dat
|
|
5
|
-
|
|
6
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
-
in the Software without restriction, including without limitation the rights
|
|
9
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
furnished to do so, subject to the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kennis AI
|
|
4
|
+
Copyright (c) 2026 Nguyen Thanh Dat
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -15,6 +15,7 @@ const CREDENTIAL_FIELD_MAPS = {
|
|
|
15
15
|
{ param: 'httpNode', secretKey: 'httpNode' },
|
|
16
16
|
],
|
|
17
17
|
googleOAuth2Api: [
|
|
18
|
+
{ param: 'serverUrl', secretKey: 'serverUrl' },
|
|
18
19
|
{ param: 'clientId', secretKey: 'clientId' },
|
|
19
20
|
{ param: 'clientSecret', secretKey: 'clientSecret' },
|
|
20
21
|
{ param: 'scope', secretKey: 'scope' },
|
|
@@ -210,18 +211,13 @@ const CREDENTIAL_FIELD_MAPS = {
|
|
|
210
211
|
{ param: 'algorithm', secretKey: 'algorithm' },
|
|
211
212
|
],
|
|
212
213
|
};
|
|
214
|
+
function toSlug(name) {
|
|
215
|
+
return name.trim().replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
216
|
+
}
|
|
213
217
|
function buildSecretPath(rootPath, credentialName) {
|
|
214
218
|
const root = rootPath.replace(/\/+$/, '') || '/';
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
// Fix 7.5: removed `typeof value === 'boolean' && value === false` — false is a meaningful value
|
|
218
|
-
// that must be written to Infisical (e.g. ssl:false, sshTunnel:false as condition keys).
|
|
219
|
-
function isEmptyValue(value) {
|
|
220
|
-
if (value === null || value === undefined)
|
|
221
|
-
return true;
|
|
222
|
-
if (typeof value === 'string' && value.trim() === '')
|
|
223
|
-
return true;
|
|
224
|
-
return false;
|
|
219
|
+
const slug = toSlug(credentialName);
|
|
220
|
+
return root === '/' ? `/${slug}` : `${root}/${slug}`;
|
|
225
221
|
}
|
|
226
222
|
// Fix 7.4: handles `number` type (port, connectTimeout, maxConnections, etc.)
|
|
227
223
|
// Fix 7.7: reads schema's own `default` before falling back to enum heuristic
|
|
@@ -257,6 +253,23 @@ function coerceValue(raw, def) {
|
|
|
257
253
|
return raw === 'true' || raw === '1';
|
|
258
254
|
return raw;
|
|
259
255
|
}
|
|
256
|
+
// Decide whether a conditional branch fires given its condition key and values.
|
|
257
|
+
//
|
|
258
|
+
// When condKey IS in schema properties, fire only when the current value matches condValues.
|
|
259
|
+
//
|
|
260
|
+
// When condKey is NOT in schema properties (e.g. useDynamicClientRegistration on
|
|
261
|
+
// googleOAuth2Api), JSON Schema evaluates the if-clause vacuously — the properties keyword
|
|
262
|
+
// has nothing to check, so it passes, and both the [true] branch and the [false] branch
|
|
263
|
+
// appear to fire simultaneously. That is the "vacuous truth" problem.
|
|
264
|
+
//
|
|
265
|
+
// n8n avoids it by internally defaulting the absent key to false before validating, so only
|
|
266
|
+
// the branch whose condValues contain a falsy value actually fires (the "standard mode"
|
|
267
|
+
// branch). We mirror that: condValues=[false] fires, condValues=[true] does not.
|
|
268
|
+
function conditionFires(condKeyInSchema, condValues, condVal) {
|
|
269
|
+
if (condKeyInSchema)
|
|
270
|
+
return condValues.includes(condVal);
|
|
271
|
+
return condValues.some((v) => !v);
|
|
272
|
+
}
|
|
260
273
|
// Validate credential data against the n8n schema's required fields and conditional requirements.
|
|
261
274
|
// For form mode, pass availableFormFields to skip checks for fields the form cannot provide.
|
|
262
275
|
function validateAgainstSchema(data, schemaInfo, availableFormFields) {
|
|
@@ -264,20 +277,20 @@ function validateAgainstSchema(data, schemaInfo, availableFormFields) {
|
|
|
264
277
|
for (const field of schemaInfo.topRequired) {
|
|
265
278
|
if (availableFormFields && !availableFormFields.has(field))
|
|
266
279
|
continue;
|
|
267
|
-
if (
|
|
268
|
-
errors.push(`"${field}" is required but
|
|
280
|
+
if (data[field] === undefined || data[field] === null) {
|
|
281
|
+
errors.push(`"${field}" is required but not provided`);
|
|
269
282
|
}
|
|
270
283
|
}
|
|
271
284
|
for (const { condKey, condValues, thenRequired } of schemaInfo.condBranches) {
|
|
272
285
|
const condVal = data[condKey];
|
|
273
286
|
const condKeyInSchema = condKey in schemaInfo.props;
|
|
274
|
-
if (
|
|
287
|
+
if (conditionFires(condKeyInSchema, condValues, condVal)) {
|
|
275
288
|
for (const field of thenRequired) {
|
|
276
289
|
if (availableFormFields && !availableFormFields.has(field))
|
|
277
290
|
continue;
|
|
278
|
-
if (
|
|
291
|
+
if (data[field] === undefined || data[field] === null) {
|
|
279
292
|
const when = condKeyInSchema ? ` when "${condKey}" is "${String(condVal)}"` : '';
|
|
280
|
-
errors.push(`"${field}" is required${when} but
|
|
293
|
+
errors.push(`"${field}" is required${when} but not provided`);
|
|
281
294
|
}
|
|
282
295
|
}
|
|
283
296
|
}
|
|
@@ -430,10 +443,8 @@ function applyCondBranches(fullData, schemaInfo) {
|
|
|
430
443
|
var _a, _b;
|
|
431
444
|
for (const { condKey, condValues, thenRequired, elseProhibited } of schemaInfo.condBranches) {
|
|
432
445
|
const condVal = fullData[condKey];
|
|
433
|
-
// When condKey is absent from schema properties it can't appear in the data,
|
|
434
|
-
// so JSON Schema's `properties` validator skips it → condition fires vacuously.
|
|
435
446
|
const condKeyInSchema = condKey in schemaInfo.props;
|
|
436
|
-
if (
|
|
447
|
+
if (conditionFires(condKeyInSchema, condValues, condVal)) {
|
|
437
448
|
// Condition fires → fill any missing then-required fields with safe defaults.
|
|
438
449
|
for (const field of thenRequired) {
|
|
439
450
|
if (field in fullData)
|
|
@@ -691,7 +702,7 @@ async function executeSyncOperation(ctx, apiUrl, baseHeaders, operation, i) {
|
|
|
691
702
|
method: 'POST',
|
|
692
703
|
url: `${apiUrl}/v2/folders`,
|
|
693
704
|
headers: baseHeaders,
|
|
694
|
-
body: { projectId, environment, name: credentialName, path: folderPath },
|
|
705
|
+
body: { projectId, environment, name: toSlug(credentialName), path: folderPath },
|
|
695
706
|
});
|
|
696
707
|
}
|
|
697
708
|
catch (err) {
|
|
@@ -701,12 +712,14 @@ async function executeSyncOperation(ctx, apiUrl, baseHeaders, operation, i) {
|
|
|
701
712
|
throw err;
|
|
702
713
|
}
|
|
703
714
|
}
|
|
704
|
-
// Collect
|
|
715
|
+
// Collect credential fields as Infisical secrets; empty strings are written as "" so that
|
|
716
|
+
// required-but-blank fields (e.g. serverUrl on googleOAuth2Api) don't fail schema validation
|
|
717
|
+
// on the way back. Only null/undefined is skipped.
|
|
705
718
|
const secretMetadata = [{ key: 'n8n_credential_type', value: credentialType }];
|
|
706
719
|
const secrets = [];
|
|
707
720
|
if (inputMode === 'json') {
|
|
708
721
|
for (const [key, value] of Object.entries(parsedJson !== null && parsedJson !== void 0 ? parsedJson : {})) {
|
|
709
|
-
if (
|
|
722
|
+
if (value === null || value === undefined)
|
|
710
723
|
continue;
|
|
711
724
|
if (fetchedSchemaProps && !(key in fetchedSchemaProps))
|
|
712
725
|
continue;
|
|
@@ -721,7 +734,7 @@ async function executeSyncOperation(ctx, apiUrl, baseHeaders, operation, i) {
|
|
|
721
734
|
}
|
|
722
735
|
for (const { param, secretKey } of fieldMap) {
|
|
723
736
|
const value = ctx.getNodeParameter(param, i, '');
|
|
724
|
-
if (
|
|
737
|
+
if (value === null || value === undefined)
|
|
725
738
|
continue;
|
|
726
739
|
secrets.push({ secretKey, secretValue: String(value), secretMetadata });
|
|
727
740
|
}
|
package/package.json
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tadnt2003/n8n-nodes-infisical",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "n8n community node for Infisical - Secret management platform",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"n8n-community-node-package",
|
|
7
|
-
"n8n",
|
|
8
|
-
"infisical",
|
|
9
|
-
"secrets",
|
|
10
|
-
"secrets-management"
|
|
11
|
-
],
|
|
12
|
-
"license": "MIT",
|
|
13
|
-
"homepage": "https://github.com/TadNT2003/n8n-nodes-infisical",
|
|
14
|
-
"author": {
|
|
15
|
-
"name": "Nguyen Thanh Dat",
|
|
16
|
-
"email": "ntdatwows2003@gmail.com",
|
|
17
|
-
"url": "https://github.com/TadNT2003"
|
|
18
|
-
},
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/TadNT2003/n8n-nodes-infisical.git"
|
|
22
|
-
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsc && gulp build",
|
|
25
|
-
"dev": "tsc --watch",
|
|
26
|
-
"format": "prettier nodes credentials --write",
|
|
27
|
-
"lint": "eslint nodes credentials package.json",
|
|
28
|
-
"lintfix": "eslint nodes credentials package.json --fix",
|
|
29
|
-
"prepublishOnly": "npm run build && npm run lint"
|
|
30
|
-
},
|
|
31
|
-
"files": [
|
|
32
|
-
"dist"
|
|
33
|
-
],
|
|
34
|
-
"n8n": {
|
|
35
|
-
"n8nNodesApiVersion": 1,
|
|
36
|
-
"credentials": [
|
|
37
|
-
"dist/credentials/InfisicalApi.credentials.js"
|
|
38
|
-
],
|
|
39
|
-
"nodes": [
|
|
40
|
-
"dist/nodes/Infisical/Infisical.node.js",
|
|
41
|
-
"dist/nodes/InfisicalSync/InfisicalSync.node.js"
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
46
|
-
"@typescript-eslint/parser": "^5.45.0",
|
|
47
|
-
"eslint": "^8.29.0",
|
|
48
|
-
"eslint-plugin-n8n-nodes-base": "^1.11.0",
|
|
49
|
-
"gulp": "^4.0.2",
|
|
50
|
-
"n8n-workflow": "^1.120.0",
|
|
51
|
-
"prettier": "^2.7.1",
|
|
52
|
-
"typescript": "~5.3.0"
|
|
53
|
-
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"n8n-workflow": "*"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@tadnt2003/n8n-nodes-infisical",
|
|
3
|
+
"version": "0.3.6",
|
|
4
|
+
"description": "n8n community node for Infisical - Secret management platform",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"infisical",
|
|
9
|
+
"secrets",
|
|
10
|
+
"secrets-management"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/TadNT2003/n8n-nodes-infisical",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Nguyen Thanh Dat",
|
|
16
|
+
"email": "ntdatwows2003@gmail.com",
|
|
17
|
+
"url": "https://github.com/TadNT2003"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/TadNT2003/n8n-nodes-infisical.git"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && gulp build",
|
|
25
|
+
"dev": "tsc --watch",
|
|
26
|
+
"format": "prettier nodes credentials --write",
|
|
27
|
+
"lint": "eslint nodes credentials package.json",
|
|
28
|
+
"lintfix": "eslint nodes credentials package.json --fix",
|
|
29
|
+
"prepublishOnly": "npm run build && npm run lint"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"n8n": {
|
|
35
|
+
"n8nNodesApiVersion": 1,
|
|
36
|
+
"credentials": [
|
|
37
|
+
"dist/credentials/InfisicalApi.credentials.js"
|
|
38
|
+
],
|
|
39
|
+
"nodes": [
|
|
40
|
+
"dist/nodes/Infisical/Infisical.node.js",
|
|
41
|
+
"dist/nodes/InfisicalSync/InfisicalSync.node.js"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
46
|
+
"@typescript-eslint/parser": "^5.45.0",
|
|
47
|
+
"eslint": "^8.29.0",
|
|
48
|
+
"eslint-plugin-n8n-nodes-base": "^1.11.0",
|
|
49
|
+
"gulp": "^4.0.2",
|
|
50
|
+
"n8n-workflow": "^1.120.0",
|
|
51
|
+
"prettier": "^2.7.1",
|
|
52
|
+
"typescript": "~5.3.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"n8n-workflow": "*"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
2
|
-
<rect width="24" height="24" rx="4" fill="#000000"/>
|
|
3
|
-
<path d="M12 6L6 9v6c0 3.5 2.5 6.5 6 7.5 3.5-1 6-4 6-7.5V9l-6-3z" fill="#FFFFFF"/>
|
|
4
|
-
<path d="M12 11v5M10 13l2 2 2-2" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
-
</svg>
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
2
|
-
<rect width="24" height="24" rx="4" fill="#000000"/>
|
|
3
|
-
<path d="M12 6L6 9v6c0 3.5 2.5 6.5 6 7.5 3.5-1 6-4 6-7.5V9l-6-3z" fill="#FFFFFF"/>
|
|
4
|
-
<path d="M12 11v5M10 13l2 2 2-2" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
-
</svg>
|