@ixiam/n8n-nodes-civicrm 0.2.4 → 0.3.8

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/.eslintignore ADDED
@@ -0,0 +1 @@
1
+ dist/
package/.eslintrc.cjs ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ root: true,
3
+ parser: '@typescript-eslint/parser',
4
+ plugins: ['@typescript-eslint','n8n-nodes-base'],
5
+ extends: [
6
+ 'plugin:@typescript-eslint/recommended',
7
+ 'plugin:n8n-nodes-base/community'
8
+ ],
9
+ ignorePatterns: ['dist/**'],
10
+ };
@@ -0,0 +1,61 @@
1
+ import type {
2
+ ICredentialType,
3
+ INodeProperties,
4
+ IHttpRequestMethods,
5
+ } from 'n8n-workflow';
6
+
7
+ export class CiviCrmApi implements ICredentialType {
8
+ name = 'civiCrmApi';
9
+ displayName = 'CiviCRM API';
10
+ documentationUrl = 'https://docs.civicrm.org/dev/en/latest/api/v4/';
11
+
12
+ authenticate = {
13
+ type: 'generic' as const,
14
+ properties: {
15
+ headers: {
16
+ 'X-Civi-Auth': '={{"Bearer " + $credentials.apiToken}}',
17
+ 'Content-Type': 'application/json',
18
+ },
19
+ },
20
+ };
21
+
22
+ // Button "Test" in credential UI
23
+ test = {
24
+ request: {
25
+ // IMPORTANT: method must be typed as IHttpRequestMethods
26
+ method: 'POST' as IHttpRequestMethods,
27
+ url: '={{$credentials.baseUrl.replace(/\\/$/, "")}}/civicrm/ajax/api4/Contact/get',
28
+ headers: {
29
+ 'X-Civi-Auth': '={{"Bearer " + $credentials.apiToken}}',
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ body: {
33
+ entity: 'Contact',
34
+ action: 'get',
35
+ params: { limit: 1 },
36
+ },
37
+ json: true,
38
+ },
39
+ };
40
+
41
+ properties: INodeProperties[] = [
42
+ {
43
+ displayName: 'Base URL',
44
+ name: 'baseUrl',
45
+ type: 'string',
46
+ default: '',
47
+ required: true,
48
+ placeholder: 'https://crm.example.org',
49
+ description: 'Sin la barra final',
50
+ },
51
+ {
52
+ displayName: 'API Token',
53
+ name: 'apiToken',
54
+ type: 'string',
55
+ typeOptions: { password: true },
56
+ default: '',
57
+ required: true,
58
+ description: 'Se envía como X-Civi-Auth: Bearer <token>',
59
+ },
60
+ ];
61
+ }
@@ -11,3 +11,4 @@ export declare class CiviCrm implements INodeType {
11
11
  };
12
12
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
13
13
  }
14
+ export default CiviCrm;
@@ -10,6 +10,11 @@ const ENTITY_MAP = {
10
10
  case: 'Case',
11
11
  contribution: 'Contribution',
12
12
  membership: 'Membership',
13
+ participant: 'Participant',
14
+ group: 'Group',
15
+ relationship: 'Relationship',
16
+ email: 'Email',
17
+ activity: 'Activity',
13
18
  };
