@ixiam/n8n-nodes-civicrm 0.3.4 → 0.3.9

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/README.md CHANGED
@@ -9,4 +9,5 @@ Credentials:
9
9
  - Use the **Save** button to verify connectivity.
10
10
 
11
11
  Entities: Contact, Event, Case, Contribution, Membership → `get|getMany|create|update|delete`
12
- Form Processor: `execute` with `recordsJson`
12
+
13
+ Node developed by Ixiam Global Solution: `https://www.ixiam.com'
@@ -35,6 +35,21 @@ class CiviCrm {
35
35
  properties: [
36
36
  resources_1.resourceProp,
37
37
  resources_1.operationProp,
38
+ {
39
+ displayName: 'Contact Type',
40
+ name: 'contactType',
41
+ type: 'options',
42
+ default: 'Individual',
43
+ options: [
44
+ { name: 'Individual', value: 'Individual' },
45
+ { name: 'Organization', value: 'Organization' },
46
+ { name: 'Household', value: 'Household' },
47
+ ],
48
+ displayOptions: {
49
+ show: { resource: ['contact'] },
50
+ },
51
+ description: 'Filter or assign contact type',
52
+ },
38
53
  {
39
54
  displayName: 'ID',
40
55
  name: 'id',
@@ -62,10 +77,9 @@ class CiviCrm {
62
77
  body: {
63
78
  params: JSON.stringify({ limit: 5 }),
64
79
  },
65
- json: false,
80
+ json: true,
66
81
  });
67
- const parsed = JSON.parse(res);
68
- const values = (parsed?.values || []);
82
+ const values = (res?.values || []);
69
83
  return values.map((v) => ({
70
84
  name: v.label,
71
85
  value: v.id,
@@ -84,7 +98,45 @@ class CiviCrm {
84
98
  // === GET ===
85
99
  if (operation === 'get') {
86
100
  const id = this.getNodeParameter('id', i);
87
- 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 }));
101
+ const contactType = this.getNodeParameter('contactType', i, '');
102
+ const where = [['id', '=', id]];
103
+ if (resource === 'contact' && contactType) {
104
+ where.push(['contact_type', '=', contactType]);
105
+ }
106
+ let params;
107
+ if (resource === 'contact') {
108
+ params = {
109
+ where,
110
+ limit: 1,
111
+ select: [
112
+ 'id',
113
+ 'display_name',
114
+ 'first_name',
115
+ 'last_name',
116
+ 'contact_type',
117
+ 'email.email',
118
+ 'phone.phone',
119
+ 'address.city',
120
+ 'address.country_id:label',
121
+ 'address.postal_code',
122
+ 'address.street_address',
123
+ ],
124
+ join: [
125
+ ['Email AS email', 'LEFT'],
126
+ ['Phone AS phone', 'LEFT'],
127
+ ['Address AS address', 'LEFT'],
128
+ ],
129
+ };
130
+ }
131
+ else {
132
+ // otras entidades: select básico
133
+ params = {
134
+ where,
135
+ limit: 1,
136
+ select: ['id', 'title', 'subject', 'display_name', 'name'],
137
+ };
138
+ }
139
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, params);
88
140
  out.push({ json: (res?.values?.[0] ?? {}) });
89
141
  }
90
142
  // === GET MANY ===
@@ -92,12 +144,43 @@ class CiviCrm {
92
144
  const returnAll = this.getNodeParameter('returnAll', i, false);
93
145
  const limit = this.getNodeParameter('limit', i, 100);
94
146
  const whereJson = this.getNodeParameter('whereJson', i, '');
95
- const where = whereJson ? JSON.parse(whereJson) : undefined;
147
+ const contactType = this.getNodeParameter('contactType', i, '');
148
+ let where = whereJson ? JSON.parse(whereJson) : [];
149
+ if (resource === 'contact' && contactType) {
150
+ where.push(['contact_type', '=', contactType]);
151
+ }
152
+ let baseParams;
153
+ if (resource === 'contact') {
154
+ baseParams = {
155
+ where,
156
+ select: [
157
+ 'id',
158
+ 'display_name',
159
+ 'first_name',
160
+ 'last_name',
161
+ 'contact_type',
162
+ 'email.email',
163
+ 'phone.phone',
164
+ 'address.city',
165
+ 'address.country_id:label',
166
+ 'address.postal_code',
167
+ 'address.street_address',
168
+ ],
169
+ join: [
170
+ ['Email AS email', 'LEFT'],
171
+ ['Phone AS phone', 'LEFT'],
172
+ ['Address AS address', 'LEFT'],
173
+ ],
174
+ };
175
+ }
176
+ else {
177
+ baseParams = { where, select: ['id', 'title', 'subject', 'display_name', 'name'] };
178
+ }
96
179
  if (returnAll) {
97
180
  let offset = 0;
98
181
  const page = 500;
99
182
  while (true) {
100
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, (0, GenericFunctions_1.api4)(entity, 'get', { where, limit: page, offset }));
183
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit: page, offset });
101
184
  const vals = (res?.values ?? []);
102
185
  for (const v of vals)
103
186
  out.push({ json: v });
@@ -107,7 +190,7 @@ class CiviCrm {
107
190
  }
108
191
  }
109
192
  else {
110
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, (0, GenericFunctions_1.api4)(entity, 'get', { where, limit }));
193
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/get`, { ...baseParams, limit });
111
194
  const vals = (res?.values ?? []);
