@cocreate/lazy-loader 1.15.2 → 1.16.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 +14 -0
- package/package.json +1 -1
- package/src/server.js +129 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.16.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.15.2...v1.16.0) (2024-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* error handling ([6bde772](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/6bde772156c95487a7c7abba494ee508c631fd99))
|
|
7
|
+
* getOrganization accepts one param ([bd2336a](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/bd2336a32033cd631199995cf4e4878451524010))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* dynamically handles any third paty api and webhooks ([6ac3c2d](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/6ac3c2dce8786315ca9daaaa375e9ea480ecdf51))
|
|
13
|
+
* operator $params to define an array of params and their data/values. ([31b6ec7](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/31b6ec728a7330410447229376a776d23011fc55))
|
|
14
|
+
|
|
1
15
|
## [1.15.2](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.15.1...v1.15.2) (2024-01-17)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -4,8 +4,6 @@ const vm = require('vm');
|
|
|
4
4
|
const Config = require("@cocreate/config");
|
|
5
5
|
const { URL } = require('url');
|
|
6
6
|
|
|
7
|
-
// const organizations = {};
|
|
8
|
-
|
|
9
7
|
class CoCreateLazyLoader {
|
|
10
8
|
constructor(server, crud, files) {
|
|
11
9
|
this.server = server
|
|
@@ -48,10 +46,12 @@ class CoCreateLazyLoader {
|
|
|
48
46
|
try {
|
|
49
47
|
const valideUrl = new URL(`http://${req.headers.host}${req.url}`);
|
|
50
48
|
const hostname = valideUrl.hostname;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
let organization
|
|
50
|
+
try {
|
|
51
|
+
organization = await this.crud.getOrganization({ host: hostname });
|
|
52
|
+
} catch {
|
|
54
53
|
return this.files.send(req, res, this.crud, organization, valideUrl)
|
|
54
|
+
}
|
|
55
55
|
|
|
56
56
|
if (valideUrl.pathname.startsWith('/webhooks/')) {
|
|
57
57
|
let name = req.url.split('/')[2]; // Assuming URL structure is /webhook/name/...
|
|
@@ -75,30 +75,38 @@ class CoCreateLazyLoader {
|
|
|
75
75
|
|
|
76
76
|
async executeScriptWithTimeout(name, data) {
|
|
77
77
|
try {
|
|
78
|
-
if (
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
else
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
if (this.modules[name].initialize) {
|
|
79
|
+
if (data.req)
|
|
80
|
+
data = await this.webhooks(this.modules[name], data, name)
|
|
81
|
+
else
|
|
82
|
+
data = await this.api(this.modules[name], data)
|
|
83
|
+
} else {
|
|
84
|
+
if (!this.modules[name].content) {
|
|
85
|
+
if (this.modules[name].path)
|
|
86
|
+
this.modules[name].content = await require(this.modules[name].path)
|
|
87
|
+
else {
|
|
88
|
+
try {
|
|
89
|
+
const scriptPath = path.join(scriptsDirectory, `${name}.js`);
|
|
90
|
+
await fs.access(scriptPath);
|
|
91
|
+
this.modules[name].content = await fs.readFile(scriptPath, 'utf8');
|
|
92
|
+
} catch {
|
|
93
|
+
this.modules[name].content = await fetchScriptFromDatabaseAndSave(name, this.modules[name], data);
|
|
94
|
+
}
|
|
88
95
|
}
|
|
89
96
|
}
|
|
97
|
+
|
|
98
|
+
if (this.modules[name].content) {
|
|
99
|
+
data.apis = await this.getApiKey(data, name)
|
|
100
|
+
data.crud = this.crud
|
|
101
|
+
data = await this.modules[name].content.send(data)
|
|
102
|
+
delete data.apis
|
|
103
|
+
delete data.crud
|
|
104
|
+
} else
|
|
105
|
+
return
|
|
90
106
|
}
|
|
91
107
|
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
data.crud = this.crud
|
|
95
|
-
data = await this.modules[name].content.send(data)
|
|
96
|
-
delete data.apis
|
|
97
|
-
delete data.crud
|
|
98
|
-
if (data.socket)
|
|
99
|
-
this.wsManager.send(data)
|
|
100
|
-
} else
|
|
101
|
-
return
|
|
108
|
+
if (data.socket)
|
|
109
|
+
this.wsManager.send(data)
|
|
102
110
|
|
|
103
111
|
if (this.modules[name].unload === false || this.modules[name].unload === 'false')
|
|
104
112
|
return
|
|
@@ -129,18 +137,108 @@ class CoCreateLazyLoader {
|
|
|
129
137
|
this.modules[name].timeout = timeout
|
|
130
138
|
}
|
|
131
139
|
} catch (error) {
|
|
132
|
-
|
|
140
|
+
data.error = error.message
|
|
141
|
+
if (data.req) {
|
|
142
|
+
data.res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
143
|
+
data.res.end(`Lazyload Error: ${error.message}`);
|
|
144
|
+
} if (data.socket)
|
|
145
|
+
this.wsManager.send(data)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async api(config, data) {
|
|
150
|
+
try {
|
|
151
|
+
const methodPath = data.method.split('.')
|
|
152
|
+
const name = methodPath.shift()
|
|
153
|
+
|
|
154
|
+
const apis = await this.getApiKey(data, name)
|
|
155
|
+
const environment = data.environment || 'production';
|
|
156
|
+
const key = apis[environment].key;
|
|
157
|
+
if (!key)
|
|
158
|
+
throw new Error(`Missing ${name} key in organization apis object`);
|
|
159
|
+
|
|
160
|
+
const service = require(config.path);
|
|
161
|
+
const instance = new service[config.initialize](key);
|
|
162
|
+
|
|
163
|
+
let method = instance
|
|
164
|
+
for (let i = 0; i < methodPath.length; i++) {
|
|
165
|
+
method = method[methodPath[i]]
|
|
166
|
+
if (method === undefined) {
|
|
167
|
+
throw new Error(`Method ${methodPath[i]} not found using ${data.method}.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (typeof method !== 'function')
|
|
172
|
+
throw new Error(`Method ${data.method} is not a function.`);
|
|
173
|
+
|
|
174
|
+
let params = data.$params || [data[name]]
|
|
175
|
+
data.postmark = await method.apply(instance, params);
|
|
176
|
+
return data
|
|
177
|
+
} catch (error) {
|
|
178
|
+
data.error = error.message
|
|
179
|
+
return data
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async webhooks(config, data, name) {
|
|
184
|
+
try {
|
|
185
|
+
const apis = await this.getApiKey(data, name)
|
|
186
|
+
let environment = data.environment || 'production';
|
|
187
|
+
if (data.host.startsWith('dev.') || data.host.startsWith('test.'))
|
|
188
|
+
environment = 'test'
|
|
189
|
+
|
|
190
|
+
const key = apis[environment].key;
|
|
191
|
+
if (!key)
|
|
192
|
+
throw new Error(`Missing ${name} key in organization apis object`);
|
|
193
|
+
|
|
194
|
+
let name = data.req.url.split('/');
|
|
195
|
+
name = name[3] || name[2] || name[1]
|
|
196
|
+
|
|
197
|
+
// TODO: webhook secert could be a key pair
|
|
198
|
+
const webhookSecret = data.apis[environment].webhooks[name];
|
|
199
|
+
if (webhookSecret !== req.headers[name])
|
|
200
|
+
throw new Error(`Webhook secret failed for ${name}. Unauthorized access attempt.`);
|
|
201
|
+
|
|
202
|
+
let rawBody = '';
|
|
203
|
+
await new Promise((resolve, reject) => {
|
|
204
|
+
data.req.on('data', chunk => {
|
|
205
|
+
rawBody += chunk.toString();
|
|
206
|
+
});
|
|
207
|
+
data.req.on('end', () => {
|
|
208
|
+
resolve();
|
|
209
|
+
});
|
|
210
|
+
data.req.on('error', (err) => {
|
|
211
|
+
reject(err);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// TODO: if decrypt and validation is builtin to service
|
|
216
|
+
// const service = require(config.path);
|
|
217
|
+
// const instance = new service[config.initialize](key);
|
|
218
|
+
|
|
219
|
+
// TODO: event may need to be handle by a built in service function
|
|
220
|
+
const event = JSON.parse(rawBody)
|
|
221
|
+
// TODO: using request.method and event.type get object and send socket.onMessage for proccessing
|
|
222
|
+
|
|
223
|
+
data.res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
224
|
+
data.res.end(JSON.stringify({ message: 'Webhook received and processed' }));
|
|
225
|
+
return data
|
|
226
|
+
} catch (error) {
|
|
227
|
+
data.error = error.message
|
|
228
|
+
data.res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
229
|
+
data.res.end(error.message);
|
|
230
|
+
return data
|
|
133
231
|
}
|
|
134
232
|
}
|
|
135
233
|
|
|
136
|
-
async getApiKey(
|
|
137
|
-
let organization = await this.crud.getOrganization(
|
|
234
|
+
async getApiKey(data, name) {
|
|
235
|
+
let organization = await this.crud.getOrganization(data);
|
|
138
236
|
if (organization.error)
|
|
139
|
-
|
|
237
|
+
throw new Error(organization.error);
|
|
140
238
|
if (!organization.apis)
|
|
141
|
-
|
|
239
|
+
throw new Error('Missing apis object in organization object');
|
|
142
240
|
if (!organization.apis[name])
|
|
143
|
-
|
|
241
|
+
throw new Error(`Missing ${name} in organization apis object`);
|
|
144
242
|
return organization.apis[name]
|
|
145
243
|
}
|
|
146
244
|
|