14
19
  /**
15
20
  * Nodo principal CiviCRM para n8n
@@ -22,7 +27,7 @@ class CiviCrm {
22
27
  icon: 'file:civicrm.svg',
23
28
  group: ['transform'],
24
29
  version: 1,
25
- description: 'Interact with CiviCRM API v4',
30
+ description: 'Interact with CiviCRM API v4 (Civi-Go compatible)',
26
31
  defaults: { name: 'CiviCRM' },
27
32
  inputs: ['main'],
28
33
  outputs: ['main'],
@@ -52,9 +57,11 @@ class CiviCrm {
52
57
  url,
53
58
  headers: {
54
59
  'X-Civi-Auth': `Bearer ${apiToken}`,
55
- 'Content-Type': 'application/json',
60
+ 'Content-Type': 'application/x-www-form-urlencoded',
61
+ },
62
+ body: {
63
+ params: JSON.stringify({ limit: 5 }),
56
64
  },
57
- body: (0, GenericFunctions_1.api4)('OptionValue', 'get', { limit: 5 }),
58
65
  json: true,
59
66
  });
60
67
  const values = (res?.values || []);
@@ -71,42 +78,68 @@ class CiviCrm {
71
78
  const out = [];
72
79
  const resource = this.getNodeParameter('resource', 0);
73
80
  const operation = this.getNodeParameter('operation', 0);
81
+ const entity = ENTITY_MAP[resource];
74
82
  for (let i = 0; i < items.length; i++) {
75
- const entity = ENTITY_MAP[resource];
76
- // GET
83
+ // === GET ===
77
84
  if (operation === 'get') {
78
85
  const id = this.getNodeParameter('id', i);
79
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, (0, GenericFunctions_1.api4)(entity, 'get', { where: [['id', '=', id]], limit: 1 }));
86
+ const params = {
87
+ where: [['id', '=', id]],
88
+ limit: 1,
89
+ select: [
90
+ 'id',
91
+ 'display_name',
92
+ 'first_name',
93
+ 'last_name',
94
+ 'contact_type',
95
+ 'email.email',
96
+ 'phone.phone',
97
+ 'address.city',
98
+ 'address.country_id:label',
99
+ 'address.postal_code',
100
+ 'address.street_address',
101
+ ],
102
+ join: [
103
+ ['Email AS email', 'LEFT'],
104
+ ['Phone AS phone', 'LEFT'],
105
+ ['Address AS address', 'LEFT'],
106
+ ],
107
+ };
108
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, params);
80
109
  out.push({ json: (res?.values?.[0] ?? {}) });
81
110
  }
82
- // GET MANY
111
+ // === GET MANY ===
83
112
  if (operation === 'getMany') {
84
113
  const returnAll = this.getNodeParameter('returnAll', i, false);
85
114
  const limit = this.getNodeParameter('limit', i, 100);
86
115
  const whereJson = this.getNodeParameter('whereJson', i, '');
87
- let where;
88
- if (whereJson) {
89
- try {
90
- where = JSON.parse(whereJson);
91
- }
92
- catch (e) {
93
- throw new Error('Where (JSON) debe ser JSON válido: usa un objeto o un array de condiciones.');
94
- }
95
- }
96
- // Normalize where: allow object or array; API4 accepts both
97
- if (where && typeof where === 'object' && !Array.isArray(where)) {
98
- where = where;
99
- }
100
- if (Array.isArray(where)) {
101
- // leave as-is; expected [[field, op, value], ...]
102
- }
103
- // Cap limit to a reasonable page size
104
- const cappedLimit = Math.max(1, Math.min(limit, 500));
116
+ const where = whereJson ? JSON.parse(whereJson) : undefined;
117
+ const baseParams = {
118
+ where,
119
+ select: [
120
+ 'id',
121
+ 'display_name',
122
+ 'first_name',
123
+ 'last_name',
124
+ 'contact_type',
125
+ 'email.email',
126
+ 'phone.phone',
127
+ 'address.city',
128
+ 'address.country_id:label',
129
+ 'address.postal_code',
130
+ 'address.street_address',
131
+ ],
132
+ join: [
133
+ ['Email AS email', 'LEFT'],
134
+ ['Phone AS phone', 'LEFT'],
135
+ ['Address AS address', 'LEFT'],
136
+ ],
137
+ };
105
138
  if (returnAll) {
106
139
  let offset = 0;
107
140
  const page = 500;
108
141
  while (true) {
109
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, (0, GenericFunctions_1.api4)(entity, 'get', { where, limit: page, offset }));
142
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit: page, offset });
110
143
  const vals = (res?.values ?? []);
111
144
  for (const v of vals)
112
145
  out.push({ json: v });
@@ -116,41 +149,43 @@ class CiviCrm {
116
149
  }
117
150
  }
118
151
  else {
119
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, (0, GenericFunctions_1.api4)(entity, 'get', { where, limit: cappedLimit, offset: 0 }));
120
- let vals = (res?.values ?? []);
121
- if (vals.length > cappedLimit) {
122
- vals = vals.slice(0, cappedLimit);
123
- }
152
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit });
153
+ const vals = (res?.values ?? []);
124
154
  for (const v of vals)
125
155
  out.push({ json: v });
126
156
  }
127
157
  }
128
- // CREATE
158
+ // === CREATE ===
129
159
  if (operation === 'create') {
130
160
  const pairs = this.getNodeParameter('fields.field', i, []);
131
- const params = Object.fromEntries(pairs
161
+ const values = Object.fromEntries(pairs
132
162
  .filter((p) => p.fieldName)
133
163
  .map((p) => [p.fieldName, convertValue(p.fieldValue)]));
134
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, (0, GenericFunctions_1.api4)(entity, 'create', params));
164
+ const params = { values };
165
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, params);
135
166
  out.push({ json: res });
136
167
  }
137
- // UPDATE
168
+ // === UPDATE ===
138
169
  if (operation === 'update') {
139
170
  const id = this.getNodeParameter('id', i);
140
171
  const pairs = this.getNodeParameter('fields.field', i, []);
172
+ const values = Object.fromEntries(pairs
173
+ .filter((p) => p.fieldName)
174
+ .map((p) => [p.fieldName, convertValue(p.fieldValue)]));
141
175
  const params = {
142
- id,
143
- ...Object.fromEntries(pairs
144
- .filter((p) => p.fieldName)
145
- .map((p) => [p.fieldName, convertValue(p.fieldValue)])),
176
+ values,
177
+ where: [['id', '=', id]],
146
178
  };
147
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, (0, GenericFunctions_1.api4)(entity, 'update', params));
179
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, params);
148
180
  out.push({ json: res });
149
181
  }
150
- // DELETE
182
+ // === DELETE ===
151
183
  if (operation === 'delete') {
152
184
  const id = this.getNodeParameter('id', i);
153
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, (0, GenericFunctions_1.api4)(entity, 'delete', { id }));
185
+ const params = {
186
+ where: [['id', '=', id]],
187
+ };
188
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, params);
154
189
  out.push({ json: res });
155
190
  }
156
191
  }
@@ -179,3 +214,5 @@ function convertValue(val) {
179
214
  catch { }
180
215
  return val;
181
216
  }
217
+ // Requerido por n8n >=1.110
218
+ exports.default = CiviCrm;
@@ -1,3 +1,3 @@
1
- import { INodeProperties } from 'n8n-workflow';
1
+ import type { INodeProperties } from 'n8n-workflow';
2
2
  export declare const resourceProp: INodeProperties;
3
3
  export declare const operationProp: INodeProperties;
@@ -1,33 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.operationProp = exports.resourceProp = void 0;
4
- const RESOURCE_OPTIONS = [
5
- { name: 'Contact', value: 'contact' },
6
- { name: 'Event', value: 'event' },
7
- { name: 'Case', value: 'case' },
8
- { name: 'Contribution', value: 'contribution' },
9
- { name: 'Membership', value: 'membership' },
10
- ];
11
4
  exports.resourceProp = {
12
5
  displayName: 'Resource',
13
6
  name: 'resource',
14
7
  type: 'options',
15
8
  default: 'contact',
16
- options: RESOURCE_OPTIONS, // sin readonly/as const
9
+ options: [
10
+ { name: 'Contact', value: 'contact' },
11
+ { name: 'Event', value: 'event' },
12
+ { name: 'Case', value: 'case' },
13
+ { name: 'Contribution', value: 'contribution' },
14
+ { name: 'Membership', value: 'membership' },
15
+ { name: 'Participant', value: 'participant' },
16
+ { name: 'Group', value: 'group' },
17
+ { name: 'Relationship', value: 'relationship' },
18
+ { name: 'Email', value: 'email' },
19
+ { name: 'Activity', value: 'activity' },
20
+ { name: 'Custom API Call', value: 'customApi' },
21
+ ],
17
22
  };
18
23
  exports.operationProp = {
19
24
  displayName: 'Operation',
20
25
  name: 'operation',
21
26
  type: 'options',
22
- displayOptions: {
23
- show: { resource: ['contact', 'event', 'case', 'contribution', 'membership'] },
24
- },
25
- default: 'get',
27
+ default: 'getMany',
26
28
  options: [
29
+ { name: 'Create', value: 'create' },
30
+ { name: 'Delete', value: 'delete' },
27
31
  { name: 'Get', value: 'get' },
28
32
  { name: 'Get Many', value: 'getMany' },
29
- { name: 'Create', value: 'create' },
30
33
  { name: 'Update', value: 'update' },
31
- { name: 'Delete', value: 'delete' },
32
- ], // tipo mutable
34
+ ],
33
35
  };
@@ -1,13 +1,10 @@
1
- import { type IExecuteFunctions } from 'n8n-workflow';
1
+ import type { IExecuteFunctions } from 'n8n-workflow';
2
2
  /**
3
- * Ejecuta una llamada a la API de CiviCRM v4
3
+ * Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
4
+ * Usa form-urlencoded con el campo "params" serializado
4
5
  */
