@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +1 -1
  3. 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/lazy-loader",
3
- "version": "1.15.2",
3
+ "version": "1.16.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
@@ -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
- let organization = await this.crud.getHost(hostname);
53
- if (organization.error)
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 (!this.modules[name].content) {
79
- if (this.modules[name].path)
80
- this.modules[name].content = await require(this.modules[name].path)
81
- else {
82
- try {
83
- const scriptPath = path.join(scriptsDirectory, `${name}.js`);
84
- await fs.access(scriptPath);
85
- this.modules[name].content = await fs.readFile(scriptPath, 'utf8');
86
- } catch {
87
- this.modules[name].content = await fetchScriptFromDatabaseAndSave(name, this.modules[name], data);
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 (this.modules[name].content) {
93
- data.apis = await this.getApiKey(data.organization_id, name)
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
- console.log(error)
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(organization_id, name) {
137
- let organization = await this.crud.getOrganization(organization_id, false);
234
+ async getApiKey(data, name) {
235
+ let organization = await this.crud.getOrganization(data);
138
236
  if (organization.error)
139
- return organization.error
237
+ throw new Error(organization.error);
140
238
  if (!organization.apis)
141
- return { error: 'Missing apis object in organization object' }
239
+ throw new Error('Missing apis object in organization object');
142
240
  if (!organization.apis[name])
143
- return { error: `Missing ${name} in organization apis object` }
241
+ throw new Error(`Missing ${name} in organization apis object`);
144
242
  return organization.apis[name]
145
243
  }
146
244