112
195
  for (const v of vals)
113
196
  out.push({ json: v });
@@ -116,29 +199,42 @@ class CiviCrm {
116
199
  // === CREATE ===
117
200
  if (operation === 'create') {
118
201
  const pairs = this.getNodeParameter('fields.field', i, []);
119
- const params = Object.fromEntries(pairs
202
+ const values = Object.fromEntries(pairs
120
203
  .filter((p) => p.fieldName)
121
204
  .map((p) => [p.fieldName, convertValue(p.fieldValue)]));
122
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, (0, GenericFunctions_1.api4)(entity, 'create', params));
205
+ const contactType = this.getNodeParameter('contactType', i, '');
206
+ if (resource === 'contact' && contactType) {
207
+ values.contact_type = contactType;
208
+ }
209
+ const params = { values };
210
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, params);
123
211
  out.push({ json: res });
124
212
  }
125
213
  // === UPDATE ===
126
214
  if (operation === 'update') {
127
215
  const id = this.getNodeParameter('id', i);
128
216
  const pairs = this.getNodeParameter('fields.field', i, []);
217
+ const values = Object.fromEntries(pairs
218
+ .filter((p) => p.fieldName)
219
+ .map((p) => [p.fieldName, convertValue(p.fieldValue)]));
220
+ const contactType = this.getNodeParameter('contactType', i, '');
221
+ if (resource === 'contact' && contactType) {
222
+ values.contact_type = contactType;
223
+ }
129
224
  const params = {
130
- id,
131
- ...Object.fromEntries(pairs
132
- .filter((p) => p.fieldName)
133
- .map((p) => [p.fieldName, convertValue(p.fieldValue)])),
225
+ values,
226
+ where: [['id', '=', id]],
134
227
  };
135
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, (0, GenericFunctions_1.api4)(entity, 'update', params));
228
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, params);
136
229
  out.push({ json: res });
137
230
  }
138
231
  // === DELETE ===
139
232
  if (operation === 'delete') {
140
233
  const id = this.getNodeParameter('id', i);
141
- const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, (0, GenericFunctions_1.api4)(entity, 'delete', { id }));
234
+ const params = {
235
+ where: [['id', '=', id]],
236
+ };
237
+ const res = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, params);
142
238
  out.push({ json: res });
143
239
  }
144
240
  }
@@ -167,5 +263,5 @@ function convertValue(val) {
167
263
  catch { }
168
264
  return val;
169
265
  }
