Skip to content

Commit c1f17b4

Browse files
committed
feat: dynamically handle webhooks using operations and objects to perform actions
1 parent cabdb83 commit c1f17b4

File tree

1 file changed

+77
-40
lines changed

1 file changed

+77
-40
lines changed

src/server.js

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const fs = require('fs').promises;
22
const path = require('path');
3+
const { URL } = require('url');
34
const vm = require('vm');
45
const Config = require("@cocreate/config");
5-
const { URL } = require('url');
6+
const { getValueFromObject } = require('@cocreate/utils');
7+
68

79
class CoCreateLazyLoader {
810
constructor(server, crud, files) {
@@ -44,6 +46,7 @@ class CoCreateLazyLoader {
4446

4547
async request(req, res) {
4648
try {
49+
// TODO: track usage
4750
const valideUrl = new URL(`http://${req.headers.host}${req.url}`);
4851
const hostname = valideUrl.hostname;
4952
let organization
@@ -211,21 +214,23 @@ class CoCreateLazyLoader {
211214
if (!webhook)
212215
throw new Error(`Webhook ${name} ${webhookName} is not defined`);
213216

214-
let dataKey = webhook.dataKey || apis[environment].dataKey
215-
if (!dataKey)
217+
// eventDataKey is used to access the event data
218+
let eventDataKey = webhook.eventDataKey || apis[environment].eventDataKey
219+
if (!eventDataKey)
216220
throw new Error(`Webhook ${name} eventKey is not defined`);
217221

218-
let nameKey = webhook.nameKey || apis[environment].nameKey
219-
if (!nameKey)
220-
throw new Error(`Webhook ${name} eventKey is not defined`);
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`);
221226

222227
if (!webhook.events)
223228
throw new Error(`Webhook ${name} events are not defined`);
224229

225-
let rawBody = '';
230+
data.rawBody = '';
226231
await new Promise((resolve, reject) => {
227232
data.req.on('data', chunk => {
228-
rawBody += chunk.toString();
233+
data.rawBody += chunk.toString();
229234
});
230235
data.req.on('end', () => {
231236
resolve();
@@ -237,18 +242,20 @@ class CoCreateLazyLoader {
237242

238243
let parameters, method
239244

240-
if (webhook.authenticate) {
245+
246+
if (webhook.authenticate && webhook.authenticate.method) {
241247
method = webhook.authenticate.method
242-
parameters = webhook.authenticate.parameters
243-
}
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`);
244252

245-
if (!parameters && apis[environment].authenticate && apis[environment].authenticate.parameters) {
253+
if (webhook.authenticate && webhook.authenticate.parameters) {
254+
parameters = webhook.authenticate.parameters
255+
} else if (apis[environment].authenticate && apis[environment].authenticate.parameters) {
246256
parameters = apis[environment].authenticate.parameters
247257
} else
248-
throw new Error(`Webhook secret ${name} is not defined`);
249-
250-
if (!method && apis[environment].authenticate)
251-
method = apis[environment].authenticate.method
258+
throw new Error(`Webhook ${name} authenticate parameters is not defined`);
252259

253260
// TODO: webhook secert could be a key pair
254261

@@ -257,7 +264,7 @@ class CoCreateLazyLoader {
257264
if (!parameters[0] !== parameters[1])
258265
throw new Error(`Webhook secret failed for ${name}. Unauthorized access attempt.`);
259266

260-
event = JSON.parse(rawBody)
267+
event = JSON.parse(data.rawBody)
261268
} else {
262269
const service = require(config.path);
263270
let instance
@@ -266,16 +273,20 @@ class CoCreateLazyLoader {
266273
else
267274
instance = new service(key);
268275

269-
event = await executeMethod(name + '.' + method, methodPath, instance, parameters)
276+
const methodPath = method.split('.')
277+
278+
await processOperators(data, '', parameters);
279+
280+
event = await executeMethod(method, methodPath, instance, parameters)
270281
}
271282

272-
let eventName = getValueFromObject(event, nameKey)
283+
let eventName = getValueFromObject(event, eventNameKey)
273284
if (!eventName)
274-
throw new Error(`Webhook ${name} nameKey: ${nameKey} could not be found in the event.`);
285+
throw new Error(`Webhook ${name} eventNameKey: ${eventNameKey} could not be found in the event.`);
275286

276-
let eventData = getValueFromObject(event, dataKey)
287+
let eventData = getValueFromObject(event, eventDataKey)
277288
if (!eventData)
278-
throw new Error(`Webhook ${name} dataKey: ${dataKey} could not be found in the event.`);
289+
throw new Error(`Webhook ${name} eventDataKey: ${eventDataKey} could not be found in the event.`);
279290

280291
let execute = webhook.events[eventName];
281292
if (execute) {
@@ -308,40 +319,66 @@ class CoCreateLazyLoader {
308319

309320
async function processOperators(data, event, execute, parent = null, parentKey = null) {
310321
if (Array.isArray(execute)) {
311-
execute.forEach(async (item, index) => await processOperators(data, event, item, execute, index));
322+
for (let index = 0; index < execute.length; index++) {
323+
execute[index] = await processOperators(data, event, execute[index], execute, index);
324+
}
312325
} else if (typeof execute === 'object' && execute !== null) {
313326
for (let key of Object.keys(execute)) {
314-
// Check if key is an operator
315327
if (key.startsWith('$')) {
316328
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-
// }
329+
if (parent && operatorResult !== null && parentKey !== null) {
330+
parent[parentKey] = operatorResult;
331+
await processOperators(data, event, parent[parentKey], parent, parentKey);
328332
}
329333
} else {
330-
await processOperators(data, event, execute[key], execute, key);
334+
execute[key] = await processOperators(data, event, execute[key], execute, key);
331335
}
332336
}
333337
} else {
334338
return await processOperator(data, event, execute);
335339
}
340+
return execute;
336341
}
337342

343+
// async function processOperators(data, event, execute, parent = null, parentKey = null) {
344+
// if (Array.isArray(execute)) {
345+
// execute.forEach(async (item, index) => await processOperators(data, event, item, execute, index));
346+
// } else if (typeof execute === 'object' && execute !== null) {
347+
// for (let key of Object.keys(execute)) {
348+
// // Check if key is an operator
349+
// if (key.startsWith('$')) {
350+
// const operatorResult = await processOperator(data, event, key, execute[key]);
351+
// if (parent && operatorResult !== null) {
352+
// if (parentKey !== null) {
353+
// parent[parentKey] = operatorResult;
354+
// await processOperators(data, event, parent[parentKey], parent, parentKey);
355+
// }
356+
// // else {
357+
// // // Scenario 2: Replace the key (more complex, might require re-structuring the executable object)
358+
// // delete parent[key]; // Remove the original key
359+
// // parent[operatorResult] = execute[key]; // Assign the value to the new key
360+
// // // Continue processing the new key if necessary
361+
// // }
362+
// }
363+
// } else {
364+
// await processOperators(data, event, execute[key], execute, key);
365+
// }
366+
// }
367+
// } else {
368+
// return await processOperator(data, event, execute);
369+
// }
370+
// }
371+
338372
async function processOperator(data, event, operator, context) {
339373
if (operator.startsWith('$data.')) {
340374
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))
375+
} else if (operator.startsWith('$req')) {
376+
console.log(operator.substring(1))
377+
operator = getValueFromObject(data, operator.substring(1))
378+
} else if (operator.startsWith('$header')) {
379+
operator = getValueFromObject(data.req, operator.substring(1))
380+
} else if (operator.startsWith('$rawBody')) {
381+
operator = getValueFromObject(data, operator.substring(1))
345382
} else if (operator.startsWith('$crud')) {
346383
operator = await data.crud.send(context)
347384
let name = operator.method.split('.')[0]

0 commit comments

Comments
 (0)