@cocreate/lazy-loader 1.17.0 → 1.19.0
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/CHANGELOG.md +28 -0
- package/package.json +1 -1
- package/src/server.js +222 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
# [1.19.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.18.0...v1.19.0) (2024-04-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* added processOperators and processOperator to lazyLoader class ([973f07a](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/973f07ac492dee348f15b6889c15e180cf4d3eb0))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* dynamically handle webhooks using operations and objects to perform actions ([c1f17b4](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/c1f17b47304bd9c0b44ba591809dfee3c7186992))
|
|
12
|
+
|
|
13
|
+
# [1.18.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.17.0...v1.18.0) (2024-03-18)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* handlng wbhook returned as string or object ([daf7438](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/daf7438bf8d6f049629112d056d9a598499cc23e))
|
|
19
|
+
* imporved authentication handling ([dfc9b1c](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/dfc9b1c8b9fe547ff16d441e4b31b3f0332bacb8))
|
|
20
|
+
* typo executeect updated to object ([a1b6258](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/a1b6258a7a88cd4e9847257fb552852342d9c7e3))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* authentication can be defined at envirnonemt level ([e4bf74c](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/e4bf74cdd8146bd390aec734d29e4177c3b264a7))
|
|
26
|
+
* executeMethod() to handle dotNotion method without losing context ([8ab4f84](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/8ab4f8484073891dba4c154938ae597c21962c5f))
|
|
27
|
+
* processOperators() to execute/rturn operator value ([e948ca2](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/e948ca24c1fb1ba5ae9718aaa466f0e26af78c74))
|
|
28
|
+
|
|
1
29
|
# [1.17.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.16.0...v1.17.0) (2024-02-05)
|
|
2
30
|
|
|
3
31
|
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const fs = require('fs').promises;
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { URL } = require('url');
|
|
3
4
|
const vm = require('vm');
|
|
4
5
|
const Config = require("@cocreate/config");
|
|
5
|
-
const {
|
|
6
|
+
const { getValueFromObject } = require('@cocreate/utils');
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class CoCreateLazyLoader {
|
|
8
10
|
constructor(server, crud, files) {
|
|
@@ -44,6 +46,7 @@ class CoCreateLazyLoader {
|
|
|
44
46
|
|
|
45
47
|
async request(req, res) {
|
|
46
48
|
try {
|
|
49
|
+
// TODO: track usage
|
|
47
50
|
const valideUrl = new URL(`http://${req.headers.host}${req.url}`);
|
|
48
51
|
const hostname = valideUrl.hostname;
|
|
49
52
|
let organization
|
|
@@ -76,7 +79,7 @@ class CoCreateLazyLoader {
|
|
|
76
79
|
|
|
77
80
|
async executeScriptWithTimeout(name, data) {
|
|
78
81
|
try {
|
|
79
|
-
if (this.modules[name].initialize) {
|
|
82
|
+
if (this.modules[name].initialize || this.modules[name].initialize === '') {
|
|
80
83
|
if (data.req)
|
|
81
84
|
data = await this.webhooks(this.modules[name], data, name)
|
|
82
85
|
else
|
|
@@ -159,18 +162,11 @@ class CoCreateLazyLoader {
|
|
|
159
162
|
throw new Error(`Missing ${name} key in organization apis object`);
|
|
160
163
|
|
|
161
164
|
const service = require(config.path);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (method === undefined) {
|
|
168
|
-
throw new Error(`Method ${methodPath[i]} not found using ${data.method}.`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (typeof method !== 'function')
|
|
173
|
-
throw new Error(`Method ${data.method} is not a function.`);
|
|
165
|
+
let instance
|
|
166
|
+
if (config.initialize)
|
|
167
|
+
instance = new service[config.initialize](key);
|
|
168
|
+
else
|
|
169
|
+
instance = new service(key);
|
|
174
170
|
|
|
175
171
|
let params = [], mainParam = false
|
|
176
172
|
for (let i = 0; true; i++) {
|
|
@@ -185,7 +181,14 @@ class CoCreateLazyLoader {
|
|
|
185
181
|
}
|
|
186
182
|
}
|
|
187
183
|
|
|
188
|
-
|
|
184
|
+
// TODO: should run processOperators before in order to perform complex opertions and get data
|
|
185
|
+
// data[name] = await processOperators(data, null, data[name]);
|
|
186
|
+
|
|
187
|
+
data[name] = await executeMethod(data.method, methodPath, instance, params)
|
|
188
|
+
|
|
189
|
+
// TODO: should run processOperators after in order to perform complex opertions and get data
|
|
190
|
+
// data[name] = await processOperators(data, data[name]);
|
|
191
|
+
|
|
189
192
|
return data
|
|
190
193
|
} catch (error) {
|
|
191
194
|
data.error = error.message
|
|
@@ -204,18 +207,30 @@ class CoCreateLazyLoader {
|
|
|
204
207
|
if (!key)
|
|
205
208
|
throw new Error(`Missing ${name} key in organization apis object`);
|
|
206
209
|
|
|
207
|
-
let
|
|
208
|
-
|
|
210
|
+
let webhookName = data.req.url.split('/');
|
|
211
|
+
webhookName = webhookName[webhookName.length - 1]
|
|
209
212
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
213
|
+
const webhook = apis[environment].webhooks[webhookName];
|
|
214
|
+
if (!webhook)
|
|
215
|
+
throw new Error(`Webhook ${name} ${webhookName} is not defined`);
|
|
216
|
+
|
|
217
|
+
// eventDataKey is used to access the event data
|
|
218
|
+
let eventDataKey = webhook.eventDataKey || apis[environment].eventDataKey
|
|
219
|
+
if (!eventDataKey)
|
|
220
|
+
throw new Error(`Webhook ${name} eventKey is not defined`);
|
|
221
|
+
|
|
222
|
+
// eventNameKey is used to access the event the event name
|
|
223
|
+
let eventNameKey = webhook.eventNameKey || apis[environment].eventNameKey
|
|
224
|
+
if (!eventNameKey)
|
|
225
|
+
throw new Error(`Webhook ${name} eventNameKey is not defined`);
|
|
226
|
+
|
|
227
|
+
if (!webhook.events)
|
|
228
|
+
throw new Error(`Webhook ${name} events are not defined`);
|
|
214
229
|
|
|
215
|
-
|
|
230
|
+
data.rawBody = '';
|
|
216
231
|
await new Promise((resolve, reject) => {
|
|
217
232
|
data.req.on('data', chunk => {
|
|
218
|
-
rawBody += chunk.toString();
|
|
233
|
+
data.rawBody += chunk.toString();
|
|
219
234
|
});
|
|
220
235
|
data.req.on('end', () => {
|
|
221
236
|
resolve();
|
|
@@ -225,13 +240,58 @@ class CoCreateLazyLoader {
|
|
|
225
240
|
});
|
|
226
241
|
});
|
|
227
242
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
let parameters, method
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
if (webhook.authenticate && webhook.authenticate.method) {
|
|
247
|
+
method = webhook.authenticate.method
|
|
248
|
+
} else if (apis[environment].authenticate && apis[environment].authenticate.method) {
|
|
249
|
+
method = apis[environment].authenticate.method
|
|
250
|
+
} else
|
|
251
|
+
throw new Error(`Webhook ${name} authenticate method is not defined`);
|
|
252
|
+
|
|
253
|
+
if (webhook.authenticate && webhook.authenticate.parameters) {
|
|
254
|
+
parameters = webhook.authenticate.parameters
|
|
255
|
+
} else if (apis[environment].authenticate && apis[environment].authenticate.parameters) {
|
|
256
|
+
parameters = apis[environment].authenticate.parameters
|
|
257
|
+
} else
|
|
258
|
+
throw new Error(`Webhook ${name} authenticate parameters is not defined`);
|
|
259
|
+
|
|
260
|
+
// TODO: webhook secert could be a key pair
|
|
261
|
+
|
|
262
|
+
let event
|
|
263
|
+
if (!method) {
|
|
264
|
+
if (!parameters[0] !== parameters[1])
|
|
265
|
+
throw new Error(`Webhook secret failed for ${name}. Unauthorized access attempt.`);
|
|
266
|
+
|
|
267
|
+
event = JSON.parse(data.rawBody)
|
|
268
|
+
} else {
|
|
269
|
+
const service = require(config.path);
|
|
270
|
+
let instance
|
|
271
|
+
if (config.initialize)
|
|
272
|
+
instance = new service[config.initialize](key);
|
|
273
|
+
else
|
|
274
|
+
instance = new service(key);
|
|
275
|
+
|
|
276
|
+
const methodPath = method.split('.')
|
|
277
|
+
|
|
278
|
+
await this.processOperators(data, '', parameters);
|
|
279
|
+
|
|
280
|
+
event = await executeMethod(method, methodPath, instance, parameters)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let eventName = getValueFromObject(event, eventNameKey)
|
|
284
|
+
if (!eventName)
|
|
285
|
+
throw new Error(`Webhook ${name} eventNameKey: ${eventNameKey} could not be found in the event.`);
|
|
231
286
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
287
|
+
let eventData = getValueFromObject(event, eventDataKey)
|
|
288
|
+
if (!eventData)
|
|
289
|
+
throw new Error(`Webhook ${name} eventDataKey: ${eventDataKey} could not be found in the event.`);
|
|
290
|
+
|
|
291
|
+
let execute = webhook.events[eventName];
|
|
292
|
+
if (execute) {
|
|
293
|
+
execute = await this.processOperators(data, event, execute);
|
|
294
|
+
}
|
|
235
295
|
|
|
236
296
|
data.res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
237
297
|
data.res.end(JSON.stringify({ message: 'Webhook received and processed' }));
|
|
@@ -244,6 +304,67 @@ class CoCreateLazyLoader {
|
|
|
244
304
|
}
|
|
245
305
|
}
|
|
246
306
|
|
|
307
|
+
async processOperators(data, event, execute, parent = null, parentKey = null) {
|
|
308
|
+
if (Array.isArray(execute)) {
|
|
309
|
+
for (let index = 0; index < execute.length; index++) {
|
|
310
|
+
execute[index] = await this.processOperators(data, event, execute[index], execute, index);
|
|
311
|
+
}
|
|
312
|
+
} else if (typeof execute === 'object' && execute !== null) {
|
|
313
|
+
for (let key of Object.keys(execute)) {
|
|
314
|
+
if (key.startsWith('$')) {
|
|
315
|
+
const operatorResult = await this.processOperator(data, event, key, execute[key]);
|
|
316
|
+
if (parent && operatorResult !== null && parentKey !== null) {
|
|
317
|
+
parent[parentKey] = operatorResult;
|
|
318
|
+
await this.processOperators(data, event, parent[parentKey], parent, parentKey);
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
execute[key] = await this.processOperators(data, event, execute[key], execute, key);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
return await this.processOperator(data, event, execute);
|
|
326
|
+
}
|
|
327
|
+
return execute;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async processOperator(data, event, operator, context) {
|
|
331
|
+
let result
|
|
332
|
+
if (operator.startsWith('$data.')) {
|
|
333
|
+
return getValueFromObject(data, operator.substring(6))
|
|
334
|
+
} else if (operator.startsWith('$req')) {
|
|
335
|
+
return getValueFromObject(data, operator.substring(1))
|
|
336
|
+
} else if (operator.startsWith('$header')) {
|
|
337
|
+
return getValueFromObject(data.req, operator.substring(1))
|
|
338
|
+
} else if (operator.startsWith('$rawBody')) {
|
|
339
|
+
return getValueFromObject(data, operator.substring(1))
|
|
340
|
+
} else if (operator.startsWith('$crud')) {
|
|
341
|
+
context = await this.processOperators(data, event, context);
|
|
342
|
+
result = await this.crud.send(context)
|
|
343
|
+
if (operator.startsWith('$crud.'))
|
|
344
|
+
result = getValueFromObject(operator, operator.substring(6))
|
|
345
|
+
return await this.processOperators(data, event, result);
|
|
346
|
+
} else if (operator.startsWith('$socket')) {
|
|
347
|
+
context = await this.processOperators(data, event, context);
|
|
348
|
+
result = await this.socket.send(context)
|
|
349
|
+
if (operator.startsWith('$socket.'))
|
|
350
|
+
result = getValueFromObject(operator, operator.substring(6))
|
|
351
|
+
return await this.processOperators(data, event, result);
|
|
352
|
+
} else if (operator.startsWith('$api')) {
|
|
353
|
+
context = await this.processOperators(data, event, context);
|
|
354
|
+
let name = context.method.split('.')[0]
|
|
355
|
+
result = this.executeScriptWithTimeout(name, context)
|
|
356
|
+
if (operator.startsWith('$api.'))
|
|
357
|
+
result = getValueFromObject(event, operator.substring(5))
|
|
358
|
+
return await this.processOperators(data, event, result);
|
|
359
|
+
} else if (operator.startsWith('$event')) {
|
|
360
|
+
if (operator.startsWith('$event.'))
|
|
361
|
+
result = getValueFromObject(event, operator.substring(7))
|
|
362
|
+
return await this.processOperators(data, event, result);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return operator;
|
|
366
|
+
}
|
|
367
|
+
|
|
247
368
|
async getApiKey(data, name) {
|
|
248
369
|
let organization = await this.crud.getOrganization(data);
|
|
249
370
|
if (organization.error)
|
|
@@ -257,6 +378,75 @@ class CoCreateLazyLoader {
|
|
|
257
378
|
|
|
258
379
|
}
|
|
259
380
|
|
|
381
|
+
|
|
382
|
+
// async function processOperators(data, event, execute, parent = null, parentKey = null) {
|
|
383
|
+
// if (Array.isArray(execute)) {
|
|
384
|
+
// execute.forEach(async (item, index) => await processOperators(data, event, item, execute, index));
|
|
385
|
+
// } else if (typeof execute === 'object' && execute !== null) {
|
|
386
|
+
// for (let key of Object.keys(execute)) {
|
|
387
|
+
// // Check if key is an operator
|
|
388
|
+
// if (key.startsWith('$')) {
|
|
389
|
+
// const operatorResult = await processOperator(data, event, key, execute[key]);
|
|
390
|
+
// if (parent && operatorResult !== null) {
|
|
391
|
+
// if (parentKey !== null) {
|
|
392
|
+
// parent[parentKey] = operatorResult;
|
|
393
|
+
// await processOperators(data, event, parent[parentKey], parent, parentKey);
|
|
394
|
+
// }
|
|
395
|
+
// // else {
|
|
396
|
+
// // // Scenario 2: Replace the key (more complex, might require re-structuring the executable object)
|
|
397
|
+
// // delete parent[key]; // Remove the original key
|
|
398
|
+
// // parent[operatorResult] = execute[key]; // Assign the value to the new key
|
|
399
|
+
// // // Continue processing the new key if necessary
|
|
400
|
+
// // }
|
|
401
|
+
// }
|
|
402
|
+
// } else {
|
|
403
|
+
// await processOperators(data, event, execute[key], execute, key);
|
|
404
|
+
// }
|
|
405
|
+
// }
|
|
406
|
+
// } else {
|
|
407
|
+
// return await processOperator(data, event, execute);
|
|
408
|
+
// }
|
|
409
|
+
// }
|
|
410
|
+
|
|
411
|
+
async function executeMethod(method, methodPath, instance, params) {
|
|
412
|
+
try {
|
|
413
|
+
switch (methodPath.length) {
|
|
414
|
+
case 1:
|
|
415
|
+
return await instance[methodPath[0]](...params)
|
|
416
|
+
case 2:
|
|
417
|
+
return await instance[methodPath[0]][methodPath[1]](...params);
|
|
418
|
+
case 3:
|
|
419
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]](...params);
|
|
420
|
+
case 4:
|
|
421
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]](...params);
|
|
422
|
+
case 5:
|
|
423
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]](...params);
|
|
424
|
+
case 6:
|
|
425
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]](...params);
|
|
426
|
+
case 7:
|
|
427
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]][methodPath[6]](...params);
|
|
428
|
+
case 8:
|
|
429
|
+
return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]][methodPath[6]][methodPath[7]](...params);
|
|
430
|
+
default:
|
|
431
|
+
const methodName = methodPath.pop();
|
|
432
|
+
let Method = instance
|
|
433
|
+
for (let i = 0; i < methodPath.length; i++) {
|
|
434
|
+
Method = Method[methodPath[i]]
|
|
435
|
+
if (Method === undefined) {
|
|
436
|
+
throw new Error(`Method ${methodPath[i]} not found using ${method}.`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (typeof Method[methodName] !== 'function')
|
|
441
|
+
throw new Error(`Method ${method} is not a function.`);
|
|
442
|
+
|
|
443
|
+
return await Method[methodName](...params)
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
throw new Error(`Method ${method} not found.`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
260
450
|
function getModuleDependencies(modulePath) {
|
|
261
451
|
let moduleObj = require.cache[modulePath];
|
|
262
452
|
if (!moduleObj) {
|
|
@@ -343,4 +533,7 @@ async function fetchScriptFromDatabaseAndSave(name, moduleConfig) {
|
|
|
343
533
|
return src;
|
|
344
534
|
}
|
|
345
535
|
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
346
539
|
module.exports = CoCreateLazyLoader;
|