@cocreate/file-server 1.17.1 → 1.18.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ ## [1.18.1](https://github.com/CoCreate-app/CoCreate-file-server/compare/v1.18.0...v1.18.1) (2024-12-22)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * pass url to render.HTML ([c5827c3](https://github.com/CoCreate-app/CoCreate-file-server/commit/c5827c3247998014d2717b0ff426e98c9dffc145))
7
+
8
+ # [1.18.0](https://github.com/CoCreate-app/CoCreate-file-server/compare/v1.17.1...v1.18.0) (2024-11-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * prettier.config options ([6fef07b](https://github.com/CoCreate-app/CoCreate-file-server/commit/6fef07b800b165da3ca2635a3e98fde80ac3e6a0))
14
+
15
+
16
+ ### Features
17
+
18
+ * add prettier.config.js and format files ([cc62b41](https://github.com/CoCreate-app/CoCreate-file-server/commit/cc62b41a411eded904bcf9f4e8b470299a9ae345))
19
+
1
20
  ## [1.17.1](https://github.com/CoCreate-app/CoCreate-file-server/compare/v1.17.0...v1.17.1) (2024-11-02)
2
21
 
3
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/file-server",
3
- "version": "1.17.1",
3
+ "version": "1.18.1",
4
4
  "description": "A simple file-server component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "file-server",
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ tabWidth: 4,
3
+ semi: true,
4
+ trailingComma: "none",
5
+ bracketSameLine: true,
6
+ useTabs: true,
7
+ overrides: [
8
+ {
9
+ files: ["*.json", "*.yml", "*.yaml"],
10
+ options: {
11
+ tabWidth: 2,
12
+ useTabs: false
13
+ },
14
+ }
15
+ ],
16
+ };
package/src/index.js CHANGED
@@ -21,250 +21,312 @@
21
21
  // For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
22
22
 
23
23
  class CoCreateFileSystem {
24
- constructor(render, sitemap) {
25
- this.render = render
26
- this.sitemap = sitemap
27
- }
28
-
29
- async send(req, res, crud, organization, valideUrl) {
30
- try {
31
- const hostname = valideUrl.hostname;
32
-
33
- let data = {
34
- method: 'object.read',
35
- host: hostname,
36
- array: 'files',
37
- $filter: {
38
- query: {
39
- host: { $in: [hostname, '*'] }
40
- },
41
- limit: 1
42
- }
43
- }
44
-
45
- let organization_id
46
- if (!organization || organization.error) {
47
- let hostNotFound = await getDefaultFile('/hostNotFound.html')
48
- return sendResponse(hostNotFound.object[0].src, 404, { 'Content-Type': 'text/html' })
49
- }
50
-
51
- organization_id = organization._id
52
- data.organization_id = organization_id
53
-
54
- res.setHeader('organization', organization_id)
55
- res.setHeader('storage', !!organization.storage);
56
- res.setHeader('Access-Control-Allow-Origin', '*');
57
- res.setHeader('Access-Control-Allow-Methods', '');
58
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
59
-
60
- let active = crud.wsManager.organizations.get(organization_id)
61
- if (active === false) {
62
- let balanceFalse = await getDefaultFile('/balanceFalse.html')
63
- return sendResponse(balanceFalse.object[0].src, 403, { 'Content-Type': 'text/html', 'Account-Balance': 'false', 'storage': organization.storage })
64
- }
65
-
66
- let parameters = valideUrl.searchParams;
67
- if (parameters.size) {
68
- console.log('parameters', parameters)
69
- }
70
-
71
- let pathname = valideUrl.pathname;
72
-
73
- if (pathname.endsWith('/')) {
74
- pathname += "index.html";
75
- } else if (!pathname.startsWith('/.well-known/acme-challenge')) {
76
- let directory = pathname.split("/").slice(-1)[0];
77
- if (!directory.includes('.'))
78
- pathname += "/index.html";
79
- }
80
-
81
- data.$filter.query.pathname = pathname
82
-
83
- let file
84
- if (pathname.startsWith('/dist') || pathname.startsWith('/admin') || ['/403.html', '/404.html', '/offline.html', '/manifest.webmanifest', '/service-worker.js'].includes(pathname))
85
- file = await getDefaultFile(pathname)
86
- else
87
- file = await crud.send(data);
88
-
89
- if (!file || !file.object || !file.object[0]) {
90
- pathname = valideUrl.pathname
91
- let lastIndex = pathname.lastIndexOf('/');
92
- let wildcardPath = pathname.substring(0, lastIndex + 1);
93
- let wildcard = pathname.substring(lastIndex + 1);
94
-
95
- if (wildcard.includes('.')) {
96
- let fileLastIndex = wildcard.lastIndexOf('.');
97
- let fileExtension = wildcard.substring(fileLastIndex);
98
- wildcard = wildcardPath + '*' + fileExtension; // Create wildcard for file name
99
- } else {
100
- wildcard = wildcardPath + '*/index.html'; // Append '*' if it's just a path or folder
101
- }
102
-
103
- data.$filter.query.pathname = wildcard
104
- file = await crud.send(data);
105
- }
106
-
107
- if (!file || !file.object || !file.object[0]) {
108
- let pageNotFound = await getDefaultFile('/404.html')
109
- return sendResponse(pageNotFound.object[0].src, 404, { 'Content-Type': 'text/html' })
110
- }
111
-
112
- file = file.object[0]
113
- if (!file['public'] || file['public'] === "false") {
114
- let pageForbidden = await getDefaultFile('/403.html')
115
- return sendResponse(pageForbidden.object[0].src, 403, { 'Content-Type': 'text/html' })
116
- }
117
-
118
- let src;
119
- if (file['src'])
120
- src = file['src'];
121
- else {
122
- let fileSrc = await crud.send({
123
- method: 'object.read',
124
- host: hostname,
125
- array: file['array'],
126
- object: {
127
- _id: file._id
128
- },
129
- organization_id
130
- });
131
- src = fileSrc[file['name']];
132
- }
133
-
134
- if (!src) {
135
- let pageNotFound = await getDefaultFile('/404.html')
136
- return sendResponse(pageNotFound.object[0].src, 404, { 'Content-Type': 'text/html' })
137
- }
138
-
139
-
140
- let modifiedOn = file.modified || file.created
141
- if (modifiedOn) {
142
- modifiedOn = modifiedOn.on
143
- if (modifiedOn instanceof Date)
144
- modifiedOn = modifiedOn.toISOString()
145
- res.setHeader('Last-Modified', modifiedOn);
146
- }
147
-
148
- let contentType = file['content-type'] || 'text/html';
149
-
150
- if (/^data:image\/[a-zA-Z0-9+.-]+;base64,([A-Za-z0-9+/]+={0,2})$/.test(src)) {
151
- src = src.replace(/^data:image\/(png|jpeg|jpg);base64,/, '');
152
- src = Buffer.from(src, 'base64');
153
- } else if (/^([A-Za-z0-9+/]+={0,2})$/.test(src)) {
154
- src = Buffer.from(src, 'base64');
155
- } else if (contentType === 'text/html') {
156
- try {
157
- src = await this.render.HTML(src, organization_id);
158
- } catch (err) {
159
- console.warn('server-side-render: ' + err.message)
160
- }
161
- } else if (contentType === 'text/xml' || contentType === 'application/xml') {
162
- const protocol = 'https://' // || req.headers['x-forwarded-proto'] || req.protocol;
163
- src = src.replaceAll('{{$host}}', `${protocol}${hostname}`)
164
- }
165
-
166
- sendResponse(src, 200, { 'Content-Type': contentType })
167
- this.sitemap.check(file, hostname);
168
-
169
- function sendResponse(src, statusCode, headers) {
170
- try {
171
- if (src instanceof Uint8Array) {
172
- src = Buffer.from(src);
173
- } else if (Buffer.isBuffer(src)) {
174
- console.log('buffer')
175
- return
176
- } else if (typeof src === 'object') {
177
- src = JSON.stringify(src);
178
- }
179
-
180
- if (organization_id)
181
- crud.wsManager.emit("setBandwidth", {
182
- type: 'out',
183
- data: src,
184
- organization_id
185
- });
186
- res.writeHead(statusCode, headers);
187
- return res.end(src);
188
- } catch (error) {
189
- console.log(error)
190
- }
191
- }
192
-
193
- async function getDefaultFile(fileName) {
194
- data.$filter.query.pathname = fileName
195
- // data.$filter.query.$or[0] = { pathname: fileName }
196
- let defaultFile
197
- if (fileName !== '/hostNotFound.html')
198
- defaultFile = await crud.send(data);
199
-
200
- if (defaultFile && defaultFile.object && defaultFile.object[0] && defaultFile.object[0].src) {
201
- return defaultFile
202
- } else {
203
- data.$filter.query.host.$in = ['*']
204
- data.organization_id = process.env.organization_id
205
-
206
- if (fileName.startsWith('/admin'))
207
- data.$filter.query.pathname = '/superadmin' + fileName.replace('/admin', '')
208
-
209
- defaultFile = await crud.send(data)
210
-
211
- if (fileName !== '/hostNotFound.html') {
212
- crud.wsManager.emit("setBandwidth", {
213
- type: 'out',
214
- data,
215
- organization_id
216
- });
217
-
218
- crud.wsManager.emit("setBandwidth", {
219
- type: 'in',
220
- data: defaultFile,
221
- organization_id
222
- });
223
- }
224
-
225
- if (defaultFile && defaultFile.object && defaultFile.object[0] && defaultFile.object[0].src) {
226
- if (fileName.startsWith('/admin')) {
227
- data.object[0].directory = 'admin'
228
- data.object[0].path = '/admin' + data.object[0].path.replace('/superadmin', '')
229
- data.object[0].pathname = fileName
230
- }
231
-
232
- crud.send({
233
- method: 'object.create',
234
- host: hostname,
235
- array: 'files',
236
- object: defaultFile.object[0],
237
- organization_id
238
- })
239
-
240
- return defaultFile
241
- } else {
242
- switch (fileName) {
243
- case '/403.html':
244
- defaultFile.object = [{ src: `${pathname} access not allowed for ${organization_id}` }]
245
- break;
246
- case '/404.html':
247
- defaultFile.object = [{ src: `${pathname} could not be found for ${organization_id}` }];
248
- break;
249
- case '/balanceFalse.html':
250
- defaultFile.object = [{ src: 'This organizations account balance has fallen bellow 0: ' }];
251
- break;
252
- case '/hostNotFound.html':
253
- defaultFile.object = [{ src: 'An organization could not be found using the host: ' + hostname + ' in platformDB: ' + process.env.organization_id }];
254
- break;
255
- }
256
- return defaultFile
257
- }
258
- }
259
- }
260
-
261
-
262
- } catch (error) {
263
- res.writeHead(400, { 'Content-Type': 'text/plain' });
264
- res.end('Invalid host format');
265
- }
266
- }
267
-
24
+ constructor(render, sitemap) {
25
+ this.render = render;
26
+ this.sitemap = sitemap;
27
+ }
28
+
29
+ async send(req, res, crud, organization, valideUrl) {
30
+ try {
31
+ const hostname = valideUrl.hostname;
32
+
33
+ let data = {
34
+ method: "object.read",
35
+ host: hostname,
36
+ array: "files",
37
+ $filter: {
38
+ query: {
39
+ host: { $in: [hostname, "*"] }
40
+ },
41
+ limit: 1
42
+ }
43
+ };
44
+
45
+ let organization_id;
46
+ if (!organization || organization.error) {
47
+ let hostNotFound = await getDefaultFile("/hostNotFound.html");
48
+ return sendResponse(hostNotFound.object[0].src, 404, {
49
+ "Content-Type": "text/html"
50
+ });
51
+ }
52
+
53
+ organization_id = organization._id;
54
+ data.organization_id = organization_id;
55
+
56
+ res.setHeader("organization", organization_id);
57
+ res.setHeader("storage", !!organization.storage);
58
+ res.setHeader("Access-Control-Allow-Origin", "*");
59
+ res.setHeader("Access-Control-Allow-Methods", "");
60
+ res.setHeader(
61
+ "Access-Control-Allow-Headers",
62
+ "Content-Type, Authorization"
63
+ );
64
+
65
+ let active = crud.wsManager.organizations.get(organization_id);
66
+ if (active === false) {
67
+ let balanceFalse = await getDefaultFile("/balanceFalse.html");
68
+ return sendResponse(balanceFalse.object[0].src, 403, {
69
+ "Content-Type": "text/html",
70
+ "Account-Balance": "false",
71
+ storage: organization.storage
72
+ });
73
+ }
74
+
75
+ let parameters = valideUrl.searchParams;
76
+ if (parameters.size) {
77
+ console.log("parameters", parameters);
78
+ }
79
+
80
+ let pathname = valideUrl.pathname;
81
+
82
+ if (pathname.endsWith("/")) {
83
+ pathname += "index.html";
84
+ } else if (!pathname.startsWith("/.well-known/acme-challenge")) {
85
+ let directory = pathname.split("/").slice(-1)[0];
86
+ if (!directory.includes(".")) pathname += "/index.html";
87
+ }
88
+
89
+ data.$filter.query.pathname = pathname;
90
+
91
+ let file;
92
+ if (
93
+ pathname.startsWith("/dist") ||
94
+ pathname.startsWith("/admin") ||
95
+ [
96
+ "/403.html",
97
+ "/404.html",
98
+ "/offline.html",
99
+ "/manifest.webmanifest",
100
+ "/service-worker.js"
101
+ ].includes(pathname)
102
+ )
103
+ file = await getDefaultFile(pathname);
104
+ else file = await crud.send(data);
105
+
106
+ if (!file || !file.object || !file.object[0]) {
107
+ pathname = valideUrl.pathname;
108
+ let lastIndex = pathname.lastIndexOf("/");
109
+ let wildcardPath = pathname.substring(0, lastIndex + 1);
110
+ let wildcard = pathname.substring(lastIndex + 1);
111
+
112
+ if (wildcard.includes(".")) {
113
+ let fileLastIndex = wildcard.lastIndexOf(".");
114
+ let fileExtension = wildcard.substring(fileLastIndex);
115
+ wildcard = wildcardPath + "*" + fileExtension; // Create wildcard for file name
116
+ } else {
117
+ wildcard = wildcardPath + "*/index.html"; // Append '*' if it's just a path or folder
118
+ }
119
+
120
+ data.$filter.query.pathname = wildcard;
121
+ file = await crud.send(data);
122
+ }
123
+
124
+ if (!file || !file.object || !file.object[0]) {
125
+ let pageNotFound = await getDefaultFile("/404.html");
126
+ return sendResponse(pageNotFound.object[0].src, 404, {
127
+ "Content-Type": "text/html"
128
+ });
129
+ }
130
+
131
+ file = file.object[0];
132
+ if (!file["public"] || file["public"] === "false") {
133
+ let pageForbidden = await getDefaultFile("/403.html");
134
+ return sendResponse(pageForbidden.object[0].src, 403, {
135
+ "Content-Type": "text/html"
136
+ });
137
+ }
138
+
139
+ let src;
140
+ if (file["src"]) src = file["src"];
141
+ else {
142
+ let fileSrc = await crud.send({
143
+ method: "object.read",
144
+ host: hostname,
145
+ array: file["array"],
146
+ object: {
147
+ _id: file._id
148
+ },
149
+ organization_id
150
+ });
151
+ src = fileSrc[file["name"]];
152
+ }
153
+
154
+ if (!src) {
155
+ let pageNotFound = await getDefaultFile("/404.html");
156
+ return sendResponse(pageNotFound.object[0].src, 404, {
157
+ "Content-Type": "text/html"
158
+ });
159
+ }
160
+
161
+ let modifiedOn = file.modified || file.created;
162
+ if (modifiedOn) {
163
+ modifiedOn = modifiedOn.on;
164
+ if (modifiedOn instanceof Date)
165
+ modifiedOn = modifiedOn.toISOString();
166
+ res.setHeader("Last-Modified", modifiedOn);
167
+ }
168
+
169
+ let contentType = file["content-type"] || "text/html";
170
+
171
+ if (
172
+ /^data:image\/[a-zA-Z0-9+.-]+;base64,([A-Za-z0-9+/]+={0,2})$/.test(
173
+ src
174
+ )
175
+ ) {
176
+ src = src.replace(/^data:image\/(png|jpeg|jpg);base64,/, "");
177
+ src = Buffer.from(src, "base64");
178
+ } else if (/^([A-Za-z0-9+/]+={0,2})$/.test(src)) {
179
+ src = Buffer.from(src, "base64");
180
+ } else if (contentType === "text/html") {
181
+ try {
182
+ src = await this.render.HTML(
183
+ src,
184
+ organization_id,
185
+ valideUrl
186
+ );
187
+ } catch (err) {
188
+ console.warn("server-side-render: " + err.message);
189
+ }
190
+ } else if (
191
+ contentType === "text/xml" ||
192
+ contentType === "application/xml"
193
+ ) {
194
+ const protocol = "https://"; // || req.headers['x-forwarded-proto'] || req.protocol;
195
+ src = src.replaceAll("{{$host}}", `${protocol}${hostname}`);
196
+ }
197
+
198
+ sendResponse(src, 200, { "Content-Type": contentType });
199
+ this.sitemap.check(file, hostname);
200
+
201
+ function sendResponse(src, statusCode, headers) {
202
+ try {
203
+ if (src instanceof Uint8Array) {
204
+ src = Buffer.from(src);
205
+ } else if (Buffer.isBuffer(src)) {
206
+ console.log("buffer");
207
+ return;
208
+ } else if (typeof src === "object") {
209
+ src = JSON.stringify(src);
210
+ }
211
+
212
+ if (organization_id)
213
+ crud.wsManager.emit("setBandwidth", {
214
+ type: "out",
215
+ data: src,
216
+ organization_id
217
+ });
218
+ res.writeHead(statusCode, headers);
219
+ return res.end(src);
220
+ } catch (error) {
221
+ console.log(error);
222
+ }
223
+ }
224
+
225
+ async function getDefaultFile(fileName) {
226
+ data.$filter.query.pathname = fileName;
227
+ // data.$filter.query.$or[0] = { pathname: fileName }
228
+ let defaultFile;
229
+ if (fileName !== "/hostNotFound.html")
230
+ defaultFile = await crud.send(data);
231
+
232
+ if (
233
+ defaultFile &&
234
+ defaultFile.object &&
235
+ defaultFile.object[0] &&
236
+ defaultFile.object[0].src
237
+ ) {
238
+ return defaultFile;
239
+ } else {
240
+ data.$filter.query.host.$in = ["*"];
241
+ data.organization_id = process.env.organization_id;
242
+
243
+ if (fileName.startsWith("/admin"))
244
+ data.$filter.query.pathname =
245
+ "/superadmin" + fileName.replace("/admin", "");
246
+
247
+ defaultFile = await crud.send(data);
248
+
249
+ if (fileName !== "/hostNotFound.html") {
250
+ crud.wsManager.emit("setBandwidth", {
251
+ type: "out",
252
+ data,
253
+ organization_id
254
+ });
255
+
256
+ crud.wsManager.emit("setBandwidth", {
257
+ type: "in",
258
+ data: defaultFile,
259
+ organization_id
260
+ });
261
+ }
262
+
263
+ if (
264
+ defaultFile &&
265
+ defaultFile.object &&
266
+ defaultFile.object[0] &&
267
+ defaultFile.object[0].src
268
+ ) {
269
+ if (fileName.startsWith("/admin")) {
270
+ data.object[0].directory = "admin";
271
+ data.object[0].path =
272
+ "/admin" +
273
+ data.object[0].path.replace("/superadmin", "");
274
+ data.object[0].pathname = fileName;
275
+ }
276
+
277
+ crud.send({
278
+ method: "object.create",
279
+ host: hostname,
280
+ array: "files",
281
+ object: defaultFile.object[0],
282
+ organization_id
283
+ });
284
+
285
+ return defaultFile;
286
+ } else {
287
+ switch (fileName) {
288
+ case "/403.html":
289
+ defaultFile.object = [
290
+ {
291
+ src: `${pathname} access not allowed for ${organization_id}`
292
+ }
293
+ ];
294
+ break;
295
+ case "/404.html":
296
+ defaultFile.object = [
297
+ {
298
+ src: `${pathname} could not be found for ${organization_id}`
299
+ }
300
+ ];
301
+ break;
302
+ case "/balanceFalse.html":
303
+ defaultFile.object = [
304
+ {
305
+ src: "This organizations account balance has fallen bellow 0: "
306
+ }
307
+ ];
308
+ break;
309
+ case "/hostNotFound.html":
310
+ defaultFile.object = [
311
+ {
312
+ src:
313
+ "An organization could not be found using the host: " +
314
+ hostname +
315
+ " in platformDB: " +
316
+ process.env.organization_id
317
+ }
318
+ ];
319
+ break;
320
+ }
321
+ return defaultFile;
322
+ }
323
+ }
324
+ }
325
+ } catch (error) {
326
+ res.writeHead(400, { "Content-Type": "text/plain" });
327
+ res.end("Invalid host format");
328
+ }
329
+ }
268
330
  }
269
331
 
270
332
  module.exports = CoCreateFileSystem;