5
6
  export declare function civicrmApiRequest(this: IExecuteFunctions, method: 'POST', path: string, body: Record<string, unknown>): Promise<any>;
6
7
  /**
7
- * Devuelve el formato estándar para una llamada API4
8
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
8
9
  */
9
- export declare function api4(entity: string, action: string, params?: Record<string, unknown>): {
10
- entity: string;
11
- action: string;
12
- params: Record<string, unknown>;
13
- };
10
+ export declare function api4(entity: string, action: string, params?: Record<string, unknown>): Record<string, unknown>;
@@ -3,25 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.api4 = exports.civicrmApiRequest = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
5
  /**
6
- * Ejecuta una llamada a la API de CiviCRM v4
6
+ * Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
7
+ * Usa form-urlencoded con el campo "params" serializado
7
8
  */
8
9
  async function civicrmApiRequest(method, path, body) {
9
10
  const { baseUrl, apiToken } = (await this.getCredentials('civiCrmApi'));
10
11
  const options = {
11
12
  method,
12
- url: `${baseUrl}${path}`,
13
+ url: `${baseUrl.replace(/\/$/, '')}${path}`,
13
14
  headers: {
14
- 'Content-Type': 'application/json',
15
+ 'Content-Type': 'application/x-www-form-urlencoded',
15
16
  'X-Civi-Auth': `Bearer ${apiToken}`,
16
17
  },
17
- body,
18
+ // cuerpo plano como espera Civi-Go
19
+ body: {
20
+ params: JSON.stringify(body.params ?? body),
21
+ },
18
22
  json: true,
19
23
  };
20
24
  try {
21
25
  const response = await this.helpers.httpRequest(options);
22
- if (response?.is_error) {
23
- throw new n8n_workflow_1.NodeApiError(this.getNode(), response);
24
- }
25
26
  return response;
26
27
  }
27
28
  catch (error) {
@@ -30,9 +31,10 @@ async function civicrmApiRequest(method, path, body) {
30
31
  }
31
32
  exports.civicrmApiRequest = civicrmApiRequest;
32
33
  /**
33
- * Devuelve el formato estándar para una llamada API4
34
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
34
35
  */
35
36
  function api4(entity, action, params = {}) {
36
- return { entity, action, params };
37
+ // devolvemos los parámetros planos, no anidados
38
+ return params;
37
39
  }
38
40
  exports.api4 = api4;
@@ -0,0 +1,302 @@
1
+ import type {
2
+ IExecuteFunctions,
3
+ ILoadOptionsFunctions,
4
+ INodeExecutionData,
5
+ INodePropertyOptions,
6
+ INodeType,
7
+ INodeTypeDescription,
8
+ IDataObject,
9
+ } from 'n8n-workflow';
10
+
11
+ import { civicrmApiRequest } from '../transport/GenericFunctions';
12
+ import { resourceProp, operationProp } from './descriptions/resources';
13
+ import { genericFields, upsertFields } from './descriptions/generic';
14
+
15
+ /**
16
+ * Recursos soportados
17
+ */
18
+ type Resource =
19
+ | 'contact'
20
+ | 'event'
21
+ | 'case'
22
+ | 'contribution'
23
+ | 'membership'
24
+ | 'participant'
25
+ | 'group'
26
+ | 'relationship'
27
+ | 'email'
28
+ | 'activity';
29
+
30
+ const ENTITY_MAP: Record<Resource, string> = {
31
+ contact: 'Contact',
32
+ event: 'Event',
33
+ case: 'Case',
34
+ contribution: 'Contribution',
35
+ membership: 'Membership',
36
+ participant: 'Participant',
37
+ group: 'Group',
38
+ relationship: 'Relationship',
39
+ email: 'Email',
40
+ activity: 'Activity',
41
+ };
42
+
43
+ type Operation = 'get' | 'getMany' | 'create' | 'update' | 'delete';
44
+
45
+ /**
46
+ * Nodo principal CiviCRM para n8n
47
+ */
48
+ export class CiviCrm implements INodeType {
49
+ description: INodeTypeDescription = {
50
+ displayName: 'CiviCRM',
51
+ name: 'civiCrm',
52
+ icon: 'file:civicrm.svg',
53
+ group: ['transform'],
54
+ version: 1,
55
+ description: 'Interact with CiviCRM API v4 (Civi-Go compatible)',
56
+ defaults: { name: 'CiviCRM' },
57
+ inputs: ['main'],
58
+ outputs: ['main'],
59
+ credentials: [{ name: 'civiCrmApi', required: true }],
60
+ properties: [
61
+ resourceProp,
62
+ operationProp,
63
+ {
64
+ displayName: 'ID',
65
+ name: 'id',
66
+ type: 'number',
67
+ default: 0,
68
+ required: true,
69
+ displayOptions: { show: { operation: ['get', 'update', 'delete'] } },
70
+ },
71
+ ...genericFields,
72
+ ...upsertFields,
73
+ ],
74
+ };
75
+
76
+ methods = {
77
+ loadOptions: {
78
+ async getOptionValues(this: ILoadOptionsFunctions) {
79
+ const { baseUrl, apiToken } = (await this.getCredentials('civiCrmApi')) as {
80
+ baseUrl: string;
81
+ apiToken: string;
82
+ };
83
+
84
+ const url = `${baseUrl.replace(/\/$/, '')}/civicrm/ajax/api4/OptionValue/get`;
85
+
86
+ const res = await this.helpers.httpRequest({
87
+ method: 'POST',
88
+ url,
89
+ headers: {
90
+ 'X-Civi-Auth': `Bearer ${apiToken}`,
91
+ 'Content-Type': 'application/x-www-form-urlencoded',
92
+ },
93
+ body: {
94
+ params: JSON.stringify({ limit: 5 }),
95
+ },
96
+ json: true,
97
+ });
98
+
99
+ const values = (res?.values || []) as Array<{ id: number; label: string }>;
100
+ return values.map((v): INodePropertyOptions => ({
101
+ name: v.label,
102
+ value: v.id,
103
+ }));
104
+ },
105
+ },
106
+ };
107
+
108
+ async execute(this: IExecuteFunctions) {
109
+ const items = this.getInputData();
110
+ const out: INodeExecutionData[] = [];
111
+
112
+ const resource = this.getNodeParameter('resource', 0) as Resource;
113
+ const operation = this.getNodeParameter('operation', 0) as Operation;
114
+ const entity = ENTITY_MAP[resource];
115
+
116
+ for (let i = 0; i < items.length; i++) {
117
+ // === GET ===
118
+ if (operation === 'get') {
119
+ const id = this.getNodeParameter('id', i) as number;
120
+
121
+ const params = {
122
+ where: [['id', '=', id]],
123
+ limit: 1,
124
+ select: [
125
+ 'id',
126
+ 'display_name',
127
+ 'first_name',
128
+ 'last_name',
129
+ 'contact_type',
130
+ 'email.email',
131
+ 'phone.phone',
132
+ 'address.city',
133
+ 'address.country_id:label',
134
+ 'address.postal_code',
135
+ 'address.street_address',
136
+ ],
137
+ join: [
138
+ ['Email AS email', 'LEFT'],
139
+ ['Phone AS phone', 'LEFT'],
140
+ ['Address AS address', 'LEFT'],
141
+ ],
142
+ };
143
+
144
+ const res = await civicrmApiRequest.call(
145
+ this,
146
+ 'POST',
147
+ `/civicrm/ajax/api4/${entity}/get`,
148
+ params,
149
+ );
150
+
151
+ out.push({ json: (res?.values?.[0] ?? {}) as IDataObject });
152
+ }
153
+
154
+ // === GET MANY ===
155
+ if (operation === 'getMany') {
156
+ const returnAll = this.getNodeParameter('returnAll', i, false) as boolean;
157
+ const limit = this.getNodeParameter('limit', i, 100) as number;
158
+ const whereJson = this.getNodeParameter('whereJson', i, '') as string;
159
+ const where = whereJson ? JSON.parse(whereJson) : undefined;
160
+
161
+ const baseParams = {
162
+ where,
163
+ select: [
164
+ 'id',
165
+ 'display_name',
166
+ 'first_name',
167
+ 'last_name',
168
+ 'contact_type',
169
+ 'email.email',
170
+ 'phone.phone',
171
+ 'address.city',
172
+ 'address.country_id:label',
173
+ 'address.postal_code',
174
+ 'address.street_address',
175
+ ],
176
+ join: [
177
+ ['Email AS email', 'LEFT'],
178
+ ['Phone AS phone', 'LEFT'],
179
+ ['Address AS address', 'LEFT'],
180
+ ],
181
+ };
182
+
183
+ if (returnAll) {
184
+ let offset = 0;
185
+ const page = 500;
186
+ while (true) {
187
+ const res = await civicrmApiRequest.call(
188
+ this,
189
+ 'POST',
190
+ `/civicrm/ajax/api4/${entity}/get`,
191
+ { ...baseParams, limit: page, offset },
192
+ );
193
+ const vals = (res?.values ?? []) as IDataObject[];
194
+ for (const v of vals) out.push({ json: v });
195
+ if (vals.length < page) break;
196
+ offset += page;
197
+ }
198
+ } else {
199
+ const res = await civicrmApiRequest.call(
200
+ this,
201
+ 'POST',
202
+ `/civicrm/ajax/api4/${entity}/get`,
203
+ { ...baseParams, limit },
204
+ );
205
+ const vals = (res?.values ?? []) as IDataObject[];
206
+ for (const v of vals) out.push({ json: v });
207
+ }
208
+ }
209
+
210
+
211
+ // === CREATE ===
212
+ if (operation === 'create') {
213
+ const pairs = this.getNodeParameter('fields.field', i, []) as Array<{
214
+ fieldName: string;
215
+ fieldValue: string;
216
+ }>;
217
+
218
+ const values = Object.fromEntries(
219
+ pairs
220
+ .filter((p) => p.fieldName)
221
+ .map((p) => [p.fieldName, convertValue(p.fieldValue)]),
222
+ );
223
+
224
+ const params = { values };
225
+
226
+ const res = await civicrmApiRequest.call(
227
+ this,
228
+ 'POST',
229
+ `/civicrm/ajax/api4/${entity}/create`,
230
+ params,
231
+ );
232
+ out.push({ json: res as IDataObject });
233
+ }
234
+
235
+ // === UPDATE ===
236
+ if (operation === 'update') {
237
+ const id = this.getNodeParameter('id', i) as number;
238
+ const pairs = this.getNodeParameter('fields.field', i, []) as Array<{
239
+ fieldName: string;
240
+ fieldValue: string;
241
+ }>;
242
+
243
+ const values = Object.fromEntries(
244
+ pairs
245
+ .filter((p) => p.fieldName)
246
+ .map((p) => [p.fieldName, convertValue(p.fieldValue)]),
247
+ );
248
+
249
+ const params = {
250
+ values,
251
+ where: [['id', '=', id]],
252
+ };
253
+
254
+ const res = await civicrmApiRequest.call(
255
+ this,
256
+ 'POST',
257
+ `/civicrm/ajax/api4/${entity}/update`,
258
+ params,
259
+ );
260
+ out.push({ json: res as IDataObject });
261
+ }
262
+
263
+ // === DELETE ===
264
+ if (operation === 'delete') {
265
+ const id = this.getNodeParameter('id', i) as number;
266
+
267
+ const params = {
268
+ where: [['id', '=', id]],
269
+ };
270
+
271
+ const res = await civicrmApiRequest.call(
272
+ this,
273
+ 'POST',
274
+ `/civicrm/ajax/api4/${entity}/delete`,
275
+ params,
276
+ );
277
+ out.push({ json: res as IDataObject });
278
+ }
279
+ }
280
+
281
+ return [out];
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Convierte string a número, boolean, objeto o deja string
287
+ */
288
+ function convertValue(val: string): unknown {
289
+ const t = String(val ?? '').trim();
290
+ if (t === '') return '';
291
+ if (t === 'true') return true;
292
+ if (t === 'false') return false;
293
+ if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t);
294
+ try {
295
+ const j = JSON.parse(t);
296
+ if (typeof j === 'object') return j;
297
+ } catch {}
298
+ return val;
299
+ }
300
+
301
+ // Requerido por n8n >=1.110
302
+ export default CiviCrm;
@@ -0,0 +1,28 @@
1
+ <svg xml:space="preserve" style="max-height: 500px" viewBox="190.4982463465553 39.1683 70.07818371607516 70.33139999999999" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" id="Layer_1" version="1.1" width="70.07818371607516" height="70.33139999999999">
2
+ <style type="text/css">
3
+ .st0{fill:#086287;}
4
+ .st1{fill:#81C459;}
5
+ </style>
6
+ <g>
7
+ <g>
8
+ <g>
9
+ <path d="M216.26,104.26C216.26,104.26,216.26,104.26,216.26,104.26c-3.77-0.07-5.2-4.43-5.35-4.92l-12.85-42.11&#xA;&#9;&#9;&#9;&#9;c-0.76-2.47-0.58-4.46,0.51-5.92c0.71-0.94,2.12-2.04,4.83-1.99c0.99,0.02,1.77,0.19,1.85,0.21l42.78,9.97&#xA;&#9;&#9;&#9;&#9;c2.75,0.64,4.44,1.94,5.02,3.85c0.93,3.04-1.65,5.92-1.95,6.24l-29.94,32.12C219.57,103.43,217.91,104.29,216.26,104.26z&#xA;&#9;&#9;&#9;&#9; M203.19,53.73c-0.77-0.01-1.02,0.19-1.06,0.26c-0.22,0.31-0.26,0.44,0.19,1.93l12.85,42.11c0.29,0.9,0.76,1.74,1.18,1.77l0,0&#xA;&#9;&#9;&#9;&#9;c0.01,0,0.52,0,1.57-1.13l29.94-32.12c0.55-0.61,1.06-1.6,0.95-1.9c-0.08-0.22-0.43-0.5-1.77-0.81l-42.78-9.97l0,0&#xA;&#9;&#9;&#9;&#9;C204.24,53.87,203.7,53.74,203.19,53.73z" class="st0"/>
10
+ </g>
11
+ <g>
12
+ <path d="M211.45,100.83c-1.38,0.51-2.83,0.61-3.96,0.24c0,0,0,0,0,0c-3.57-1.17-3.68-5.74-3.68-6.26l0-41l4.21,0.94&#xA;&#9;&#9;&#9;&#9;l0.02,40.15c0.01,0.94,0.25,1.84,0.83,1.94l0,0c0,0,0.3,0.09,1.15-0.3L211.45,100.83z M214.02,94.31l34.62-20.03&#xA;&#9;&#9;&#9;&#9;c0.7-0.42,1.53-1.04,1.46-1.54c-0.01-0.07-0.17-0.52-0.92-1.05l2.9-3.3c1.64,1.25,2.47,2.71,2.47,4.35c0,3.17-3.3,5.17-3.68,5.39&#xA;&#9;&#9;&#9;&#9;l-35.51,20.4L214.02,94.31z M245.14,69.42l-34.02-19.79c0,0-0.85-0.54-1.34-0.7c-0.73-0.24-1.08,0-1.15,0.05&#xA;&#9;&#9;&#9;&#9;c-0.2,0.14-0.27,0.24-0.35,1.24l-4.38-0.82c0.24-1.82,0.95-3.17,2.12-4.03c0.95-0.69,2.62-1.33,5.19-0.5&#xA;&#9;&#9;&#9;&#9;c0.94,0.31,1.63,0.7,1.71,0.74l35.39,20.42L245.14,69.42z" class="st1"/>
13
+ </g>
14
+ </g>
15
+ <g>
16
+ <path d="M183.02,66.82c-0.48-0.28-0.86-0.67-1.15-1.15c-0.28-0.48-0.42-1-0.42-1.57c0-0.56,0.14-1.09,0.42-1.57&#xA;&#9;&#9;&#9;s0.66-0.86,1.15-1.15s1-0.42,1.57-0.42s1.09,0.14,1.57,0.42s0.86,0.66,1.15,1.15s0.42,1,0.42,1.57c0,0.57-0.14,1.09-0.42,1.57&#xA;&#9;&#9;&#9;c-0.28,0.48-0.66,0.86-1.15,1.15s-1,0.42-1.57,0.42S183.5,67.1,183.02,66.82z M185.93,66.42c0.41-0.24,0.74-0.57,0.98-0.98&#xA;&#9;&#9;&#9;c0.24-0.41,0.36-0.86,0.36-1.35c0-0.48-0.12-0.93-0.36-1.34c-0.24-0.41-0.57-0.73-0.98-0.98c-0.41-0.24-0.86-0.36-1.35-0.36&#xA;&#9;&#9;&#9;c-0.48,0-0.93,0.12-1.34,0.36c-0.41,0.24-0.73,0.57-0.98,0.98c-0.24,0.41-0.36,0.85-0.36,1.34c0,0.49,0.12,0.94,0.36,1.35&#xA;&#9;&#9;&#9;c0.24,0.41,0.57,0.74,0.98,0.98s0.85,0.36,1.34,0.36C185.07,66.79,185.52,66.66,185.93,66.42z M183.37,65.8&#xA;&#9;&#9;&#9;c-0.06-0.05-0.08-0.12-0.08-0.21v-2.83c0-0.11,0.04-0.21,0.11-0.28s0.17-0.12,0.28-0.12h1.05c0.46,0,0.8,0.1,1.03,0.29&#xA;&#9;&#9;&#9;s0.34,0.45,0.34,0.76c0,0.21-0.06,0.39-0.18,0.53c-0.12,0.14-0.28,0.25-0.46,0.32c0.16,0.06,0.3,0.18,0.42,0.35&#xA;&#9;&#9;&#9;c0.12,0.18,0.18,0.42,0.18,0.74v0.24c0,0.08-0.03,0.15-0.09,0.21c-0.06,0.06-0.13,0.09-0.21,0.09s-0.15-0.03-0.21-0.09&#xA;&#9;&#9;&#9;c-0.06-0.06-0.09-0.13-0.09-0.21v-0.16c0-0.25-0.04-0.46-0.11-0.63c-0.07-0.17-0.25-0.26-0.53-0.26h-0.95v1.06&#xA;&#9;&#9;&#9;c0,0.08-0.03,0.15-0.09,0.21c-0.06,0.06-0.13,0.08-0.21,0.08C183.49,65.88,183.42,65.86,183.37,65.8z M184.7,64.02&#xA;&#9;&#9;&#9;c0.25,0,0.45-0.05,0.6-0.15c0.15-0.1,0.22-0.25,0.22-0.44c0-0.18-0.06-0.32-0.19-0.42c-0.13-0.1-0.34-0.14-0.65-0.14h-0.81v1.15&#xA;&#9;&#9;&#9;H184.7z" class="st0"/>
17
+ </g>
18
+ <g>
19
+ <path d="M31.72,88.55c-2.15-1.18-3.85-2.87-5.08-5.08c-1.23-2.21-1.85-4.79-1.85-7.74s0.62-5.53,1.85-7.74&#xA;&#9;&#9;&#9;c1.23-2.21,2.93-3.9,5.08-5.08c2.15-1.18,4.58-1.77,7.29-1.77c1.84,0,3.49,0.22,4.94,0.65c1.45,0.43,2.89,1.06,4.33,1.87&#xA;&#9;&#9;&#9;c0.6,0.32,0.89,0.84,0.89,1.54c0,0.41-0.15,0.77-0.45,1.08c-0.3,0.31-0.69,0.47-1.18,0.47c-0.27,0-0.51-0.05-0.73-0.16&#xA;&#9;&#9;&#9;c-1.19-0.62-2.36-1.1-3.49-1.42c-1.14-0.32-2.45-0.49-3.94-0.49c-2.33,0-4.31,0.48-5.95,1.44c-1.64,0.96-2.87,2.28-3.7,3.94&#xA;&#9;&#9;&#9;c-0.83,1.67-1.24,3.55-1.24,5.67s0.41,4,1.24,5.67c0.83,1.67,2.06,2.98,3.7,3.94c1.64,0.96,3.62,1.44,5.95,1.44&#xA;&#9;&#9;&#9;c1.49,0,2.8-0.16,3.94-0.49c1.14-0.32,2.3-0.8,3.49-1.42c0.22-0.11,0.46-0.16,0.73-0.16c0.49,0,0.88,0.15,1.18,0.45&#xA;&#9;&#9;&#9;c0.3,0.3,0.45,0.66,0.45,1.1c0,0.7-0.3,1.22-0.89,1.54c-1.44,0.81-2.88,1.44-4.33,1.87c-1.45,0.43-3.09,0.65-4.94,0.65&#xA;&#9;&#9;&#9;C36.3,90.32,33.87,89.73,31.72,88.55z" class="st0"/>
20
+ <path d="M53.47,64.35c-0.41-0.41-0.61-0.89-0.61-1.46v-0.16c0-0.57,0.2-1.06,0.61-1.46c0.41-0.41,0.89-0.61,1.46-0.61&#xA;&#9;&#9;&#9;h0.24c0.57,0,1.06,0.2,1.46,0.61s0.61,0.89,0.61,1.46v0.16c0,0.57-0.2,1.06-0.61,1.46c-0.41,0.41-0.89,0.61-1.46,0.61h-0.24&#xA;&#9;&#9;&#9;C54.37,64.96,53.88,64.76,53.47,64.35z M53.72,89.58c-0.35-0.35-0.53-0.79-0.53-1.3V70.86c0-0.51,0.18-0.96,0.53-1.32&#xA;&#9;&#9;&#9;c0.35-0.37,0.79-0.55,1.3-0.55c0.54,0,0.99,0.18,1.34,0.53c0.35,0.35,0.53,0.8,0.53,1.34v17.43c0,0.51-0.18,0.95-0.55,1.3&#xA;&#9;&#9;&#9;c-0.37,0.35-0.81,0.53-1.32,0.53C54.5,90.11,54.07,89.94,53.72,89.58z" class="st0"/>
21
+ <path d="M68.5,89.69c-0.41-0.28-0.7-0.64-0.89-1.08l-7.07-16.9c-0.14-0.32-0.2-0.61-0.2-0.85&#xA;&#9;&#9;&#9;c0-0.51,0.18-0.96,0.53-1.32c0.35-0.37,0.79-0.55,1.3-0.55c0.35,0,0.68,0.1,1,0.3c0.31,0.2,0.53,0.45,0.67,0.75l6.22,15.76&#xA;&#9;&#9;&#9;l6.22-15.76c0.14-0.3,0.36-0.55,0.67-0.75c0.31-0.2,0.64-0.3,1-0.3c0.51,0,0.95,0.18,1.3,0.55c0.35,0.37,0.53,0.81,0.53,1.32&#xA;&#9;&#9;&#9;c0,0.24-0.07,0.53-0.2,0.85l-7.07,16.9c-0.19,0.43-0.49,0.79-0.89,1.08s-0.85,0.43-1.34,0.43h-0.41&#xA;&#9;&#9;&#9;C69.36,90.11,68.91,89.97,68.5,89.69z" class="st0"/>
22
+ <path d="M83.5,64.35c-0.41-0.41-0.61-0.89-0.61-1.46v-0.16c0-0.57,0.2-1.06,0.61-1.46c0.41-0.41,0.89-0.61,1.46-0.61&#xA;&#9;&#9;&#9;h0.24c0.57,0,1.06,0.2,1.46,0.61s0.61,0.89,0.61,1.46v0.16c0,0.57-0.2,1.06-0.61,1.46c-0.41,0.41-0.89,0.61-1.46,0.61h-0.24&#xA;&#9;&#9;&#9;C84.39,64.96,83.9,64.76,83.5,64.35z M83.74,89.58c-0.35-0.35-0.53-0.79-0.53-1.3V70.86c0-0.51,0.18-0.96,0.53-1.32&#xA;&#9;&#9;&#9;c0.35-0.37,0.79-0.55,1.3-0.55c0.54,0,0.99,0.18,1.34,0.53c0.35,0.35,0.53,0.8,0.53,1.34v17.43c0,0.51-0.18,0.95-0.55,1.3&#xA;&#9;&#9;&#9;c-0.37,0.35-0.81,0.53-1.32,0.53C84.53,90.11,84.09,89.94,83.74,89.58z" class="st0"/>
23
+ <path d="M97.65,88.55c-2.15-1.18-3.85-2.87-5.08-5.08c-1.23-2.21-1.85-4.79-1.85-7.74s0.62-5.53,1.85-7.74&#xA;&#9;&#9;&#9;c1.23-2.21,2.93-3.9,5.08-5.08c2.15-1.18,4.58-1.77,7.29-1.77c1.84,0,3.49,0.22,4.94,0.65c1.45,0.43,2.89,1.06,4.33,1.87&#xA;&#9;&#9;&#9;c0.6,0.32,0.89,0.84,0.89,1.54c0,0.41-0.15,0.77-0.45,1.08c-0.3,0.31-0.69,0.47-1.18,0.47c-0.27,0-0.51-0.05-0.73-0.16&#xA;&#9;&#9;&#9;c-1.19-0.62-2.36-1.1-3.49-1.42c-1.14-0.32-2.45-0.49-3.94-0.49c-2.33,0-4.31,0.48-5.95,1.44c-1.64,0.96-2.87,2.28-3.7,3.94&#xA;&#9;&#9;&#9;c-0.83,1.67-1.24,3.55-1.24,5.67s0.41,4,1.24,5.67c0.83,1.67,2.06,2.98,3.7,3.94c1.64,0.96,3.62,1.44,5.95,1.44&#xA;&#9;&#9;&#9;c1.49,0,2.8-0.16,3.94-0.49c1.14-0.32,2.3-0.8,3.49-1.42c0.22-0.11,0.46-0.16,0.73-0.16c0.49,0,0.88,0.15,1.18,0.45&#xA;&#9;&#9;&#9;c0.3,0.3,0.45,0.66,0.45,1.1c0,0.7-0.3,1.22-0.89,1.54c-1.44,0.81-2.88,1.44-4.33,1.87c-1.45,0.43-3.09,0.65-4.94,0.65&#xA;&#9;&#9;&#9;C102.24,90.32,99.81,89.73,97.65,88.55z" class="st0"/>
24
+ <path d="M119.9,89.58c-0.35-0.35-0.53-0.79-0.53-1.3V63.42c0-0.51,0.18-0.96,0.53-1.32s0.79-0.55,1.3-0.55h9.47&#xA;&#9;&#9;&#9;c3.68,0,6.45,0.76,8.29,2.28c1.84,1.52,2.76,3.51,2.76,5.97c0,1.62-0.45,3.11-1.36,4.45c-0.91,1.34-2.23,2.31-3.96,2.9&#xA;&#9;&#9;&#9;c1.95,0.51,3.28,1.73,4,3.64c0.72,1.91,1.08,3.79,1.08,5.63v1.87c0,0.51-0.18,0.95-0.53,1.3c-0.35,0.35-0.79,0.53-1.3,0.53&#xA;&#9;&#9;&#9;c-0.57,0-1.02-0.17-1.36-0.51c-0.34-0.34-0.51-0.78-0.51-1.32v-1.22c0-1.35-0.12-2.61-0.37-3.76s-0.83-2.18-1.75-3.09&#xA;&#9;&#9;&#9;c-0.92-0.91-2.32-1.36-4.18-1.36h-8.41v9.43c0,0.51-0.18,0.95-0.55,1.3s-0.81,0.53-1.32,0.53&#xA;&#9;&#9;&#9;C120.68,90.11,120.25,89.94,119.9,89.58z M130.42,75.37c2.33,0,4.18-0.46,5.55-1.38c1.37-0.92,2.05-2.22,2.05-3.9&#xA;&#9;&#9;&#9;c0-1.62-0.59-2.87-1.77-3.74c-1.18-0.87-3.19-1.3-6.03-1.3h-7.15v10.32H130.42z" class="st0"/>
25
+ <path d="M146.71,89.58c-0.35-0.35-0.53-0.79-0.53-1.3V64.03c0-0.73,0.26-1.36,0.77-1.89&#xA;&#9;&#9;&#9;c0.51-0.53,1.14-0.79,1.87-0.79h1.34c0.54,0,1.04,0.16,1.48,0.49c0.45,0.33,0.78,0.73,1,1.22l9.22,22.99l9.22-22.99&#xA;&#9;&#9;&#9;c0.22-0.49,0.55-0.89,1-1.22c0.45-0.32,0.94-0.49,1.48-0.49h1.34c0.73,0,1.35,0.26,1.87,0.79c0.51,0.53,0.77,1.16,0.77,1.89v24.25&#xA;&#9;&#9;&#9;c0,0.51-0.18,0.95-0.53,1.3c-0.35,0.35-0.79,0.53-1.3,0.53c-0.52,0-0.96-0.18-1.32-0.53c-0.37-0.35-0.55-0.79-0.55-1.3V65.21&#xA;&#9;&#9;&#9;l-9.38,23.2c-0.22,0.51-0.56,0.93-1.04,1.24c-0.47,0.31-1,0.47-1.56,0.47s-1.09-0.16-1.56-0.47c-0.47-0.31-0.82-0.72-1.04-1.24&#xA;&#9;&#9;&#9;l-9.38-23.2v23.08c0,0.51-0.18,0.95-0.55,1.3s-0.81,0.53-1.32,0.53C147.5,90.11,147.06,89.94,146.71,89.58z" class="st0"/>
26
+ </g>
27
+ </g>
28
+ </svg>
@@ -0,0 +1,9 @@
1
+ import type { INodeProperties } from 'n8n-workflow';
2
+ export const genericFields: INodeProperties[] = [
3
+ { displayName: 'Return All', name: 'returnAll', type: 'boolean', default: false, displayOptions: { show: { operation: ['getMany'] } } },
4
+ { displayName: 'Limit', name: 'limit', type: 'number', typeOptions: { minValue: 1, maxValue: 1000 }, default: 100, displayOptions: { show: { operation: ['getMany'], returnAll: [false] } } },
5
+ { displayName: 'Where (JSON)', name: 'whereJson', type: 'string', default: '', placeholder: `[["first_name","=","Alice"]]`, displayOptions: { show: { operation: ['getMany'] } } },
6
+ ];
7
+ export const upsertFields: INodeProperties[] = [
8
+ { displayName: 'Fields', name: 'fields', type: 'fixedCollection', typeOptions: { multipleValues: true }, default: {}, options: [{ name:'field', displayName:'Field', values:[{displayName:'Name',name:'fieldName',type:'string',default:''},{displayName:'Value',name:'fieldValue',type:'string',default:''}]}], displayOptions: { show: { operation: ['create','update'] } } }
9
+ ];
@@ -0,0 +1,35 @@
1
+ import type { INodeProperties } from 'n8n-workflow';
2
+
3
+ export const resourceProp: INodeProperties = {
4
+ displayName: 'Resource',
5
+ name: 'resource',
6
+ type: 'options',
7
+ default: 'contact',
8
+ options: [
9
+ { name: 'Contact', value: 'contact' },
10
+ { name: 'Event', value: 'event' },
11
+ { name: 'Case', value: 'case' },
12
+ { name: 'Contribution', value: 'contribution' },
13
+ { name: 'Membership', value: 'membership' },
14
+ { name: 'Participant', value: 'participant' },
15
+ { name: 'Group', value: 'group' },
16
+ { name: 'Relationship', value: 'relationship' },
17
+ { name: 'Email', value: 'email' },
18
+ { name: 'Activity', value: 'activity' },
19
+ { name: 'Custom API Call', value: 'customApi' },
20
+ ],
21
+ };
22
+
23
+ export const operationProp: INodeProperties = {
24
+ displayName: 'Operation',
25
+ name: 'operation',
26
+ type: 'options',
27
+ default: 'getMany',
28
+ options: [
29
+ { name: 'Create', value: 'create' },
30
+ { name: 'Delete', value: 'delete' },
31
+ { name: 'Get', value: 'get' },
32
+ { name: 'Get Many', value: 'getMany' },
33
+ { name: 'Update', value: 'update' },
34
+ ],
35
+ };
@@ -0,0 +1,51 @@
1
+ import type { IExecuteFunctions, IHttpRequestOptions, JsonObject } from 'n8n-workflow';
2
+ import { NodeApiError } from 'n8n-workflow';
3
+
4
+ /**
5
+ * Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
6
+ * Usa form-urlencoded con el campo "params" serializado
7
+ */
8
+ export async function civicrmApiRequest(
9
+ this: IExecuteFunctions,
10
+ method: 'POST',
11
+ path: string,
12
+ body: Record<string, unknown>,
13
+ ) {
14
+ const { baseUrl, apiToken } = (await this.getCredentials('civiCrmApi')) as {
15
+ baseUrl: string;
16
+ apiToken: string;
17
+ };
18
+
19
+ const options: IHttpRequestOptions = {
20
+ method,
21
+ url: `${baseUrl.replace(/\/$/, '')}${path}`,
22
+ headers: {
23
+ 'Content-Type': 'application/x-www-form-urlencoded',
24
+ 'X-Civi-Auth': `Bearer ${apiToken}`,
25
+ },
26
+ // cuerpo plano como espera Civi-Go
27
+ body: {
28
+ params: JSON.stringify(body.params ?? body),
29
+ },
30
+ json: true,
31
+ };
32
+
33
+ try {
34
+ const response = await this.helpers.httpRequest(options);
35
+ return response;
36
+ } catch (error: unknown) {
37
+ throw new NodeApiError(this.getNode(), error as JsonObject);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
43
+ */
44
+ export function api4(
45
+ entity: string,
46
+ action: string,
47
+ params: Record<string, unknown> = {},
48
+ ) {
49
+ // devolvemos los parámetros planos, no anidados
50
+ return params;
51
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ixiam/n8n-nodes-civicrm",
3
- "version": "0.2.4",
4
- "description": "CiviCRM API v4 for n8n",
3
+ "version": "0.3.8",
4
+ "description": "CiviCRM API v4",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "n8n-community-node-package",
@@ -10,12 +10,6 @@
10
10
  ],
11
11
  "main": "dist/index.js",
12
12
  "types": "dist/index.d.ts",
13
- "files": [
14
- "dist",
15
- "icons",
16
- "README.md",
17
- "LICENSE"
18
- ],
19
13
  "scripts": {
20
14
  "dev": "n8n-node dev",
21
15
  "build": "n8n-node build",
@@ -30,17 +24,6 @@
30
24
  "dist/credentials/CiviCrmApi.credentials.js"
31
25
  ]
32
26
  },
33
- "publishConfig": {
34
- "access": "public"
35
- },
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://git.ixiam.com/dev/research.git"
39
- },
40
- "bugs": {
41
- "url": "https://git.ixiam.com/dev/research/issues"
42
- },
43
- "homepage": "https://git.ixiam.com/dev/research#readme",
44
27
  "devDependencies": {
45
28
  "@n8n/node-cli": "0.11.0",
46
29
  "@types/node": "^20.11.30",
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["es2020"],
4
+ "module": "commonjs",
5
+ "target": "es2020",
6
+ "declaration": true,
7
+ "outDir": "dist",
8
+ "rootDir": ".",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "resolveJsonModule": true,
12
+ "skipLibCheck": true
13
+ },
14
+ "include": ["nodes/**/*.ts", "credentials/**/*.ts"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }