@ixiam/n8n-nodes-civicrm 1.1.41 → 2.1.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/dist/credentials/CiviCrmApi.credentials.js +1 -0
- package/dist/src/nodes/CiviCrm/CiviCrm.node.js +432 -422
- package/dist/src/nodes/transport/GenericFunctions.js +5 -5
- package/package.json +2 -5
- package/.release-it.json +0 -6
- package/credentials/CiviCrmApi.credentials.ts +0 -58
- package/credentials/CiviCrmApi.credentials.ts.bak +0 -52
- package/debug-auth.js +0 -94
- package/eslint.config.mjs +0 -3
- package/jest.config.cjs +0 -9
- package/reload-in-docker.md +0 -68
- package/src/index.ts +0 -12
- package/src/nodes/CiviCrm/CiviCrm.node.ts +0 -1257
- package/src/nodes/CiviCrm/civicrm.svg +0 -28
- package/src/nodes/CiviCrm/descriptions/generic.ts +0 -9
- package/src/nodes/CiviCrm/descriptions/resources.ts +0 -43
- package/src/nodes/transport/GenericFunctions.ts +0 -52
- package/sxkeychain erase +0 -7
- package/test/helpers/mockServer.ts +0 -27
- package/test/nodes/CiviCrm.test.ts +0 -67
- package/test/tsconfig.json +0 -10
- package/tsconfig.json +0 -23
|
@@ -4,8 +4,8 @@ exports.civicrmApiRequest = civicrmApiRequest;
|
|
|
4
4
|
exports.api4 = api4;
|
|
5
5
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Executes a CiviCRM API v4 call (Civi-Go).
|
|
8
|
+
* Uses form-urlencoded encoding with the "params" field serialized as JSON.
|
|
9
9
|
*/
|
|
10
10
|
async function civicrmApiRequest(method, path, body) {
|
|
11
11
|
var _a;
|
|
@@ -17,7 +17,7 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
17
17
|
headers: {
|
|
18
18
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
19
19
|
},
|
|
20
|
-
//
|
|
20
|
+
// flat body as expected by Civi-Go
|
|
21
21
|
body: {
|
|
22
22
|
params: JSON.stringify((_a = body.params) !== null && _a !== void 0 ? _a : body),
|
|
23
23
|
},
|
|
@@ -32,9 +32,9 @@ async function civicrmApiRequest(method, path, body) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* Returns the standard body for API4 calls (flat params).
|
|
36
36
|
*/
|
|
37
37
|
function api4(entity, action, params = {}) {
|
|
38
|
-
//
|
|
38
|
+
// return flat parameters, not nested
|
|
39
39
|
return params;
|
|
40
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixiam/n8n-nodes-civicrm",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Full-featured CiviCRM API v4 integration for n8n",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"main": "dist/index.js",
|
|
14
14
|
"types": "dist/index.d.ts",
|
|
15
|
+
"files": ["dist"],
|
|
15
16
|
"scripts": {
|
|
16
17
|
"dev": "n8n-node dev",
|
|
17
18
|
"build": "n8n-node build && pnpm run copy:assets",
|
|
@@ -53,9 +54,5 @@
|
|
|
53
54
|
"peerDependencies": {
|
|
54
55
|
"n8n-workflow": "*"
|
|
55
56
|
},
|
|
56
|
-
"overrides": {
|
|
57
|
-
"eslint": "9.32.0",
|
|
58
|
-
"change-case": "4.1.2"
|
|
59
|
-
},
|
|
60
57
|
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a"
|
|
61
58
|
}
|
package/.release-it.json
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ICredentialType,
|
|
3
|
-
INodeProperties,
|
|
4
|
-
ICredentialTestRequest,
|
|
5
|
-
} from 'n8n-workflow';
|
|
6
|
-
|
|
7
|
-
export class CiviCrmApi implements ICredentialType {
|
|
8
|
-
|
|
9
|
-
name = 'civiCrmApi';
|
|
10
|
-
displayName = 'CiviCRM API';
|
|
11
|
-
documentationUrl = 'https://docs.civicrm.org/dev/en/latest/api/v4/usage/#auth';
|
|
12
|
-
|
|
13
|
-
properties: INodeProperties[] = [
|
|
14
|
-
{
|
|
15
|
-
displayName: 'Base URL',
|
|
16
|
-
name: 'baseUrl',
|
|
17
|
-
type: 'string',
|
|
18
|
-
default: '',
|
|
19
|
-
placeholder: 'https://example.org/civicrm',
|
|
20
|
-
required: true,
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
displayName: 'API Token',
|
|
24
|
-
name: 'apiToken',
|
|
25
|
-
type: 'string',
|
|
26
|
-
typeOptions: {
|
|
27
|
-
password: true,
|
|
28
|
-
},
|
|
29
|
-
default: '',
|
|
30
|
-
required: true,
|
|
31
|
-
},
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
authenticate = {
|
|
35
|
-
type: 'generic' as const,
|
|
36
|
-
properties: {
|
|
37
|
-
headers: {
|
|
38
|
-
'X-Civi-Auth': '={{ "Bearer " + $credentials.apiToken }}',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
test: ICredentialTestRequest = {
|
|
44
|
-
request: {
|
|
45
|
-
baseURL: '={{$credentials.baseUrl}}',
|
|
46
|
-
url: '/civicrm/ajax/api4/Contact/get',
|
|
47
|
-
method: 'POST',
|
|
48
|
-
headers: {
|
|
49
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
50
|
-
},
|
|
51
|
-
body: {
|
|
52
|
-
params: JSON.stringify({ select: ['id'], limit: 1 }),
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const civiCrmApi = CiviCrmApi;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ICredentialType,
|
|
3
|
-
INodeProperties,
|
|
4
|
-
ICredentialTestRequest,
|
|
5
|
-
} from 'n8n-workflow';
|
|
6
|
-
|
|
7
|
-
export class CiviCrmApi implements ICredentialType {
|
|
8
|
-
|
|
9
|
-
name = 'civiCrmApi';
|
|
10
|
-
displayName = 'CiviCRM API';
|
|
11
|
-
documentationUrl = 'https://docs.civicrm.org/dev/en/latest/api/';
|
|
12
|
-
|
|
13
|
-
properties: INodeProperties[] = [
|
|
14
|
-
{
|
|
15
|
-
displayName: 'Base URL',
|
|
16
|
-
name: 'baseUrl',
|
|
17
|
-
type: 'string',
|
|
18
|
-
default: '',
|
|
19
|
-
required: true,
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
displayName: 'API Token',
|
|
23
|
-
name: 'apiToken',
|
|
24
|
-
type: 'string',
|
|
25
|
-
typeOptions: { password: true },
|
|
26
|
-
default: '',
|
|
27
|
-
required: true,
|
|
28
|
-
},
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
// ← ESTA ES LA PARTE CRÍTICA
|
|
32
|
-
authenticate = {
|
|
33
|
-
type: 'generic' as const,
|
|
34
|
-
properties: {
|
|
35
|
-
headers: {
|
|
36
|
-
'X-Civi-Auth': '={{ "Bearer " + $credentials.apiToken }}',
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
test: ICredentialTestRequest = {
|
|
42
|
-
request: {
|
|
43
|
-
method: 'POST',
|
|
44
|
-
url: '={{ $credentials.baseUrl.replace(/\\/$/, "") }}/civicrm/ajax/api4/Contact/get',
|
|
45
|
-
headers: {
|
|
46
|
-
'X-Civi-Auth': '={{ "Bearer " + $credentials.apiToken }}',
|
|
47
|
-
'Content-Type': 'application/json',
|
|
48
|
-
},
|
|
49
|
-
body: { limit: 1 },
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
package/debug-auth.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const https = require('https');
|
|
3
|
-
|
|
4
|
-
const config = {
|
|
5
|
-
url: 'https://smaster.demo.civicrm.org',
|
|
6
|
-
apiKey: 'Q{12XT/su[+W'
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const requestBody = JSON.stringify({
|
|
10
|
-
version: 4,
|
|
11
|
-
select: ['id'],
|
|
12
|
-
limit: 1
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const options = {
|
|
16
|
-
hostname: 'smaster.demo.civicrm.org',
|
|
17
|
-
path: '/civicrm/ajax/api4/Contact/get',
|
|
18
|
-
method: 'POST',
|
|
19
|
-
headers: {
|
|
20
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
21
|
-
'Content-Type': 'application/x-www-form-urlencoded', // Based on CiviCrmApi.credentials.ts? No, wait.
|
|
22
|
-
// In CiviCrmApi.credentials.ts, we see:
|
|
23
|
-
// headers: { Authorization: ... }
|
|
24
|
-
// BUT GenericFunctions.ts says: 'Content-Type': 'application/x-www-form-urlencoded'
|
|
25
|
-
// AND body: { params: JSON.stringify(body) }
|
|
26
|
-
|
|
27
|
-
// HOWEVER, the `test` property in CiviCrmApi.credentials.ts does NOT go through GenericFunctions.
|
|
28
|
-
// It's a standard n8n credential test request.
|
|
29
|
-
// It defines:
|
|
30
|
-
// request: { ... method: 'POST', body: { ... } }
|
|
31
|
-
// n8n by default sends JSON if body is an object? Or form-urlencoded?
|
|
32
|
-
// Let's check CiviCrmApi.credentials.ts again.
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Re-checking the credential definition:
|
|
37
|
-
/*
|
|
38
|
-
authenticate = {
|
|
39
|
-
type: 'generic' as const,
|
|
40
|
-
properties: {
|
|
41
|
-
headers: {
|
|
42
|
-
Authorization: 'Bearer ={{$credentials.apiKey}}',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
test: ICredentialTestRequest = {
|
|
47
|
-
request: {
|
|
48
|
-
...
|
|
49
|
-
body: {
|
|
50
|
-
version: 4,
|
|
51
|
-
select: ['id'],
|
|
52
|
-
limit: 1,
|
|
53
|
-
},
|
|
54
|
-
*/
|
|
55
|
-
// It does NOT specify a Content-Type in the `test` request. N8n defaults to JSON for object bodies usually.
|
|
56
|
-
// BUT GenericFunctions.ts explicitly sets 'Content-Type': 'application/x-www-form-urlencoded'.
|
|
57
|
-
// Maybe the test request fails because it sends JSON but CiviCRM expects form-urlencoded with `params`?
|
|
58
|
-
// OR it expects JSON?
|
|
59
|
-
// The user said "it works in the previous version".
|
|
60
|
-
// The previous version had the SAME credential file content (just in a different folder).
|
|
61
|
-
// So the request definition itself should be correct.
|
|
62
|
-
// Let's try sending it as JSON first (n8n default for object body).
|
|
63
|
-
|
|
64
|
-
const req = https.request(options, (res) => {
|
|
65
|
-
let data = '';
|
|
66
|
-
res.on('data', (chunk) => {
|
|
67
|
-
data += chunk;
|
|
68
|
-
});
|
|
69
|
-
res.on('end', () => {
|
|
70
|
-
console.log(`Status Code: ${res.statusCode}`);
|
|
71
|
-
console.log(`Body: ${data}`);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
req.on('error', (error) => {
|
|
76
|
-
console.error(error);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// If n8n sends as JSON:
|
|
80
|
-
// req.setHeader('Content-Type', 'application/json');
|
|
81
|
-
// req.write(requestBody);
|
|
82
|
-
|
|
83
|
-
// Wait, CiviCrm v4 API usually expects `params` parameter if using form-urlencoded, OR direct JSON?
|
|
84
|
-
// Let's look at `GenericFunctions.ts` again.
|
|
85
|
-
// It wraps the body in `params: JSON.stringify(body)`.
|
|
86
|
-
// The `test` request DOES NOT do that. It just sends `body: { version: 4 ... }`.
|
|
87
|
-
// Does n8n credential tester use the `authenticate` block? Yes.
|
|
88
|
-
// Does it use `GenericFunctions`? No.
|
|
89
|
-
// So if the `test` request works in the old version, then CiviCRM API4 MUST accept raw JSON body on that endpoint.
|
|
90
|
-
// Let's try sending standard JSON.
|
|
91
|
-
|
|
92
|
-
req.setHeader('Content-Type', 'application/json');
|
|
93
|
-
req.write(requestBody);
|
|
94
|
-
req.end();
|
package/eslint.config.mjs
DELETED
package/jest.config.cjs
DELETED
package/reload-in-docker.md
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Reload Node in Docker n8n
|
|
2
|
-
|
|
3
|
-
If you're loading this node from a local folder in Docker and seeing cached/old versions, try these steps:
|
|
4
|
-
|
|
5
|
-
## Option 1: Restart Docker Container (Quick)
|
|
6
|
-
```bash
|
|
7
|
-
# Restart your n8n container
|
|
8
|
-
docker restart <container-name>
|
|
9
|
-
# or if using docker-compose
|
|
10
|
-
docker-compose restart
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Option 2: Clear n8n Cache (Better)
|
|
14
|
-
```bash
|
|
15
|
-
# Stop the container
|
|
16
|
-
docker stop <container-name>
|
|
17
|
-
|
|
18
|
-
# Remove the container (keeps volumes)
|
|
19
|
-
docker rm <container-name>
|
|
20
|
-
|
|
21
|
-
# Start fresh
|
|
22
|
-
docker-compose up -d
|
|
23
|
-
# or your docker run command
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Option 3: Verify Volume Mount
|
|
27
|
-
If you're using a volume mount like `-v /path/to/n8n-nodes-civicrm:/data/custom-nodes/n8n-nodes-civicrm`:
|
|
28
|
-
|
|
29
|
-
1. Make sure the path points to THIS directory
|
|
30
|
-
2. Verify the dist folder is being mounted:
|
|
31
|
-
```bash
|
|
32
|
-
docker exec <container-name> ls -la /data/custom-nodes/n8n-nodes-civicrm/dist/credentials/
|
|
33
|
-
docker exec <container-name> cat /data/custom-nodes/n8n-nodes-civicrm/dist/credentials/CiviCrmApi.credentials.js | grep baseURL
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Option 4: Check n8n Custom Nodes Path
|
|
37
|
-
If using `N8N_CUSTOM_EXTENSION_ENV` environment variable:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
# Check what path n8n is using
|
|
41
|
-
docker exec <container-name> env | grep N8N_CUSTOM
|
|
42
|
-
|
|
43
|
-
# Verify the file exists in that path
|
|
44
|
-
docker exec <container-name> ls -la <custom-path>/dist/credentials/
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Option 5: Force Rebuild and Reload
|
|
48
|
-
```bash
|
|
49
|
-
# In this directory, clean and rebuild
|
|
50
|
-
npm run build
|
|
51
|
-
|
|
52
|
-
# If using npm link
|
|
53
|
-
npm link
|
|
54
|
-
|
|
55
|
-
# Then restart n8n container
|
|
56
|
-
docker restart <container-name>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Verify the Fix
|
|
60
|
-
After restarting, check if the error is gone. The built file should have:
|
|
61
|
-
```javascript
|
|
62
|
-
baseURL: '={{ $credentials.baseUrl }}',
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
NOT:
|
|
66
|
-
```javascript
|
|
67
|
-
baseURL: '={{ $credentials.baseUrl.replace(/\\/$/, "") }}',
|
|
68
|
-
```
|
package/src/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { INodeType, ICredentialType } from 'n8n-workflow';
|
|
2
|
-
|
|
3
|
-
import CiviCrmNode from './nodes/CiviCrm/CiviCrm.node';
|
|
4
|
-
import { CiviCrmApi } from '../credentials/CiviCrmApi.credentials';
|
|
5
|
-
|
|
6
|
-
export const nodes: INodeType[] = [
|
|
7
|
-
new CiviCrmNode(),
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
export const credentials: ICredentialType[] = [
|
|
11
|
-
new CiviCrmApi(),
|
|
12
|
-
];
|