@lucaapp/service-utils 1.56.1 → 1.56.3

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.
@@ -8,6 +8,7 @@ const zod_1 = require("zod");
8
8
  const assert_1 = __importDefault(require("assert"));
9
9
  const http_1 = require("./types/http");
10
10
  const libphonenumber_js_1 = require("libphonenumber-js");
11
+ const busboy_1 = __importDefault(require("busboy"));
11
12
  const sendBadContextError = (response, error, debug) => {
12
13
  response.err = error;
13
14
  return response.status(500).send({
@@ -146,6 +147,45 @@ const validateAndSendResponse = async (expressResponse, response, validResponses
146
147
  sendErrorResponse(expressResponse, error, undefined, debug);
147
148
  }
148
149
  };
150
+ async function stream2buffer(stream) {
151
+ return new Promise((resolve, reject) => {
152
+ const buf = [];
153
+ stream.on('data', chunk => buf.push(chunk));
154
+ stream.on('end', () => resolve(Buffer.concat(buf)));
155
+ stream.on('error', error => reject(error));
156
+ });
157
+ }
158
+ function handleFileUpload(request) {
159
+ return new Promise(resolve => {
160
+ const bb = (0, busboy_1.default)({
161
+ headers: request.headers,
162
+ defCharset: 'utf8',
163
+ limits: {
164
+ fileSize: 20 * 1024 * 1024, // 20 mb
165
+ files: 1,
166
+ },
167
+ });
168
+ let file = undefined;
169
+ bb.on('file', async (fieldname, fileStream, filename) => {
170
+ const { encoding, mimetype, filename: name } = filename;
171
+ const originalName = Buffer.from(name, 'latin1').toString('utf8');
172
+ const fileBuffer = await stream2buffer(fileStream);
173
+ file = {
174
+ buffer: fileBuffer,
175
+ originalname: originalName,
176
+ encoding,
177
+ mimetype,
178
+ size: fileBuffer.length,
179
+ fieldname: fieldname,
180
+ filename: name,
181
+ };
182
+ });
183
+ bb.on('finish', () => {
184
+ resolve(file);
185
+ });
186
+ request.pipe(bb);
187
+ });
188
+ }
149
189
  const handleMiddleware = async (middleware, context, request, response, debug) =>
150
190
  // resolves true when next middleware should continue
151
191
  // resolves false when a response was sent and next middleware should not be called
@@ -174,8 +214,14 @@ new Promise(async (resolve) => {
174
214
  throw error;
175
215
  }
176
216
  const { ip, baseUrl, originalUrl, route, method } = request;
217
+ let file = undefined;
218
+ if (request.headers['content-type']?.includes('multipart/form-data')) {
219
+ file = await handleFileUpload(request);
220
+ }
221
+ // if the header is multipart we should return a buffer with the content
177
222
  const handlerRequest = {
178
223
  body: handlerRequestBody,
224
+ ...(file && { file }),
179
225
  params: handlerRequestParams,
180
226
  query: handlerRequestQuery,
181
227
  headers: handlerRequestHeaders,
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { z } from 'zod';
2
3
  import { ArrayToUnion, ExtractZodOutput, ZodSchemaOuput } from './utils';
3
4
  export type EndpointResponseSchema = {
@@ -6,6 +7,15 @@ export type EndpointResponseSchema = {
6
7
  schema: z.ZodSchema<any> | z.ZodVoid;
7
8
  headers?: Record<string, string>;
8
9
  };
10
+ export type FileUpload = {
11
+ buffer: Buffer;
12
+ originalname: string;
13
+ encoding: string;
14
+ mimetype: string;
15
+ size: number;
16
+ fieldname: string;
17
+ filename: string;
18
+ };
9
19
  export type MiddlewareHandler<TResponseSchema, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = (request: {
10
20
  body: ZodSchemaOuput<TRequestBodySchema>;
11
21
  params: ZodSchemaOuput<TRequestParamsSchema>;
@@ -16,6 +26,7 @@ export type MiddlewareHandler<TResponseSchema, TRequestBodySchema, TRequestParam
16
26
  originalUrl: string;
17
27
  path: string;
18
28
  method: string;
29
+ file?: FileUpload;
19
30
  }, send: (response: ExtractZodOutput<ArrayToUnion<TResponseSchema>>) => void, next: (context?: ZodSchemaOuput<TContextSchema>) => void) => Promise<void>;
20
31
  export type MiddlewareOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = {
21
32
  schemas?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "1.56.1",
3
+ "version": "1.56.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -27,6 +27,7 @@
27
27
  "@types/response-time": "^2.3.5",
28
28
  "@types/swagger-ui-express": "4.1.3",
29
29
  "axios": "^1.6.0",
30
+ "busboy": "^1.6.0",
30
31
  "cls-rtracer": "^2.6.2",
31
32
  "express": "4.19.2",
32
33
  "express-async-errors": "3.1.1",
@@ -47,6 +48,7 @@
47
48
  "zod": "3.22.3"
48
49
  },
49
50
  "devDependencies": {
51
+ "@types/busboy": "^1.5.3",
50
52
  "@types/express": "4.17.15",
51
53
  "@types/lodash": "^4.14.187",
52
54
  "@types/negotiator": "^0.6.1",