170
- // 👇 ESTA LÍNEA ES NECESARIA EN n8n >=1.110
266
+ // Requerido por n8n >=1.110
171
267
  exports.default = CiviCrm;
@@ -1,10 +1,10 @@
1
1
  import type { IExecuteFunctions } from 'n8n-workflow';
2
2
  /**
3
- * Ejecuta una llamada a la API de CiviCRM v4 (form-urlencoded, formato Civi-Go)
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 esperado por Civi-Go
8
- * Solo los parámetros planos: where, limit, select...
8
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
9
9
  */
10
10
  export declare function api4(entity: string, action: string, params?: Record<string, unknown>): Record<string, unknown>;
@@ -3,7 +3,8 @@ 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 (form-urlencoded, formato Civi-Go)
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'));
@@ -14,11 +15,11 @@ async function civicrmApiRequest(method, path, body) {
14
15
  'Content-Type': 'application/x-www-form-urlencoded',
15
16
  'X-Civi-Auth': `Bearer ${apiToken}`,
16
17
  },
17
- // Civi-Go exige el campo 'params' con el JSON serializado
18
+ // cuerpo plano como espera Civi-Go
18
19
  body: {
19
- params: JSON.stringify(body),
20
+ params: JSON.stringify(body.params ?? body),
20
21
  },
21
- json: true, // importante: dejar que n8n maneje el parseo
22
+ json: true,
22
23
  };
