@cocreate/lazy-loader 1.17.0 → 1.18.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +1 -1
  3. package/src/server.js +173 -26
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ # [1.18.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.17.0...v1.18.0) (2024-03-18)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * handlng wbhook returned as string or object ([daf7438](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/daf7438bf8d6f049629112d056d9a598499cc23e))
7
+ * imporved authentication handling ([dfc9b1c](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/dfc9b1c8b9fe547ff16d441e4b31b3f0332bacb8))
8
+ * typo executeect updated to object ([a1b6258](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/a1b6258a7a88cd4e9847257fb552852342d9c7e3))
9
+
10
+
11
+ ### Features
12
+
13
+ * authentication can be defined at envirnonemt level ([e4bf74c](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/e4bf74cdd8146bd390aec734d29e4177c3b264a7))
14
+ * executeMethod() to handle dotNotion method without losing context ([8ab4f84](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/8ab4f8484073891dba4c154938ae597c21962c5f))
15
+ * processOperators() to execute/rturn operator value ([e948ca2](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/e948ca24c1fb1ba5ae9718aaa466f0e26af78c74))
16
+
1
17
  # [1.17.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.16.0...v1.17.0) (2024-02-05)
2
18
 
3
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/lazy-loader",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "A simple lazy-loader component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "lazy-loader",
package/src/server.js CHANGED
@@ -76,7 +76,7 @@ class CoCreateLazyLoader {
76
76
 
77
77
  async executeScriptWithTimeout(name, data) {
78
78
  try {
79
- if (this.modules[name].initialize) {
79
+ if (this.modules[name].initialize || this.modules[name].initialize === '') {
80
80
  if (data.req)
81
81
  data = await this.webhooks(this.modules[name], data, name)
82
82
  else
@@ -159,18 +159,11 @@ class CoCreateLazyLoader {
159
159
  throw new Error(`Missing ${name} key in organization apis object`);
160
160
 
161
161
  const service = require(config.path);
162
- const instance = new service[config.initialize](key);
163
-
164
- let method = instance
165
- for (let i = 0; i < methodPath.length; i++) {
166
- method = method[methodPath[i]]
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.`);
162
+ let instance
163
+ if (config.initialize)
164
+ instance = new service[config.initialize](key);
165
+ else
166
+ instance = new service(key);
174
167
 
175
168
  let params = [], mainParam = false
176
169
  for (let i = 0; true; i++) {
@@ -185,7 +178,14 @@ class CoCreateLazyLoader {
185
178
  }
186
179
  }
187
180
 
188
- data.postmark = await method.apply(instance, params);
181
+ // TODO: should run processOperators before in order to perform complex opertions and get data
182
+ // data[name] = await processOperators(data, null, data[name]);
183
+
184
+ data[name] = await executeMethod(data.method, methodPath, instance, params)
185
+
186
+ // TODO: should run processOperators after in order to perform complex opertions and get data
187
+ // data[name] = await processOperators(data, data[name]);
188
+
189
189
  return data
190
190
  } catch (error) {
191
191
  data.error = error.message
@@ -204,13 +204,23 @@ class CoCreateLazyLoader {
204
204
  if (!key)
205
205
  throw new Error(`Missing ${name} key in organization apis object`);
206
206
 
207
- let name = data.req.url.split('/');
208
- name = name[3] || name[2] || name[1]
207
+ let webhookName = data.req.url.split('/');
208
+ webhookName = webhookName[webhookName.length - 1]
209
209
 
210
- // TODO: webhook secert could be a key pair
211
- const webhookSecret = data.apis[environment].webhooks[name];
212
- if (webhookSecret !== req.headers[name])
213
- throw new Error(`Webhook secret failed for ${name}. Unauthorized access attempt.`);
210
+ const webhook = apis[environment].webhooks[webhookName];
211
+ if (!webhook)
212
+ throw new Error(`Webhook ${name} ${webhookName} is not defined`);
213
+
214
+ let dataKey = webhook.dataKey || apis[environment].dataKey
215
+ if (!dataKey)
216
+ throw new Error(`Webhook ${name} eventKey is not defined`);
217
+
218
+ let nameKey = webhook.nameKey || apis[environment].nameKey
219
+ if (!nameKey)
220
+ throw new Error(`Webhook ${name} eventKey is not defined`);
221
+
222
+ if (!webhook.events)
223
+ throw new Error(`Webhook ${name} events are not defined`);
214
224
 
215
225
  let rawBody = '';
216
226
  await new Promise((resolve, reject) => {
@@ -225,13 +235,52 @@ class CoCreateLazyLoader {
225
235
  });
226
236
  });
227
237
 
228
- // TODO: if decrypt and validation is builtin to service
229
- // const service = require(config.path);
230
- // const instance = new service[config.initialize](key);
238
+ let parameters, method
239
+
240
+ if (webhook.authenticate) {
241
+ method = webhook.authenticate.method
242
+ parameters = webhook.authenticate.parameters
243
+ }
244
+
245
+ if (!parameters && apis[environment].authenticate && apis[environment].authenticate.parameters) {
246
+ parameters = apis[environment].authenticate.parameters
247
+ } else
248
+ throw new Error(`Webhook secret ${name} is not defined`);
249
+
250
+ if (!method && apis[environment].authenticate)
251
+ method = apis[environment].authenticate.method
252
+
253
+ // TODO: webhook secert could be a key pair
231
254
 
232
- // TODO: event may need to be handle by a built in service function
233
- const event = JSON.parse(rawBody)
234
- // TODO: using request.method and event.type get object and send socket.onMessage for proccessing
255
+ let event
256
+ if (!method) {
257
+ if (!parameters[0] !== parameters[1])
258
+ throw new Error(`Webhook secret failed for ${name}. Unauthorized access attempt.`);
259
+
260
+ event = JSON.parse(rawBody)
261
+ } else {
262
+ const service = require(config.path);
263
+ let instance
264
+ if (config.initialize)
265
+ instance = new service[config.initialize](key);
266
+ else
267
+ instance = new service(key);
268
+
269
+ event = await executeMethod(name + '.' + method, methodPath, instance, parameters)
270
+ }
271
+
272
+ let eventName = getValueFromObject(event, nameKey)
273
+ if (!eventName)
274
+ throw new Error(`Webhook ${name} nameKey: ${nameKey} could not be found in the event.`);
275
+
276
+ let eventData = getValueFromObject(event, dataKey)
277
+ if (!eventData)
278
+ throw new Error(`Webhook ${name} dataKey: ${dataKey} could not be found in the event.`);
279
+
280
+ let execute = webhook.events[eventName];
281
+ if (execute) {
282
+ execute = await processOperators(data, event, execute);
283
+ }
235
284
 
236
285
  data.res.writeHead(200, { 'Content-Type': 'application/json' });
237
286
  data.res.end(JSON.stringify({ message: 'Webhook received and processed' }));
@@ -257,6 +306,101 @@ class CoCreateLazyLoader {
257
306
 
258
307
  }
259
308
 
309
+ async function processOperators(data, event, execute, parent = null, parentKey = null) {
310
+ if (Array.isArray(execute)) {
311
+ execute.forEach(async (item, index) => await processOperators(data, event, item, execute, index));
312
+ } else if (typeof execute === 'object' && execute !== null) {
313
+ for (let key of Object.keys(execute)) {
314
+ // Check if key is an operator
315
+ if (key.startsWith('$')) {
316
+ const operatorResult = await processOperator(data, event, key, execute[key]);
317
+ if (parent && operatorResult !== null) {
318
+ if (parentKey !== null) {
319
+ parent[parentKey] = operatorResult;
320
+ await processOperators(data, event, parent[parentKey], parent, parentKey);
321
+ }
322
+ // else {
323
+ // // Scenario 2: Replace the key (more complex, might require re-structuring the executable object)
324
+ // delete parent[key]; // Remove the original key
325
+ // parent[operatorResult] = execute[key]; // Assign the value to the new key
326
+ // // Continue processing the new key if necessary
327
+ // }
328
+ }
329
+ } else {
330
+ await processOperators(data, event, execute[key], execute, key);
331
+ }
332
+ }
333
+ } else {
334
+ return await processOperator(data, event, execute);
335
+ }
336
+ }
337
+
338
+ async function processOperator(data, event, operator, context) {
339
+ if (operator.startsWith('$data.')) {
340
+ operator = getValueFromObject(data, operator.substring(6))
341
+ } else if (operator.startsWith('$req.')) {
342
+ operator = getValueFromObject(data.req, operator.substring(5))
343
+ } else if (operator.startsWith('$header.')) {
344
+ operator = getValueFromObject(data.req.header, operator.substring(7))
345
+ } else if (operator.startsWith('$crud')) {
346
+ operator = await data.crud.send(context)
347
+ let name = operator.method.split('.')[0]
348
+ operator = operator[name]
349
+ } else if (operator.startsWith('$socket')) {
350
+ operator = await data.socket.send(context)
351
+ let name = operator.method.split('.')[0]
352
+ operator = operator[name]
353
+ } else if (operator.startsWith('$api')) {
354
+ let name = context.method.split('.')[0]
355
+ operator = this.executeScriptWithTimeout(name, context)
356
+ } else if (operator.startsWith('$webhook.')) {
357
+ operator = getValueFromObject(webhook, operator.substring(9))
358
+ } else if (operator.startsWith('$event.')) {
359
+ operator = getValueFromObject(event, operator.substring(7))
360
+ }
361
+
362
+ return operator;
363
+ }
364
+
365
+ async function executeMethod(method, methodPath, instance, params) {
366
+ try {
367
+ switch (methodPath.length) {
368
+ case 1:
369
+ return await instance[methodPath[0]](...params)
370
+ case 2:
371
+ return await instance[methodPath[0]][methodPath[1]](...params);
372
+ case 3:
373
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]](...params);
374
+ case 4:
375
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]](...params);
376
+ case 5:
377
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]](...params);
378
+ case 6:
379
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]](...params);
380
+ case 7:
381
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]][methodPath[6]](...params);
382
+ case 8:
383
+ return await instance[methodPath[0]][methodPath[1]][methodPath[2]][methodPath[3]][methodPath[4]][methodPath[5]][methodPath[6]][methodPath[7]](...params);
384
+ default:
385
+ const methodName = methodPath.pop();
386
+ let Method = instance
387
+ for (let i = 0; i < methodPath.length; i++) {
388
+ Method = Method[methodPath[i]]
389
+ if (Method === undefined) {
390
+ throw new Error(`Method ${methodPath[i]} not found using ${method}.`);
391
+ }
392
+ }
393
+
394
+ if (typeof Method[methodName] !== 'function')
395
+ throw new Error(`Method ${method} is not a function.`);
396
+
397
+ return await Method[methodName](...params)
398
+ }
399
+ } catch (error) {
400
+ throw new Error(`Method ${method} not found.`);
401
+ }
402
+ }
403
+
260
404
  function getModuleDependencies(modulePath) {
261
405
  let moduleObj = require.cache[modulePath];
262
406
  if (!moduleObj) {
@@ -343,4 +487,7 @@ async function fetchScriptFromDatabaseAndSave(name, moduleConfig) {
343
487
  return src;
344
488
  }
345
489
 
490
+
491
+
492
+
346
493
  module.exports = CoCreateLazyLoader;