@trayio/express 3.8.0 → 3.9.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.
|
@@ -22,15 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
@@ -43,140 +34,142 @@ const BufferExtensions_1 = require("@trayio/commons/buffer/BufferExtensions");
|
|
|
43
34
|
const formidable_1 = __importDefault(require("formidable"));
|
|
44
35
|
const stream_1 = require("stream");
|
|
45
36
|
class ExpressHttpController {
|
|
37
|
+
controller;
|
|
38
|
+
baseTmpPathForUploadedFiles;
|
|
46
39
|
constructor(controller, baseTmpPathForUploadedFiles = '/tmp') {
|
|
47
40
|
this.controller = controller;
|
|
48
41
|
this.baseTmpPathForUploadedFiles = baseTmpPathForUploadedFiles;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
method = 'get';
|
|
71
|
-
break;
|
|
72
|
-
case Http_1.HttpMethod.Post:
|
|
73
|
-
method = 'post';
|
|
74
|
-
break;
|
|
75
|
-
case Http_1.HttpMethod.Put:
|
|
76
|
-
method = 'put';
|
|
77
|
-
break;
|
|
78
|
-
case Http_1.HttpMethod.Delete:
|
|
79
|
-
method = 'delete';
|
|
80
|
-
break;
|
|
81
|
-
case Http_1.HttpMethod.Patch:
|
|
82
|
-
method = 'patch';
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
method = 'get';
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
return (router) => router[method](endpoint.path, route);
|
|
89
|
-
};
|
|
90
|
-
this.addRoutes = (router) => {
|
|
91
|
-
this.controller
|
|
92
|
-
.getEndpoints()
|
|
93
|
-
.forEach((endpoint) => this.addRoute(endpoint)(router));
|
|
94
|
-
return router;
|
|
42
|
+
}
|
|
43
|
+
addRoute = (endpoint) => {
|
|
44
|
+
const route = async (req, res) => {
|
|
45
|
+
const headers = Object.entries(req.headers).reduce((acc, [key, value]) => {
|
|
46
|
+
const newValue = typeof value === 'undefined' ? '' : value;
|
|
47
|
+
return {
|
|
48
|
+
...acc,
|
|
49
|
+
[key]: newValue,
|
|
50
|
+
};
|
|
51
|
+
}, {});
|
|
52
|
+
const requestBody = await this.parseRequestBody(req);
|
|
53
|
+
const httpResponse = await endpoint.execute({
|
|
54
|
+
headers,
|
|
55
|
+
pathParams: req.params,
|
|
56
|
+
queryString: req.query,
|
|
57
|
+
body: requestBody,
|
|
58
|
+
})();
|
|
59
|
+
const response = Object.entries(httpResponse.headers)
|
|
60
|
+
.reduce((acc, [key, value]) => acc.setHeader(key, value), res)
|
|
61
|
+
.status(httpResponse.statusCode);
|
|
62
|
+
httpResponse.body.pipe(response);
|
|
95
63
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
64
|
+
let method;
|
|
65
|
+
switch (endpoint.method) {
|
|
66
|
+
case Http_1.HttpMethod.Get:
|
|
67
|
+
method = 'get';
|
|
68
|
+
break;
|
|
69
|
+
case Http_1.HttpMethod.Post:
|
|
70
|
+
method = 'post';
|
|
71
|
+
break;
|
|
72
|
+
case Http_1.HttpMethod.Put:
|
|
73
|
+
method = 'put';
|
|
74
|
+
break;
|
|
75
|
+
case Http_1.HttpMethod.Delete:
|
|
76
|
+
method = 'delete';
|
|
77
|
+
break;
|
|
78
|
+
case Http_1.HttpMethod.Patch:
|
|
79
|
+
method = 'patch';
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
method = 'get';
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
return (router) => router[method](endpoint.path, route);
|
|
86
|
+
};
|
|
87
|
+
addRoutes = (router) => {
|
|
88
|
+
this.controller
|
|
89
|
+
.getEndpoints()
|
|
90
|
+
.forEach((endpoint) => this.addRoute(endpoint)(router));
|
|
91
|
+
return router;
|
|
92
|
+
};
|
|
93
|
+
parseRequestBody = async (req) => {
|
|
94
|
+
const contentType = req.headers['content-type'];
|
|
95
|
+
if (contentType && contentType.startsWith('multipart/form-data')) {
|
|
96
|
+
const multiPartResponse = await this.parseMultipartFormData(req)();
|
|
97
|
+
const multiPartBody = E.getOrElse((error) => {
|
|
98
|
+
throw new Error(error.message);
|
|
99
|
+
})(multiPartResponse);
|
|
100
|
+
return multiPartBody;
|
|
101
|
+
}
|
|
102
|
+
return this.parseGeneralRequestBody(req);
|
|
103
|
+
};
|
|
104
|
+
// express defaults empty request body to an empty object, so we need to transform to an array buffer
|
|
105
|
+
parseGeneralRequestBody = (req) => {
|
|
106
|
+
const body = Object.keys(req.body).length === 0 ? new ArrayBuffer(0) : req.body;
|
|
107
|
+
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(body);
|
|
108
|
+
};
|
|
109
|
+
parseMultipartFormData = (req) => TE.tryCatch(() => new Promise((resolve, reject) => {
|
|
110
|
+
/*
|
|
111
|
+
* NOTE: inorder to use any other underlying file storage other than node fs, we would have to use
|
|
112
|
+
* formidable's fileWriteStreamHandler option that enables formidable to write a file to a stream.
|
|
113
|
+
* When used the fileWriteStreamHandler option with passThrough stream, we ran into errors that we didn't have
|
|
114
|
+
* time to solve, but ideally, we would be using the FileStorage interface instead of letting formidable
|
|
115
|
+
* write to the file system directly.
|
|
116
|
+
*/
|
|
117
|
+
const form = (0, formidable_1.default)({
|
|
118
|
+
maxFiles: 1,
|
|
119
|
+
maxFileSize: 50 * 1024 * 1024,
|
|
120
|
+
uploadDir: this.baseTmpPathForUploadedFiles,
|
|
121
|
+
});
|
|
122
|
+
form.parse(req, (err, fields, files) => {
|
|
123
|
+
if (err) {
|
|
124
|
+
reject(err);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const body = {
|
|
128
|
+
fields: this.flattenFields(fields),
|
|
129
|
+
files: this.flattenFiles(files),
|
|
130
|
+
};
|
|
131
|
+
resolve(body);
|
|
104
132
|
}
|
|
105
|
-
return this.parseGeneralRequestBody(req);
|
|
106
133
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
else {
|
|
148
|
-
flattenedFields[key] = value !== null && value !== void 0 ? value : '';
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
return flattenedFields;
|
|
152
|
-
};
|
|
153
|
-
this.flattenFiles = (files) => {
|
|
154
|
-
const flattenedFiles = {};
|
|
155
|
-
Object.entries(files)
|
|
156
|
-
.filter(([key, file]) => file !== null)
|
|
157
|
-
.forEach(([key, file]) => {
|
|
158
|
-
if (Array.isArray(file) && file.length > 1) {
|
|
159
|
-
throw new Error(`Field ${key} has more than one file and is currently not supported`);
|
|
160
|
-
}
|
|
161
|
-
if (Array.isArray(file)) {
|
|
162
|
-
const fileContent = this.convertFormidableFileToTrayFile(file[0]);
|
|
163
|
-
flattenedFiles[key] = fileContent;
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
return flattenedFiles;
|
|
167
|
-
};
|
|
168
|
-
this.convertFormidableFileToTrayFile = (file) => {
|
|
169
|
-
var _a;
|
|
170
|
-
return ({
|
|
171
|
-
key: file.newFilename,
|
|
172
|
-
metadata: {
|
|
173
|
-
name: file.newFilename,
|
|
174
|
-
contentType: (_a = file.mimetype) !== null && _a !== void 0 ? _a : undefined,
|
|
175
|
-
size: file.size,
|
|
176
|
-
},
|
|
177
|
-
content: stream_1.Readable.from('0'),
|
|
178
|
-
});
|
|
179
|
-
};
|
|
180
|
-
}
|
|
134
|
+
}), (error) => new Error(error.message));
|
|
135
|
+
flattenFields = (fields) => {
|
|
136
|
+
const flattenedFields = {};
|
|
137
|
+
Object.entries(fields).forEach(([key, value]) => {
|
|
138
|
+
if (Array.isArray(value) && value.length > 1) {
|
|
139
|
+
throw new Error(`Field ${key} has more than one value and is current not supported`);
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
flattenedFields[key] = value.join(',');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
flattenedFields[key] = value ?? '';
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return flattenedFields;
|
|
149
|
+
};
|
|
150
|
+
flattenFiles = (files) => {
|
|
151
|
+
const flattenedFiles = {};
|
|
152
|
+
Object.entries(files)
|
|
153
|
+
.filter(([key, file]) => file !== null)
|
|
154
|
+
.forEach(([key, file]) => {
|
|
155
|
+
if (Array.isArray(file) && file.length > 1) {
|
|
156
|
+
throw new Error(`Field ${key} has more than one file and is currently not supported`);
|
|
157
|
+
}
|
|
158
|
+
if (Array.isArray(file)) {
|
|
159
|
+
const fileContent = this.convertFormidableFileToTrayFile(file[0]);
|
|
160
|
+
flattenedFiles[key] = fileContent;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return flattenedFiles;
|
|
164
|
+
};
|
|
165
|
+
convertFormidableFileToTrayFile = (file) => ({
|
|
166
|
+
key: file.newFilename,
|
|
167
|
+
metadata: {
|
|
168
|
+
name: file.newFilename,
|
|
169
|
+
contentType: file.mimetype ?? undefined,
|
|
170
|
+
size: file.size,
|
|
171
|
+
},
|
|
172
|
+
content: stream_1.Readable.from('0'),
|
|
173
|
+
});
|
|
181
174
|
}
|
|
182
175
|
exports.ExpressHttpController = ExpressHttpController;
|
|
@@ -4,8 +4,7 @@ exports.startServer = void 0;
|
|
|
4
4
|
const express = require("express");
|
|
5
5
|
const cors = require("cors");
|
|
6
6
|
const startServer = (controllers, options) => {
|
|
7
|
-
|
|
8
|
-
const port = (_a = options.port) !== null && _a !== void 0 ? _a : 3000;
|
|
7
|
+
const port = options.port ?? 3000;
|
|
9
8
|
const app = express();
|
|
10
9
|
const router = express.Router();
|
|
11
10
|
app.use(cors());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trayio/express",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "Express extensions and implementations",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./*": "./dist/*.js"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"access": "public"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@trayio/commons": "3.
|
|
17
|
+
"@trayio/commons": "3.9.0",
|
|
18
18
|
"cors": "2.8.5",
|
|
19
19
|
"express": "4.18.2",
|
|
20
20
|
"formidable": "3.5.1"
|