23
24
  try {
24
25
  const response = await this.helpers.httpRequest(options);
@@ -30,10 +31,10 @@ async function civicrmApiRequest(method, path, body) {
30
31
  }
31
32
  exports.civicrmApiRequest = civicrmApiRequest;
32
33
  /**
33
- * Devuelve el formato esperado por Civi-Go
34
- * Solo los parámetros planos: where, limit, select...
34
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
35
35
  */
36
36
  function api4(entity, action, params = {}) {
37
+ // devolvemos los parámetros planos, no anidados
37
38
  return params;
38
39
  }
39
40
  exports.api4 = api4;
@@ -8,7 +8,7 @@ import type {
8
8
  IDataObject,
9
9
  } from 'n8n-workflow';
10
10
 
11
- import { civicrmApiRequest, api4 } from '../transport/GenericFunctions';
11
+ import { civicrmApiRequest } from '../transport/GenericFunctions';
12
12
  import { resourceProp, operationProp } from './descriptions/resources';
13
13
  import { genericFields, upsertFields } from './descriptions/generic';
14
14
 
@@ -40,7 +40,6 @@ const ENTITY_MAP: Record<Resource, string> = {
40
40
  activity: 'Activity',
41
41
  };
42
42
 
43
-
44
43
  type Operation = 'get' | 'getMany' | 'create' | 'update' | 'delete';
45
44
 
46
45
  /**
@@ -61,6 +60,21 @@ export class CiviCrm implements INodeType {
61
60
  properties: [
62
61
  resourceProp,
63
62
  operationProp,
63
+ {
64
+ displayName: 'Contact Type',
65
+ name: 'contactType',
66
+ type: 'options',
67
+ default: 'Individual',
68
+ options: [
69
+ { name: 'Individual', value: 'Individual' },
70
+ { name: 'Organization', value: 'Organization' },
71
+ { name: 'Household', value: 'Household' },
72
+ ],
73
+ displayOptions: {
74
+ show: { resource: ['contact'] },
75
+ },
76
+ description: 'Filter or assign contact type',
77
+ },
64
78
  {
65
79
  displayName: 'ID',
66
80
  name: 'id',
@@ -94,11 +108,10 @@ export class CiviCrm implements INodeType {
94
108
  body: {
95
109
  params: JSON.stringify({ limit: 5 }),
96
110
  },
97
- json: false,
111
+ json: true,
98
112
  });
99
113
 
100
- const parsed = JSON.parse(res);
101
- const values = (parsed?.values || []) as Array<{ id: number; label: string }>;
114
+ const values = (res?.values || []) as Array<{ id: number; label: string }>;
102
115
  return values.map((v): INodePropertyOptions => ({
103
116
  name: v.label,
104
117
  value: v.id,
@@ -116,51 +129,127 @@ export class CiviCrm implements INodeType {
116
129
  const entity = ENTITY_MAP[resource];
117
130
 
118
131
  for (let i = 0; i < items.length; i++) {
119
- // === GET ===
120
- if (operation === 'get') {
121
- const id = this.getNodeParameter('id', i) as number;
122
- const res = await civicrmApiRequest.call(
123
- this,
124
- 'POST',
125
- `/civicrm/ajax/api4/${entity}/get`,
126
- api4(entity, 'get', { where: [['id', '=', id]], limit: 1 }),
127
- );
128
- out.push({ json: (res?.values?.[0] ?? {}) as IDataObject });
129
- }
130
132
 
131
- // === GET MANY ===
132
- if (operation === 'getMany') {
133
- const returnAll = this.getNodeParameter('returnAll', i, false) as boolean;
134
- const limit = this.getNodeParameter('limit', i, 100) as number;
135
- const whereJson = this.getNodeParameter('whereJson', i, '') as string;
136
- const where = whereJson ? JSON.parse(whereJson) : undefined;
137
-
138
- if (returnAll) {
139
- let offset = 0;
140
- const page = 500;
141
- while (true) {
142
- const res = await civicrmApiRequest.call(
143
- this,
144
- 'POST',
145
- `/civicrm/ajax/api4/${entity}/get`,
146
- api4(entity, 'get', { where, limit: page, offset }),
147
- );
148
- const vals = (res?.values ?? []) as IDataObject[];
149
- for (const v of vals) out.push({ json: v });
150
- if (vals.length < page) break;
151
- offset += page;
152
- }
153
- } else {
154
- const res = await civicrmApiRequest.call(
155
- this,
156
- 'POST',
157
- `/civicrm/ajax/api4/${entity}/get`,
158
- api4(entity, 'get', { where, limit }),
159
- );
160
- const vals = (res?.values ?? []) as IDataObject[];
161
- for (const v of vals) out.push({ json: v });
162
- }
163
- }
133
+ // === GET ===
134
+ if (operation === 'get') {
135
+ const id = this.getNodeParameter('id', i) as number;
136
+ const contactType = this.getNodeParameter('contactType', i, '') as string;
137
+
138
+ const where = [['id', '=', id]];
139
+ if (resource === 'contact' && contactType) {
140
+ where.push(['contact_type', '=', contactType]);
141
+ }
142
+
143
+ let params: Record<string, unknown>;
144
+
145
+ if (resource === 'contact') {
146
+ params = {
147
+ where,
148
+ limit: 1,
149
+ select: [
150
+ 'id',
151
+ 'display_name',
152
+ 'first_name',
153
+ 'last_name',
154
+ 'contact_type',
155
+ 'email.email',
156
+ 'phone.phone',
157
+ 'address.city',
158
+ 'address.country_id:label',
159
+ 'address.postal_code',
160
+ 'address.street_address',
161
+ ],
162
+ join: [
163
+ ['Email AS email', 'LEFT'],
164
+ ['Phone AS phone', 'LEFT'],
165
+ ['Address AS address', 'LEFT'],
166
+ ],
167
+ };
168
+ } else {
169
+ // otras entidades: select básico
170
+ params = {
171
+ where,
172
+ limit: 1,
173
+ select: ['id', 'title', 'subject', 'display_name', 'name'],
174
+ };
175
+ }
176
+
177
+ const res = await civicrmApiRequest.call(
178
+ this,
179
+ 'POST',
180
+ `/civicrm/ajax/api4/${entity}/get`,
181
+ params,
182
+ );
183
+
184
+ out.push({ json: (res?.values?.[0] ?? {}) as IDataObject });
185
+ }
186
+
187
+ // === GET MANY ===
188
+ if (operation === 'getMany') {
189
+ const returnAll = this.getNodeParameter('returnAll', i, false) as boolean;
190
+ const limit = this.getNodeParameter('limit', i, 100) as number;
191
+ const whereJson = this.getNodeParameter('whereJson', i, '') as string;
192
+ const contactType = this.getNodeParameter('contactType', i, '') as string;
193
+
194
+ let where = whereJson ? JSON.parse(whereJson) : [];
195
+ if (resource === 'contact' && contactType) {
196
+ where.push(['contact_type', '=', contactType]);
197
+ }
198
+
199
+ let baseParams: Record<string, unknown>;
200
+
201
+ if (resource === 'contact') {
202
+ baseParams = {
203
+ where,
204
+ select: [
205
+ 'id',
206
+ 'display_name',
207
+ 'first_name',
208
+ 'last_name',
209
+ 'contact_type',
210
+ 'email.email',
211
+ 'phone.phone',
212
+ 'address.city',
213
+ 'address.country_id:label',
214
+ 'address.postal_code',
215
+ 'address.street_address',
216
+ ],
217
+ join: [
218
+ ['Email AS email', 'LEFT'],
219
+ ['Phone AS phone', 'LEFT'],
220
+ ['Address AS address', 'LEFT'],
221
+ ],
222
+ };
223
+ } else {
224
+ baseParams = { where, select: ['id', 'title', 'subject', 'display_name', 'name'] };
225
+ }
226
+
227
+ if (returnAll) {
228
+ let offset = 0;
229
+ const page = 500;
230
+ while (true) {
231
+ const res = await civicrmApiRequest.call(
232
+ this,
233
+ 'POST',
234
+ `/civicrm/ajax/api4/${entity}/get`,
235
+ { ...baseParams, limit: page, offset },
236
+ );
237
+ const vals = (res?.values ?? []) as IDataObject[];
238
+ for (const v of vals) out.push({ json: v });
239
+ if (vals.length < page) break;
240
+ offset += page;
241
+ }
242
+ } else {
243
+ const res = await civicrmApiRequest.call(
244
+ this,
245
+ 'POST',
246
+ `/civicrm/ajax/api4/${entity}/get`,
247
+ { ...baseParams, limit },
248
+ );
249
+ const vals = (res?.values ?? []) as IDataObject[];
250
+ for (const v of vals) out.push({ json: v });
251
+ }
252
+ }
164
253
 
165
254
  // === CREATE ===
166
255
  if (operation === 'create') {
@@ -168,16 +257,25 @@ export class CiviCrm implements INodeType {
168
257
  fieldName: string;
169
258
  fieldValue: string;
170
259
  }>;
171
- const params = Object.fromEntries(
260
+
261
+ const values = Object.fromEntries(
172
262
  pairs
173
263
  .filter((p) => p.fieldName)
174
264
  .map((p) => [p.fieldName, convertValue(p.fieldValue)]),
175
265
  );
266
+
267
+ const contactType = this.getNodeParameter('contactType', i, '') as string;
268
+ if (resource === 'contact' && contactType) {
269
+ values.contact_type = contactType;
270
+ }
271
+
272
+ const params = { values };
273
+
176
274
  const res = await civicrmApiRequest.call(
177
275
  this,
178
276
  'POST',
179
277
  `/civicrm/ajax/api4/${entity}/create`,
180
- api4(entity, 'create', params),
278
+ params,
181
279
  );
182
280
  out.push({ json: res as IDataObject });
183
281
  }
@@ -189,19 +287,28 @@ export class CiviCrm implements INodeType {
189
287
  fieldName: string;
190
288
  fieldValue: string;
191
289
  }>;
290
+
291
+ const values = Object.fromEntries(
292
+ pairs
293
+ .filter((p) => p.fieldName)
294
+ .map((p) => [p.fieldName, convertValue(p.fieldValue)]),
295
+ );
296
+
297
+ const contactType = this.getNodeParameter('contactType', i, '') as string;
298
+ if (resource === 'contact' && contactType) {
299
+ values.contact_type = contactType;
300
+ }
301
+
192
302
  const params = {
193
- id,
194
- ...Object.fromEntries(
195
- pairs
196
- .filter((p) => p.fieldName)
197
- .map((p) => [p.fieldName, convertValue(p.fieldValue)]),
198
- ),
303
+ values,
304
+ where: [['id', '=', id]],
199
305
  };
306
+
200
307
  const res = await civicrmApiRequest.call(
201
308
  this,
202
309
  'POST',
203
310
  `/civicrm/ajax/api4/${entity}/update`,
204
- api4(entity, 'update', params),
311
+ params,
205
312
  );
206
313
  out.push({ json: res as IDataObject });
207
314
  }
@@ -209,11 +316,16 @@ export class CiviCrm implements INodeType {
209
316
  // === DELETE ===
210
317
  if (operation === 'delete') {
211
318
  const id = this.getNodeParameter('id', i) as number;
319
+
320
+ const params = {
321
+ where: [['id', '=', id]],
322
+ };
323
+
212
324
  const res = await civicrmApiRequest.call(
213
325
  this,
214
326
  'POST',
215
327
  `/civicrm/ajax/api4/${entity}/delete`,
216
- api4(entity, 'delete', { id }),
328
+ params,
217
329
  );
218
330
  out.push({ json: res as IDataObject });
219
331
  }
@@ -239,5 +351,5 @@ function convertValue(val: string): unknown {
239
351
  return val;
240
352
  }
241
353
 
242
- // 👇 ESTA LÍNEA ES NECESARIA EN n8n >=1.110
354
+ // Requerido por n8n >=1.110
243
355
  export default CiviCrm;
@@ -2,7 +2,8 @@ import type { IExecuteFunctions, IHttpRequestOptions, JsonObject } from 'n8n-wor
2
2
  import { NodeApiError } from 'n8n-workflow';
3
3
 
4
4
  /**
5
- * Ejecuta una llamada a la API de CiviCRM v4 (form-urlencoded, formato Civi-Go)
5
+ * Ejecuta una llamada a la API de CiviCRM v4 (Civi-Go)
6
+ * Usa form-urlencoded con el campo "params" serializado
6
7
  */
7
8
  export async function civicrmApiRequest(
8
9
  this: IExecuteFunctions,
@@ -22,11 +23,11 @@ export async function civicrmApiRequest(
22
23
  'Content-Type': 'application/x-www-form-urlencoded',
23
24
  'X-Civi-Auth': `Bearer ${apiToken}`,
24
25
  },
25
- // Civi-Go exige el campo 'params' con el JSON serializado
26
+ // cuerpo plano como espera Civi-Go
26
27
  body: {
27
- params: JSON.stringify(body),
28
+ params: JSON.stringify(body.params ?? body),
28
29
  },
29
- json: true, // importante: dejar que n8n maneje el parseo
30
+ json: true,
30
31
  };
31
32
 
32
33
  try {
@@ -38,13 +39,13 @@ export async function civicrmApiRequest(
38
39
  }
39
40
 
40
41
  /**
41
- * Devuelve el formato esperado por Civi-Go
42
- * Solo los parámetros planos: where, limit, select...
42
+ * Devuelve el cuerpo estándar para las llamadas API4 (plano)
43
43
  */
44
44
  export function api4(
45
45
  entity: string,
46
46
  action: string,
47
47
  params: Record<string, unknown> = {},
48
48
  ) {
49
+ // devolvemos los parámetros planos, no anidados
49
50
  return params;
50
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixiam/n8n-nodes-civicrm",
3
- "version": "0.3.4",
3
+ "version": "0.3.9",
4
4
  "description": "CiviCRM API v4",
5
5
  "license": "MIT",
6
6
  "keywords": [