@cocreate/lazy-loader 1.10.0 → 1.11.1

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 +19 -0
  2. package/package.json +2 -1
  3. package/src/server.js +137 -43
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [1.11.1](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.11.0...v1.11.1) (2023-12-09)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * hosts.get() converted to object ([c21187b](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/c21187ba2209bae5565078cd8fb1a7fea0b22b4c))
7
+
8
+ # [1.11.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.10.0...v1.11.0) (2023-12-09)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * add "@cocreate/config" ([bac22b5](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/bac22b5d4e5bafd83e68fe1ca727b184f07e8231))
14
+
15
+
16
+ ### Features
17
+
18
+ * handle http and websocket requests ([07b205c](https://github.com/CoCreate-app/CoCreate-lazy-loader/commit/07b205c31527e10c55f716a6ea1db243bebcccfd))
19
+
1
20
  # [1.10.0](https://github.com/CoCreate-app/CoCreate-lazy-loader/compare/v1.9.0...v1.10.0) (2023-12-01)
2
21
 
3
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/lazy-loader",
3
- "version": "1.10.0",
3
+ "version": "1.11.1",
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",
@@ -58,6 +58,7 @@
58
58
  "webpack-log": "^3.0.1"
59
59
  },
60
60
  "dependencies": {
61
+ "@cocreate/config": "^1.10.0",
61
62
  "@cocreate/observer": "^1.14.0"
62
63
  }
63
64
  }
package/src/server.js CHANGED
@@ -1,14 +1,18 @@
1
- const EventEmitter = require('events');
2
- const eventEmitter = new EventEmitter();
3
1
  const fs = require('fs').promises;
4
2
  const path = require('path');
5
3
  const vm = require('vm');
6
4
  const Config = require("@cocreate/config");
5
+ const { URL } = require('url');
6
+
7
+ const organizations = {};
8
+ const hosts = {};
7
9
 
