@trayio/express
Advanced tools
Comparing version 3.8.0 to 3.9.0
@@ -25,11 +25,2 @@ "use strict"; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -47,138 +38,140 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
class ExpressHttpController { | ||
controller; | ||
baseTmpPathForUploadedFiles; | ||
constructor(controller, baseTmpPathForUploadedFiles = '/tmp') { | ||
this.controller = controller; | ||
this.baseTmpPathForUploadedFiles = baseTmpPathForUploadedFiles; | ||
this.addRoute = (endpoint) => { | ||
const route = (req, res) => __awaiter(this, void 0, void 0, function* () { | ||
const headers = Object.entries(req.headers).reduce((acc, [key, value]) => { | ||
const newValue = typeof value === 'undefined' ? '' : value; | ||
return Object.assign(Object.assign({}, acc), { [key]: newValue }); | ||
}, {}); | ||
const requestBody = yield this.parseRequestBody(req); | ||
const httpResponse = yield endpoint.execute({ | ||
headers, | ||
pathParams: req.params, | ||
queryString: req.query, | ||
body: requestBody, | ||
})(); | ||
const response = Object.entries(httpResponse.headers) | ||
.reduce((acc, [key, value]) => acc.setHeader(key, value), res) | ||
.status(httpResponse.statusCode); | ||
httpResponse.body.pipe(response); | ||
}); | ||
let method; | ||
switch (endpoint.method) { | ||
case Http_1.HttpMethod.Get: | ||
method = 'get'; | ||
break; | ||
case Http_1.HttpMethod.Post: | ||
method = 'post'; | ||
break; | ||
case Http_1.HttpMethod.Put: | ||
method = 'put'; | ||
break; | ||
case Http_1.HttpMethod.Delete: | ||
method = 'delete'; | ||
break; | ||
case Http_1.HttpMethod.Patch: | ||
method = 'patch'; | ||
break; | ||
default: | ||
method = 'get'; | ||
break; | ||
} | ||
return (router) => router[method](endpoint.path, route); | ||
} | ||
addRoute = (endpoint) => { | ||
const route = async (req, res) => { | ||
const headers = Object.entries(req.headers).reduce((acc, [key, value]) => { | ||
const newValue = typeof value === 'undefined' ? '' : value; | ||
return { | ||
...acc, | ||
[key]: newValue, | ||
}; | ||
}, {}); | ||
const requestBody = await this.parseRequestBody(req); | ||
const httpResponse = await endpoint.execute({ | ||
headers, | ||
pathParams: req.params, | ||
queryString: req.query, | ||
body: requestBody, | ||
})(); | ||
const response = Object.entries(httpResponse.headers) | ||
.reduce((acc, [key, value]) => acc.setHeader(key, value), res) | ||
.status(httpResponse.statusCode); | ||
httpResponse.body.pipe(response); | ||
}; | ||
this.addRoutes = (router) => { | ||
this.controller | ||
.getEndpoints() | ||
.forEach((endpoint) => this.addRoute(endpoint)(router)); | ||
return router; | ||
}; | ||
this.parseRequestBody = (req) => __awaiter(this, void 0, void 0, function* () { | ||
const contentType = req.headers['content-type']; | ||
if (contentType && contentType.startsWith('multipart/form-data')) { | ||
const multiPartResponse = yield this.parseMultipartFormData(req)(); | ||
const multiPartBody = E.getOrElse((error) => { | ||
throw new Error(error.message); | ||
})(multiPartResponse); | ||
return multiPartBody; | ||
let method; | ||
switch (endpoint.method) { | ||
case Http_1.HttpMethod.Get: | ||
method = 'get'; | ||
break; | ||
case Http_1.HttpMethod.Post: | ||
method = 'post'; | ||
break; | ||
case Http_1.HttpMethod.Put: | ||
method = 'put'; | ||
break; | ||
case Http_1.HttpMethod.Delete: | ||
method = 'delete'; | ||
break; | ||
case Http_1.HttpMethod.Patch: | ||
method = 'patch'; | ||
break; | ||
default: | ||
method = 'get'; | ||
break; | ||
} | ||
return (router) => router[method](endpoint.path, route); | ||
}; | ||
addRoutes = (router) => { | ||
this.controller | ||
.getEndpoints() | ||
.forEach((endpoint) => this.addRoute(endpoint)(router)); | ||
return router; | ||
}; | ||
parseRequestBody = async (req) => { | ||
const contentType = req.headers['content-type']; | ||
if (contentType && contentType.startsWith('multipart/form-data')) { | ||
const multiPartResponse = await this.parseMultipartFormData(req)(); | ||
const multiPartBody = E.getOrElse((error) => { | ||
throw new Error(error.message); | ||
})(multiPartResponse); | ||
return multiPartBody; | ||
} | ||
return this.parseGeneralRequestBody(req); | ||
}; | ||
// express defaults empty request body to an empty object, so we need to transform to an array buffer | ||
parseGeneralRequestBody = (req) => { | ||
const body = Object.keys(req.body).length === 0 ? new ArrayBuffer(0) : req.body; | ||
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(body); | ||
}; | ||
parseMultipartFormData = (req) => TE.tryCatch(() => new Promise((resolve, reject) => { | ||
/* | ||
* NOTE: inorder to use any other underlying file storage other than node fs, we would have to use | ||
* formidable's fileWriteStreamHandler option that enables formidable to write a file to a stream. | ||
* When used the fileWriteStreamHandler option with passThrough stream, we ran into errors that we didn't have | ||
* time to solve, but ideally, we would be using the FileStorage interface instead of letting formidable | ||
* write to the file system directly. | ||
*/ | ||
const form = (0, formidable_1.default)({ | ||
maxFiles: 1, | ||
maxFileSize: 50 * 1024 * 1024, | ||
uploadDir: this.baseTmpPathForUploadedFiles, | ||
}); | ||
form.parse(req, (err, fields, files) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
return this.parseGeneralRequestBody(req); | ||
else { | ||
const body = { | ||
fields: this.flattenFields(fields), | ||
files: this.flattenFiles(files), | ||
}; | ||
resolve(body); | ||
} | ||
}); | ||
// express defaults empty request body to an empty object, so we need to transform to an array buffer | ||
this.parseGeneralRequestBody = (req) => { | ||
const body = Object.keys(req.body).length === 0 ? new ArrayBuffer(0) : req.body; | ||
return BufferExtensions_1.BufferExtensions.arrayBufferToReadable(body); | ||
}; | ||
this.parseMultipartFormData = (req) => TE.tryCatch(() => new Promise((resolve, reject) => { | ||
/* | ||
* NOTE: inorder to use any other underlying file storage other than node fs, we would have to use | ||
* formidable's fileWriteStreamHandler option that enables formidable to write a file to a stream. | ||
* When used the fileWriteStreamHandler option with passThrough stream, we ran into errors that we didn't have | ||
* time to solve, but ideally, we would be using the FileStorage interface instead of letting formidable | ||
* write to the file system directly. | ||
*/ | ||
const form = (0, formidable_1.default)({ | ||
maxFiles: 1, | ||
maxFileSize: 50 * 1024 * 1024, | ||
uploadDir: this.baseTmpPathForUploadedFiles, | ||
}); | ||
form.parse(req, (err, fields, files) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
const body = { | ||
fields: this.flattenFields(fields), | ||
files: this.flattenFiles(files), | ||
}; | ||
resolve(body); | ||
} | ||
}); | ||
}), (error) => new Error(error.message)); | ||
this.flattenFields = (fields) => { | ||
const flattenedFields = {}; | ||
Object.entries(fields).forEach(([key, value]) => { | ||
if (Array.isArray(value) && value.length > 1) { | ||
throw new Error(`Field ${key} has more than one value and is current not supported`); | ||
} | ||
if (Array.isArray(value)) { | ||
flattenedFields[key] = value.join(','); | ||
} | ||
else { | ||
flattenedFields[key] = value !== null && value !== void 0 ? value : ''; | ||
} | ||
}); | ||
return flattenedFields; | ||
}; | ||
this.flattenFiles = (files) => { | ||
const flattenedFiles = {}; | ||
Object.entries(files) | ||
.filter(([key, file]) => file !== null) | ||
.forEach(([key, file]) => { | ||
if (Array.isArray(file) && file.length > 1) { | ||
throw new Error(`Field ${key} has more than one file and is currently not supported`); | ||
} | ||
if (Array.isArray(file)) { | ||
const fileContent = this.convertFormidableFileToTrayFile(file[0]); | ||
flattenedFiles[key] = fileContent; | ||
} | ||
}); | ||
return flattenedFiles; | ||
}; | ||
this.convertFormidableFileToTrayFile = (file) => { | ||
var _a; | ||
return ({ | ||
key: file.newFilename, | ||
metadata: { | ||
name: file.newFilename, | ||
contentType: (_a = file.mimetype) !== null && _a !== void 0 ? _a : undefined, | ||
size: file.size, | ||
}, | ||
content: stream_1.Readable.from('0'), | ||
}); | ||
}; | ||
} | ||
}), (error) => new Error(error.message)); | ||
flattenFields = (fields) => { | ||
const flattenedFields = {}; | ||
Object.entries(fields).forEach(([key, value]) => { | ||
if (Array.isArray(value) && value.length > 1) { | ||
throw new Error(`Field ${key} has more than one value and is current not supported`); | ||
} | ||
if (Array.isArray(value)) { | ||
flattenedFields[key] = value.join(','); | ||
} | ||
else { | ||
flattenedFields[key] = value ?? ''; | ||
} | ||
}); | ||
return flattenedFields; | ||
}; | ||
flattenFiles = (files) => { | ||
const flattenedFiles = {}; | ||
Object.entries(files) | ||
.filter(([key, file]) => file !== null) | ||
.forEach(([key, file]) => { | ||
if (Array.isArray(file) && file.length > 1) { | ||
throw new Error(`Field ${key} has more than one file and is currently not supported`); | ||
} | ||
if (Array.isArray(file)) { | ||
const fileContent = this.convertFormidableFileToTrayFile(file[0]); | ||
flattenedFiles[key] = fileContent; | ||
} | ||
}); | ||
return flattenedFiles; | ||
}; | ||
convertFormidableFileToTrayFile = (file) => ({ | ||
key: file.newFilename, | ||
metadata: { | ||
name: file.newFilename, | ||
contentType: file.mimetype ?? undefined, | ||
size: file.size, | ||
}, | ||
content: stream_1.Readable.from('0'), | ||
}); | ||
} | ||
exports.ExpressHttpController = ExpressHttpController; |
@@ -7,4 +7,3 @@ "use strict"; | ||
const startServer = (controllers, options) => { | ||
var _a; | ||
const port = (_a = options.port) !== null && _a !== void 0 ? _a : 3000; | ||
const port = options.port ?? 3000; | ||
const app = express(); | ||
@@ -11,0 +10,0 @@ const router = express.Router(); |
{ | ||
"name": "@trayio/express", | ||
"version": "3.8.0", | ||
"version": "3.9.0", | ||
"description": "Express extensions and implementations", | ||
@@ -17,3 +17,3 @@ "exports": { | ||
"dependencies": { | ||
"@trayio/commons": "3.8.0", | ||
"@trayio/commons": "3.9.0", | ||
"cors": "2.8.5", | ||
@@ -20,0 +20,0 @@ "express": "4.18.2", |
10783
225
+ Added@trayio/commons@3.9.0(transitive)
- Removed@trayio/commons@3.8.0(transitive)
Updated@trayio/commons@3.9.0