@ixiam/n8n-nodes-civicrm 3.2.0 → 3.2.3
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
|
@@ -76,11 +76,14 @@ Time-bounded tokens for enhanced security. **Contact ID is automatically resolve
|
|
|
76
76
|
|
|
77
77
|
> **Note on warnings vs. results:** When JWT auth is enabled but the token can't be obtained (e.g. AuthX disabled or misconfigured on the CiviCRM side), the node still returns data — it silently retries the same request with the API Key. You'll see a **warning in the node's output pane** explaining why JWT wasn't used, but the workflow does not fail and the query results are still shown. This is intentional: JWT failures never break a workflow, they only fall back to API Key auth and surface a non-blocking warning.
|
|
78
78
|
|
|
79
|
+
> **Troubleshooting "JWT authentication could not be obtained (no token returned by CiviCRM)":** This message covers several distinct failures on the CiviCRM side (Contact lookup by API Key failed, or `AuthxCredential.create` was denied), so it doesn't say which one occurred. The most common cause is a missing permission: the Contact that owns the API Key must have the **"AuthX: Generate new JWT credentials for other users via the API"** permission on their role — see [JWT Setup Requirements](#jwt-setup-requirements) above. To confirm which step is failing, call `Contact.get` (filtered by `api_key`) and `AuthxCredential.create` directly against your CiviCRM instance and check the HTTP status/response of each.
|
|
80
|
+
|
|
79
81
|
#### JWT Setup Requirements
|
|
80
82
|
|
|
81
83
|
**CiviCRM Extensions & Settings:**
|
|
82
84
|
- ✓ AuthX extension enabled (CiviCRM 5.48+)
|
|
83
85
|
- ✓ API Key assigned to a Contact record
|
|
86
|
+
- ✓ The Contact's role has the **"AuthX: Generate new JWT credentials for other users via the API"** permission (`generate any authx credential`) — under **Administer → Users and Permissions → Permissions**. Without it, `AuthxCredential.create` returns `403 Authorization failed` and the node silently falls back to API Key auth. Note that having "Administrator"/`administer CiviCRM` does **not** grant this by itself — it must be checked explicitly for the role.
|
|
84
87
|
|
|
85
88
|
**CiviCRM Authentication Configuration**
|
|
86
89
|
|
|
@@ -703,7 +703,7 @@ class CiviCrm {
|
|
|
703
703
|
'for. Leave empty to use the credential (JWT auto-resolve or API key) as before.',
|
|
704
704
|
displayOptions: {
|
|
705
705
|
show: {
|
|
706
|
-
operation: ['get', 'getMany', 'getFields', 'search', 'raw'],
|
|
706
|
+
operation: ['get', 'getMany', 'getFields', 'search', 'raw', 'create', 'update', 'delete'],
|
|
707
707
|
},
|
|
708
708
|
},
|
|
709
709
|
},
|
|
@@ -753,11 +753,16 @@ class CiviCrm {
|
|
|
753
753
|
try {
|
|
754
754
|
// Per-execution JWT for a specific real user (issue #25 - permissions
|
|
755
755
|
// by real user via Authx), read once per item so it can come from an
|
|
756
|
-
// expression like ={{ $json.user_jwt }}.
|
|
757
|
-
//
|
|
758
|
-
//
|
|
759
|
-
//
|
|
760
|
-
//
|
|
756
|
+
// expression like ={{ $json.user_jwt }}. Threaded into every
|
|
757
|
+
// operation this parameter is exposed for - get/getMany/getFields/
|
|
758
|
+
// search/raw Custom API Call, and (issue #30 fix) the fixed-resource
|
|
759
|
+
// create/update/delete branches for Contact/Membership/Group/
|
|
760
|
+
// Relationship/Activity below - see civicrmApiRequest for why an
|
|
761
|
+
// empty result with this token must never fall back to the
|
|
762
|
+
// credential's API key. Without this, a write always ran as the
|
|
763
|
+
// client's admin credential regardless of the real logged-in user's
|
|
764
|
+
// actual CiviCRM permissions, defeating the point of issue #25 for
|
|
765
|
+
// every write operation.
|
|
761
766
|
const runtimeBearerToken = this.getNodeParameter('runtimeBearerToken', i, '').trim() || undefined;
|
|
762
767
|
// Custom API resource: raw passthrough, plus first-class List Fields /
|
|
763
768
|
// Dynamic Search operations for any API4 entity (not just the 5 fixed
|
|
@@ -994,7 +999,7 @@ class CiviCrm {
|
|
|
994
999
|
const id = this.getNodeParameter('id', i);
|
|
995
1000
|
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/delete`, {
|
|
996
1001
|
where: [['id', '=', id]],
|
|
997
|
-
});
|
|
1002
|
+
}, runtimeBearerToken);
|
|
998
1003
|
out.push({
|
|
999
1004
|
json: {
|
|
1000
1005
|
success: true,
|
|
@@ -1130,7 +1135,7 @@ class CiviCrm {
|
|
|
1130
1135
|
/* CREATE/UPDATE contact */
|
|
1131
1136
|
let contactId = id;
|
|
1132
1137
|
if (isCreate) {
|
|
1133
|
-
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST',
|
|
1138
|
+
const r = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/create`, { values }, runtimeBearerToken);
|
|
1134
1139
|
contactId = (_k = (_j = r === null || r === void 0 ? void 0 : r.values) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.id;
|
|
1135
1140
|
if (!contactId)
|
|
1136
1141
|
throw new Error('Failed to create contact.');
|
|
@@ -1139,7 +1144,7 @@ class CiviCrm {
|
|
|
1139
1144
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', `/civicrm/ajax/api4/${entity}/update`, {
|
|
1140
1145
|
values,
|
|
1141
1146
|
where: [['id', '=', contactId]],
|
|
1142
|
-
});
|
|
1147
|
+
}, runtimeBearerToken);
|
|
1143
1148
|
}
|
|
1144
1149
|
/* SUBENTITIES */
|
|
1145
1150
|
if (resource === 'contact') {
|
|
@@ -1149,7 +1154,7 @@ class CiviCrm {
|
|
|
1149
1154
|
['contact_id', '=', contactId],
|
|
1150
1155
|
['is_primary', '=', true],
|
|
1151
1156
|
],
|
|
1152
|
-
});
|
|
1157
|
+
}, runtimeBearerToken);
|
|
1153
1158
|
}
|
|
1154
1159
|
if (isCreate && isPrimaryPhone) {
|
|
1155
1160
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Phone/delete', {
|
|
@@ -1157,7 +1162,7 @@ class CiviCrm {
|
|
|
1157
1162
|
['contact_id', '=', contactId],
|
|
1158
1163
|
['is_primary', '=', true],
|
|
1159
1164
|
],
|
|
1160
|
-
});
|
|
1165
|
+
}, runtimeBearerToken);
|
|
1161
1166
|
}
|
|
1162
1167
|
if (isCreate && isPrimaryAddress) {
|
|
1163
1168
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Address/delete', {
|
|
@@ -1165,7 +1170,7 @@ class CiviCrm {
|
|
|
1165
1170
|
['contact_id', '=', contactId],
|
|
1166
1171
|
['is_primary', '=', true],
|
|
1167
1172
|
],
|
|
1168
|
-
});
|
|
1173
|
+
}, runtimeBearerToken);
|
|
1169
1174
|
}
|
|
1170
1175
|
if (Object.keys(emailData).length) {
|
|
1171
1176
|
if (isCreate) {
|
|
@@ -1176,7 +1181,7 @@ class CiviCrm {
|
|
|
1176
1181
|
is_primary: isPrimaryEmail,
|
|
1177
1182
|
'location_type_id:name': emailLocationName,
|
|
1178
1183
|
},
|
|
1179
|
-
});
|
|
1184
|
+
}, runtimeBearerToken);
|
|
1180
1185
|
}
|
|
1181
1186
|
else {
|
|
1182
1187
|
const existingEmail = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Email/get', {
|
|
@@ -1186,7 +1191,7 @@ class CiviCrm {
|
|
|
1186
1191
|
],
|
|
1187
1192
|
limit: 1,
|
|
1188
1193
|
select: ['id'],
|
|
1189
|
-
});
|
|
1194
|
+
}, runtimeBearerToken);
|
|
1190
1195
|
const existingEmailId = (_m = (_l = existingEmail === null || existingEmail === void 0 ? void 0 : existingEmail.values) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.id;
|
|
1191
1196
|
if (existingEmailId) {
|
|
1192
1197
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Email/update', {
|
|
@@ -1196,7 +1201,7 @@ class CiviCrm {
|
|
|
1196
1201
|
contact_id: contactId,
|
|
1197
1202
|
is_primary: isPrimaryEmail,
|
|
1198
1203
|
},
|
|
1199
|
-
});
|
|
1204
|
+
}, runtimeBearerToken);
|
|
1200
1205
|
}
|
|
1201
1206
|
else {
|
|
1202
1207
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Email/create', {
|
|
@@ -1206,7 +1211,7 @@ class CiviCrm {
|
|
|
1206
1211
|
is_primary: isPrimaryEmail,
|
|
1207
1212
|
'location_type_id:name': emailLocationName,
|
|
1208
1213
|
},
|
|
1209
|
-
});
|
|
1214
|
+
}, runtimeBearerToken);
|
|
1210
1215
|
}
|
|
1211
1216
|
}
|
|
1212
1217
|
}
|
|
@@ -1219,7 +1224,7 @@ class CiviCrm {
|
|
|
1219
1224
|
is_primary: isPrimaryPhone,
|
|
1220
1225
|
'location_type_id:name': phoneLocationName,
|
|
1221
1226
|
},
|
|
1222
|
-
});
|
|
1227
|
+
}, runtimeBearerToken);
|
|
1223
1228
|
}
|
|
1224
1229
|
else {
|
|
1225
1230
|
const existingPhone = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Phone/get', {
|
|
@@ -1229,7 +1234,7 @@ class CiviCrm {
|
|
|
1229
1234
|
],
|
|
1230
1235
|
limit: 1,
|
|
1231
1236
|
select: ['id'],
|
|
1232
|
-
});
|
|
1237
|
+
}, runtimeBearerToken);
|
|
1233
1238
|
const existingPhoneId = (_p = (_o = existingPhone === null || existingPhone === void 0 ? void 0 : existingPhone.values) === null || _o === void 0 ? void 0 : _o[0]) === null || _p === void 0 ? void 0 : _p.id;
|
|
1234
1239
|
if (existingPhoneId) {
|
|
1235
1240
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Phone/update', {
|
|
@@ -1239,7 +1244,7 @@ class CiviCrm {
|
|
|
1239
1244
|
contact_id: contactId,
|
|
1240
1245
|
is_primary: isPrimaryPhone,
|
|
1241
1246
|
},
|
|
1242
|
-
});
|
|
1247
|
+
}, runtimeBearerToken);
|
|
1243
1248
|
}
|
|
1244
1249
|
else {
|
|
1245
1250
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Phone/create', {
|
|
@@ -1249,7 +1254,7 @@ class CiviCrm {
|
|
|
1249
1254
|
is_primary: isPrimaryPhone,
|
|
1250
1255
|
'location_type_id:name': phoneLocationName,
|
|
1251
1256
|
},
|
|
1252
|
-
});
|
|
1257
|
+
}, runtimeBearerToken);
|
|
1253
1258
|
}
|
|
1254
1259
|
}
|
|
1255
1260
|
}
|
|
@@ -1262,7 +1267,7 @@ class CiviCrm {
|
|
|
1262
1267
|
is_primary: isPrimaryAddress,
|
|
1263
1268
|
'location_type_id:name': addressLocationName,
|
|
1264
1269
|
},
|
|
1265
|
-
});
|
|
1270
|
+
}, runtimeBearerToken);
|
|
1266
1271
|
}
|
|
1267
1272
|
else {
|
|
1268
1273
|
const existingAddress = await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Address/get', {
|
|
@@ -1272,7 +1277,7 @@ class CiviCrm {
|
|
|
1272
1277
|
],
|
|
1273
1278
|
limit: 1,
|
|
1274
1279
|
select: ['id'],
|
|
1275
|
-
});
|
|
1280
|
+
}, runtimeBearerToken);
|
|
1276
1281
|
const existingAddressId = (_r = (_q = existingAddress === null || existingAddress === void 0 ? void 0 : existingAddress.values) === null || _q === void 0 ? void 0 : _q[0]) === null || _r === void 0 ? void 0 : _r.id;
|
|
1277
1282
|
if (existingAddressId) {
|
|
1278
1283
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Address/update', {
|
|
@@ -1282,7 +1287,7 @@ class CiviCrm {
|
|
|
1282
1287
|
contact_id: contactId,
|
|
1283
1288
|
is_primary: isPrimaryAddress,
|
|
1284
1289
|
},
|
|
1285
|
-
});
|
|
1290
|
+
}, runtimeBearerToken);
|
|
1286
1291
|
}
|
|
1287
1292
|
else {
|
|
1288
1293
|
await GenericFunctions_1.civicrmApiRequest.call(this, 'POST', '/civicrm/ajax/api4/Address/create', {
|
|
@@ -1292,7 +1297,7 @@ class CiviCrm {
|
|
|
1292
1297
|
is_primary: isPrimaryAddress,
|
|
1293
1298
|
'location_type_id:name': addressLocationName,
|
|
1294
1299
|
},
|
|
1295
|
-
});
|
|
1300
|
+
}, runtimeBearerToken);
|
|
1296
1301
|
}
|
|
1297
1302
|
}
|
|
1298
1303
|
}
|
|
@@ -1321,7 +1326,7 @@ class CiviCrm {
|
|
|
1321
1326
|
},
|
|
1322
1327
|
}
|
|
1323
1328
|
: {}),
|
|
1324
|
-
});
|
|
1329
|
+
}, runtimeBearerToken);
|
|
1325
1330
|
out.push({
|
|
1326
1331
|
json: (_t = (_s = res === null || res === void 0 ? void 0 : res.values) === null || _s === void 0 ? void 0 : _s[0]) !== null && _t !== void 0 ? _t : {},
|
|
1327
1332
|
pairedItem: { item: i },
|
|
@@ -116,7 +116,6 @@ async function civicrmApiRequest(method, path, body, runtimeBearerToken) {
|
|
|
116
116
|
useJwt = true;
|
|
117
117
|
}
|
|
118
118
|
else {
|
|
119
|
-
console.warn('[CiviCRM] JWT generation returned no token, falling back to API key');
|
|
120
119
|
this.addExecutionHints({
|
|
121
120
|
message: 'JWT authentication could not be obtained (no token returned by CiviCRM). Falling back to API Key authentication.',
|
|
122
121
|
type: 'warning',
|
|
@@ -126,7 +125,6 @@ async function civicrmApiRequest(method, path, body, runtimeBearerToken) {
|
|
|
126
125
|
}
|
|
127
126
|
catch (error) {
|
|
128
127
|
const errorMsg = getHttpErrorDetails(error);
|
|
129
|
-
console.warn(`[CiviCRM] JWT generation failed: ${errorMsg}. Falling back to API key.`);
|
|
130
128
|
this.addExecutionHints({
|
|
131
129
|
message: `JWT authentication failed (${errorMsg}). Falling back to API Key authentication.`,
|
|
132
130
|
type: 'warning',
|
|
@@ -154,7 +152,6 @@ async function civicrmApiRequest(method, path, body, runtimeBearerToken) {
|
|
|
154
152
|
return response;
|
|
155
153
|
}
|
|
156
154
|
else {
|
|
157
|
-
console.warn('[CiviCRM] JWT returned empty response. Retrying with API key (JWT may have limited permissions).');
|
|
158
155
|
this.addExecutionHints({
|
|
159
156
|
message: 'The JWT-authenticated request returned no data (JWT may have limited permissions). Retrying with API Key authentication.',
|
|
160
157
|
type: 'warning',
|
|
@@ -165,7 +162,6 @@ async function civicrmApiRequest(method, path, body, runtimeBearerToken) {
|
|
|
165
162
|
}
|
|
166
163
|
catch (error) {
|
|
167
164
|
const errorMsg = getHttpErrorDetails(error);
|
|
168
|
-
console.warn('[CiviCRM] JWT request failed. Retrying with API key.');
|
|
169
165
|
this.addExecutionHints({
|
|
170
166
|
message: `The JWT-authenticated request failed (${errorMsg}). Retrying with API Key authentication.`,
|
|
171
167
|
type: 'warning',
|
|
@@ -186,11 +182,7 @@ async function civicrmApiRequest(method, path, body, runtimeBearerToken) {
|
|
|
186
182
|
json: true,
|
|
187
183
|
};
|
|
188
184
|
try {
|
|
189
|
-
|
|
190
|
-
if (useJwt && jwtToken) {
|
|
191
|
-
console.log('[CiviCRM] API key request successful (JWT was insufficient, using API key as fallback)');
|
|
192
|
-
}
|
|
193
|
-
return response;
|
|
185
|
+
return await this.helpers.httpRequest.call(this, apiKeyOptions);
|
|
194
186
|
}
|
|
195
187
|
catch (error) {
|
|
196
188
|
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
@@ -8,28 +8,6 @@ const contactIdCache = {}; // Cache resolved contact IDs
|
|
|
8
8
|
function isJwtAuthEnabled(credentials) {
|
|
9
9
|
return (credentials === null || credentials === void 0 ? void 0 : credentials.enableJwtAuth) === true;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Extracts a readable message from an HTTP error, including the response body
|
|
13
|
-
* (e.g. CiviCRM's "Login not permitted. Must satisfy guard (perm, site_key)."),
|
|
14
|
-
* which the bare `error.message` (e.g. "Request failed with status code 401")
|
|
15
|
-
* does not include.
|
|
16
|
-
*/
|
|
17
|
-
function getErrorDetails(error) {
|
|
18
|
-
var _a, _b, _c;
|
|
19
|
-
const errorObj = error;
|
|
20
|
-
const status = (_a = errorObj === null || errorObj === void 0 ? void 0 : errorObj.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
21
|
-
const data = (_b = errorObj === null || errorObj === void 0 ? void 0 : errorObj.response) === null || _b === void 0 ? void 0 : _b.data;
|
|
22
|
-
const message = (_c = errorObj === null || errorObj === void 0 ? void 0 : errorObj.message) !== null && _c !== void 0 ? _c : String(error);
|
|
23
|
-
const body = typeof data === 'string' && data.trim()
|
|
24
|
-
? data
|
|
25
|
-
: data && typeof data === 'object'
|
|
26
|
-
? JSON.stringify(data)
|
|
27
|
-
: undefined;
|
|
28
|
-
if (body) {
|
|
29
|
-
return status ? `${message} | HTTP ${status} body: ${body}` : `${message} | body: ${body}`;
|
|
30
|
-
}
|
|
31
|
-
return status ? `${message} | HTTP ${status}` : message;
|
|
32
|
-
}
|
|
33
11
|
/**
|
|
34
12
|
* Resolve the current authenticated user's contact ID from Contact/get.
|
|
35
13
|
* Finds the contact that owns the given api_key.
|
|
@@ -60,16 +38,13 @@ async function resolveContactId(context, baseUrl, apiToken) {
|
|
|
60
38
|
});
|
|
61
39
|
const contacts = (response === null || response === void 0 ? void 0 : response.values) || [];
|
|
62
40
|
if (contacts.length === 0) {
|
|
63
|
-
console.warn('[CiviCRM] Contact/get found no contact with this api_key - JWT auto-resolve will be skipped');
|
|
64
41
|
return undefined;
|
|
65
42
|
}
|
|
66
43
|
const contactId = contacts[0].id;
|
|
67
44
|
contactIdCache[cacheKey] = contactId;
|
|
68
45
|
return contactId;
|
|
69
46
|
}
|
|
70
|
-
catch
|
|
71
|
-
const errorMsg = getErrorDetails(error);
|
|
72
|
-
console.warn(`[CiviCRM] Failed to auto-resolve contact ID: ${errorMsg}. Will attempt API key fallback.`);
|
|
47
|
+
catch {
|
|
73
48
|
return undefined;
|
|
74
49
|
}
|
|
75
50
|
}
|
|
@@ -116,26 +91,15 @@ async function getServerIssuedJwt(context, baseUrl, apiToken, contactId = 0, ttl
|
|
|
116
91
|
});
|
|
117
92
|
const cred = ((_b = (_a = response === null || response === void 0 ? void 0 : response.values) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.cred) || '';
|
|
118
93
|
if (!cred.startsWith('Bearer ')) {
|
|
119
|
-
console.warn('[CiviCRM] Invalid JWT response: missing Bearer token');
|
|
120
94
|
return undefined;
|
|
121
95
|
}
|
|
122
96
|
const token = cred.substring(7); // Remove "Bearer " prefix
|
|
123
97
|
serverIssuedCache[cacheKey] = { token, expiresAt: now + ttl * 1000 };
|
|
124
98
|
return token;
|
|
125
99
|
}
|
|
126
|
-
catch
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
errorMsg.includes('403') ||
|
|
130
|
-
errorMsg.includes('Permission denied') ||
|
|
131
|
-
errorMsg.includes('Login not permitted') ||
|
|
132
|
-
errorMsg.includes('Must satisfy guard');
|
|
133
|
-
if (isPermissionDenied) {
|
|
134
|
-
// User lacks permissions for JWT. Fall back to API key auth.
|
|
135
|
-
console.warn(`[CiviCRM JWT] User lacks permissions for AuthxCredential/create (${errorMsg}). Will use API key authentication instead.`);
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
console.warn(`[CiviCRM JWT] Failed to obtain JWT: ${errorMsg}. Falling back to API key.`);
|
|
100
|
+
catch {
|
|
101
|
+
// Any failure here (permission denied, network error, malformed response) falls
|
|
102
|
+
// back to API key auth in the caller -- see GenericFunctions.civicrmApiRequest.
|
|
139
103
|
return undefined;
|
|
140
104
|
}
|
|
141
105
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixiam/n8n-nodes-civicrm",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.3",
|
|
4
4
|
"description": "Full-featured CiviCRM API v4 integration for n8n",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@n8n/node-cli": "^0.23.1",
|
|
54
54
|
"@types/jest": "^30.0.0",
|
|
55
|
-
"@types/jsonwebtoken": "^9.0.10",
|
|
56
55
|
"@types/node": "^20.11.30",
|
|
57
56
|
"eslint": "9.32.0",
|
|
58
57
|
"jest": "^30.5.1",
|
|
@@ -61,9 +60,7 @@
|
|
|
61
60
|
"ts-jest": "^29.4.12",
|
|
62
61
|
"typescript": "5.9.2"
|
|
63
62
|
},
|
|
64
|
-
"dependencies": {
|
|
65
|
-
"jsonwebtoken": "^9.0.3"
|
|
66
|
-
},
|
|
63
|
+
"dependencies": {},
|
|
67
64
|
"peerDependencies": {
|
|
68
65
|
"n8n-workflow": "*"
|
|
69
66
|
},
|
|
@@ -73,4 +70,4 @@
|
|
|
73
70
|
}
|
|
74
71
|
},
|
|
75
72
|
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a"
|
|
76
|
-
}
|
|
73
|
+
}
|