8
10
  class CoCreateLazyLoader {
9
- constructor(crud) {
11
+ constructor(server, crud, files) {
12
+ this.server = server
10
13
  this.wsManager = crud.wsManager
11
14
  this.crud = crud
15
+ this.files = files
12
16
  this.exclusion = { ...require.cache };
13
17
  this.modules = {};
14
18
  this.init()
@@ -30,70 +34,160 @@ class CoCreateLazyLoader {
30
34
  // Call this function at the start of your application
31
35
  createScriptsDirectory();
32
36
 
33
- const config = await Config('lazyload', false, false)
37
+ // TODO: return the value so it can be applied directly to modules
38
+ // this.modules[key] = await Config('modules', false, false)
39
+
40
+ const config = await Config('modules', false, false)
34
41
  if (!config)
35
42
  return
36
43
 
37
- for (let key of Object.keys(config.lazyload)) {
38
- let moduleConfig = config.lazyload[key];
39
- eventEmitter.on(moduleConfig.event, async () => {
40
- this.executeScriptWithTimeout(key, moduleConfig)
44
+ for (let name of Object.keys(config.modules)) {
45
+ this.modules[name] = config.modules[name];
46
+ this.wsManager.on(this.modules[name].event, async (data) => {
47
+ this.executeScriptWithTimeout(name, data)
41
48
  });
42
49
  }
43
50
 
44
- // eventEmitter.emit('openai');
51
+ this.server.on('request', async (req, res) => {
52
+ try {
53
+ const valideUrl = new URL(`http://${req.headers.host}${req.url}`);
54
+ const hostname = valideUrl.hostname;
55
+
56
+ let organization = hosts[hostname];
57
+ if (!organization) {
58
+ let org = await this.crud.send({
59
+ method: 'object.read',
60
+ array: 'organizations',
61
+ $filter: {
62
+ query: [
63
+ { key: "host", value: [hostname], operator: "$in" }
64
+ ]
65
+ },
66
+ organization_id: process.env.organization_id
67
+ })
68
+
69
+ if (!org || !org.object || !org.object[0]) {
70
+ if (!hostNotFound)
71
+ hostNotFound = await getDefaultFile('/hostNotFound.html')
72
+ return sendResponse(hostNotFound.object[0].src, 404, { 'Content-Type': 'text/html', 'storage': organization.storage })
73
+ } else {
74
+ organization = org.object[0]
75
+ organizations[organization._id] = organization
76
+ hosts[hostname] = organization
77
+ }
78
+ }
79
+
80
+ if (valideUrl.pathname.startsWith('/webhooks/')) {
81
+ let name = req.url.split('/')[2]; // Assuming URL structure is /webhook/name/...
82
+ if (this.modules[name]) {
83
+ this.executeScriptWithTimeout(name, { req, res, crud: this.crud, organization, valideUrl })
84
+ } else {
85
+ // Handle unknown module or missing webhook method
86
+ res.writeHead(404, { 'Content-Type': 'application/json' });
87
+ res.end(JSON.stringify({ error: 'Not found' }));
88
+ }
89
+
90
+ } else {
91
+ this.files.send(req, res, this.crud, organization, valideUrl)
92
+ }
93
+
94
+ } catch (error) {
95
+ res.writeHead(400, { 'Content-Type': 'text/plain' });
96
+ res.end('Invalid host format');
97
+ }
98
+
99
+
100
+ })
45
101
 
46
102
  }
47
103
 
48
- async executeScriptWithTimeout(moduleName, moduleConfig) {
104
+ async executeScriptWithTimeout(name, data) {
49
105
  try {
50
- if (!moduleConfig.content) {
51
- if (moduleConfig.path)
52
- moduleConfig.content = await require(moduleConfig.path)
106
+ if (!this.modules[name].content) {
107
+ if (this.modules[name].path)
108
+ this.modules[name].content = await require(this.modules[name].path)
53
109
  else {
54
110
  try {
55
- const scriptPath = path.join(scriptsDirectory, `${moduleName}.js`);
111
+ const scriptPath = path.join(scriptsDirectory, `${name}.js`);
56
112
  await fs.access(scriptPath);
57
- moduleConfig.content = await fs.readFile(scriptPath, 'utf8');
113
+ this.modules[name].content = await fs.readFile(scriptPath, 'utf8');
58
114
  } catch {
59
- moduleConfig.content = await fetchScriptFromDatabaseAndSave(moduleName, moduleConfig);
115
+ this.modules[name].content = await fetchScriptFromDatabaseAndSave(name, this.modules[name], data);
60
116
  }
61
117
  }
62
118
  }
63
119
 
64
- if (moduleConfig.unload === false || moduleConfig.unload === 'false')
120
+ if (this.modules[name].content) {
121
+ data.apis = await this.getApiKey(data.organization_id, name)
122
+ data = await this.modules[name].content.send(data)
123
+ delete data.apis
124
+ if (data.socket)
125
+ this.wsManager.send(data)
126
+ } else
65
127
  return
66
- else if (moduleConfig.unload === true || moduleConfig.unload === 'true')
128
+
129
+ if (this.modules[name].unload === false || this.modules[name].unload === 'false')
130
+ return
131
+ else if (this.modules[name].unload === true || this.modules[name].unload === 'true')
67
132
  console.log('config should unload after completeion ')
68
- else if (moduleConfig.unload = parseInt(moduleConfig.unload, 10)) {
133
+ else if (this.modules[name].unload = parseInt(this.modules[name].unload, 10)) {
69
134
  // Check if the script is already loaded
70
- if (moduleConfig.timeout) {
71
- clearTimeout(moduleConfig.timeout);
72
- } else if (!moduleConfig.path) {
135
+ if (this.modules[name].timeout) {
136
+ clearTimeout(this.modules[name].timeout);
137
+ } else if (!this.modules[name].path) {
73
138
  // Execute the script
74
- moduleConfig.context = new vm.createContext({});
75
- const script = new vm.Script(moduleConfig.context);
139
+ this.modules[name].context = new vm.createContext({});
140
+ const script = new vm.Script(this.modules[name].context);
76
141
  script.runInContext(context);
77
142
  }
78
143
 
79
144
  // Reset or set the timeout
80
145
  const timeout = setTimeout(() => {
81
- delete this.modules[moduleName]
82
- delete moduleConfig.timeout
83
- delete moduleConfig.context
84
- delete moduleConfig.content
85
- console.log(`Module ${moduleName} removed due to inactivity.`);
86
- clearModuleCache(moduleName);
146
+ // delete this.modules[name]
147
+ delete this.modules[name].timeout
148
+ delete this.modules[name].context
149
+ delete this.modules[name].content
150
+ console.log(`Module ${name} removed due to inactivity.`);
151
+ clearModuleCache(name);
87
152
 
88
- }, moduleConfig.unload);
153
+ }, this.modules[name].unload);
89
154
 
90
- moduleConfig.timeout = timeout
155
+ this.modules[name].timeout = timeout
91
156
  }
92
157
  } catch (error) {
93
158
  console.log(error)
94
159
  }
95
160
  }
96
161
 
162
+ async getApiKey(organization_id, name) {
163
+ organizations[organization_id] = this.getOrganization(organization_id, name)
164
+ organizations[organization_id] = await organizations[organization_id]
165
+ return organizations[organization_id][name]
166
+ }
167
+
168
+ async getOrganization(organization_id) {
169
+ let organization = await this.crud.send({
170
+ method: 'object.read',
171
+ database: organization_id,
172
+ array: 'organizations',
173
+ object: [{ _id: organization_id }],
174
+ organization_id
175
+ })
176
+
177
+ if (organization
178
+ && organization.object
179
+ && organization.object[0]) {
180
+ if (organization.object[0].apis) {
181
+ return organization.object[0].apis
182
+ } else
183
+ return { error: 'No apis defined could not be found' }
184
+ } else {
185
+ return { serverOrganization: false, error: 'An organization could not be found' }
186
+ }
187
+
188
+ }
189
+
190
+
97
191
  }
98
192
 
99
193
  function getModuleDependencies(modulePath) {
@@ -106,7 +200,7 @@ function getModuleDependencies(modulePath) {
106
200
  return moduleObj.children.map(child => child.id);
107
201
  }
108
202
 
109
- function isModuleUsedElsewhere(modulePath, moduleName) {
203
+ function isModuleUsedElsewhere(modulePath, name) {
110
204
  return Object.keys(require.cache).some(path => {
111
205
  const moduleObj = require.cache[path];
112
206
  // return moduleObj.children.some(child => child.id === modulePath && path !== modulePath);
@@ -119,39 +213,39 @@ function isModuleUsedElsewhere(modulePath, moduleName) {
119
213
  });
120
214
  }
121
215
 
122
- function clearModuleCache(moduleName) {
216
+ function clearModuleCache(name) {
123
217
  try {
124
- const modulePath = require.resolve(moduleName);
218
+ const modulePath = require.resolve(name);
125
219
  const dependencies = getModuleDependencies(modulePath);
126
220
 
127
221
  // Check if the module is a dependency of other modules
128
222
  // const moduleObj = require.cache[modulePath];
129
223
  // if (moduleObj && moduleObj.parent) {
130
- // console.log(`Module ${moduleName} is a dependency of other modules.`);
224
+ // console.log(`Module ${name} is a dependency of other modules.`);
131
225
  // return;
132
226
  // }
133
227
 
134
228
  // Check if the module is used by other modules
135
- if (isModuleUsedElsewhere(modulePath, moduleName)) {
136
- console.log(`Module ${moduleName} is a dependency of other modules.`);
229
+ if (isModuleUsedElsewhere(modulePath, name)) {
230
+ console.log(`Module ${name} is a dependency of other modules.`);
137
231
  return;
138
232
  }
139
233
 
140
234
  // Remove the module from the cache
141
235
  delete require.cache[modulePath];
142
- console.log(`Module ${moduleName} has been removed from cache.`);
236
+ console.log(`Module ${name} has been removed from cache.`);
143
237
  // Recursively clear dependencies from cache
144
238
  dependencies.forEach(depPath => {
145
239
  clearModuleCache(depPath);
146
240
  });
147
241
 
148
242
  } catch (error) {
149
- console.error(`Error clearing module cache for ${moduleName}: ${error.message}`);
243
+ console.error(`Error clearing module cache for ${name}: ${error.message}`);
150
244
  }
151
245
  }
152
246
 
153
247
  // Function to fetch script from database and save to disk
154
- async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
248
+ async function fetchScriptFromDatabaseAndSave(name, moduleConfig) {
155
249
  let data = {
156
250
  method: 'object.read',
157
251
  array: moduleConfig.array,
@@ -165,7 +259,7 @@ async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
165
259
  organization_id
166
260
  };
167
261
 
168
- let file = await crud.send(data);
262
+ let file = await this.crud.send(data);
169
263
  let src;
170
264
 
171
265
  if (file && file.object && file.object[0]) {
@@ -175,7 +269,7 @@ async function fetchScriptFromDatabaseAndSave(moduleName, moduleConfig) {
175
269
  }
176
270
 
177
271
  // Save to disk for future use
178
- const scriptPath = path.join(scriptsDirectory, `${moduleName}.js`);
272
+ const scriptPath = path.join(scriptsDirectory, `${name}.js`);
179
273
  await fs.writeFile(scriptPath, src);
180
274
 
181
275
  return src;