@abejarano/ts-express-server 1.6.0 → 1.7.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.
@@ -24,6 +24,15 @@ export interface ServerResponse {
24
24
  send(body: unknown): void | Promise<void>;
25
25
  set(name: string, value: string): this;
26
26
  header(name: string, value: string): this;
27
+ cookie?(name: string, value: string, options?: {
28
+ maxAge?: number;
29
+ domain?: string;
30
+ path?: string;
31
+ expires?: Date;
32
+ httpOnly?: boolean;
33
+ secure?: boolean;
34
+ sameSite?: "lax" | "strict" | "none";
35
+ }): this;
27
36
  end(body?: unknown): void | Promise<void>;
28
37
  }
29
38
  export type ServerHandlerInput = ServerHandler | ServerHandler[] | ServerRouter;
@@ -1,4 +1,4 @@
1
- import { ServerAdapter, ServerApp, ServerInstance, ServerRouter, ServerRuntime } from "../abstract/ServerTypes";
1
+ import { ServerAdapter, ServerApp, ServerInstance, ServerRequest, ServerRouter, ServerRuntime } from "../abstract/ServerTypes";
2
2
  export declare class BunAdapter implements ServerAdapter {
3
3
  runtime: ServerRuntime;
4
4
  createApp(): ServerApp;
@@ -6,3 +6,13 @@ export declare class BunAdapter implements ServerAdapter {
6
6
  configure(app: ServerApp, _port: number): void;
7
7
  listen(app: ServerApp, port: number, onListen: () => void): ServerInstance;
8
8
  }
9
+ type MultipartFile = {
10
+ name: string;
11
+ size: number;
12
+ type: string;
13
+ arrayBuffer(): Promise<ArrayBuffer>;
14
+ lastModified?: number;
15
+ };
16
+ export declare function getFiles(req: ServerRequest, field: string): MultipartFile[];
17
+ export declare function getFile(req: ServerRequest, field: string): MultipartFile | undefined;
18
+ export {};
@@ -1,28 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BunAdapter = void 0;
4
+ exports.getFiles = getFiles;
5
+ exports.getFile = getFile;
4
6
  const ServerTypes_1 = require("../abstract/ServerTypes");
5
7
  class BunResponse {
6
- constructor() {
8
+ constructor(cookieJar, handlerTimeoutMs) {
7
9
  this.statusCode = 200;
10
+ this.statusExplicitlySet = false;
8
11
  this.headers = new Headers();
12
+ this.setCookies = [];
9
13
  this.body = null;
10
14
  this.ended = false;
15
+ this.cookieJar = cookieJar;
16
+ this.handlerTimeoutMs = handlerTimeoutMs;
11
17
  this.endPromise = new Promise((resolve) => {
12
18
  this.resolveEnd = resolve;
13
19
  });
14
20
  }
15
21
  status(code) {
22
+ this.statusExplicitlySet = true;
16
23
  this.statusCode = code;
17
24
  return this;
18
25
  }
19
26
  set(name, value) {
27
+ if (name.toLowerCase() === "set-cookie") {
28
+ this.setCookies.push(value);
29
+ return this;
30
+ }
20
31
  this.headers.set(name, value);
21
32
  return this;
22
33
  }
23
34
  header(name, value) {
24
35
  return this.set(name, value);
25
36
  }
37
+ cookie(name, value, options = {}) {
38
+ if (this.cookieJar && typeof this.cookieJar.set === "function") {
39
+ this.cookieJar.set(name, value, toCookieJarOptions(options));
40
+ return this;
41
+ }
42
+ this.setCookies.push(serializeCookie(name, value, options));
43
+ return this;
44
+ }
26
45
  json(body) {
27
46
  if (!this.headers.has("content-type")) {
28
47
  this.headers.set("content-type", "application/json");
@@ -71,13 +90,47 @@ class BunResponse {
71
90
  waitForEnd() {
72
91
  return this.endPromise;
73
92
  }
93
+ getHandlerTimeoutMs() {
94
+ return this.handlerTimeoutMs;
95
+ }
74
96
  toResponse() {
75
97
  if (this.rawResponse) {
76
- return this.rawResponse;
98
+ const headerMap = new Map();
99
+ const setCookies = readSetCookieHeaders(this.rawResponse.headers);
100
+ this.rawResponse.headers.forEach((value, key) => {
101
+ if (key.toLowerCase() === "set-cookie") {
102
+ return;
103
+ }
104
+ headerMap.set(key.toLowerCase(), value);
105
+ });
106
+ this.headers.forEach((value, key) => {
107
+ headerMap.set(key.toLowerCase(), value);
108
+ });
109
+ setCookies.push(...this.setCookies);
110
+ const headersInit = [];
111
+ headerMap.forEach((value, key) => {
112
+ headersInit.push([key, value]);
113
+ });
114
+ for (const cookie of setCookies) {
115
+ headersInit.push(["set-cookie", cookie]);
116
+ }
117
+ return new Response(this.rawResponse.body, {
118
+ status: this.statusExplicitlySet
119
+ ? this.statusCode
120
+ : this.rawResponse.status,
121
+ headers: headersInit,
122
+ });
123
+ }
124
+ const headersInit = [];
125
+ this.headers.forEach((value, key) => {
126
+ headersInit.push([key, value]);
127
+ });
128
+ for (const cookie of this.setCookies) {
129
+ headersInit.push(["set-cookie", cookie]);
77
130
  }
78
131
  return new Response(this.body, {
79
132
  status: this.statusCode,
80
- headers: this.headers,
133
+ headers: headersInit,
81
134
  });
82
135
  }
83
136
  }
@@ -128,14 +181,41 @@ class BunRouter {
128
181
  ...(routeMatch ? routeMatch.route.handlers : []),
129
182
  ];
130
183
  let chainCompleted = false;
184
+ let timeoutId;
185
+ let timedOut = false;
186
+ const timeoutMs = res.getHandlerTimeoutMs();
187
+ const timeoutPromise = typeof timeoutMs === "number" && timeoutMs > 0
188
+ ? new Promise((resolve) => {
189
+ timeoutId = setTimeout(() => {
190
+ timedOut = true;
191
+ if (!res.isEnded()) {
192
+ res.status(504).json({ message: "Handler timeout" });
193
+ }
194
+ resolve(false);
195
+ }, timeoutMs);
196
+ })
197
+ : null;
131
198
  try {
132
- chainCompleted = await runHandlers(handlers, req, res);
199
+ chainCompleted = timeoutPromise
200
+ ? await Promise.race([runHandlers(handlers, req, res), timeoutPromise])
201
+ : await runHandlers(handlers, req, res);
133
202
  }
134
203
  catch (error) {
135
- res.status(500).json({ message: "Internal server error" });
204
+ if (!res.isEnded()) {
205
+ res.status(500).json({ message: "Internal server error" });
206
+ }
136
207
  done(error);
137
208
  return;
138
209
  }
210
+ finally {
211
+ if (timeoutId) {
212
+ clearTimeout(timeoutId);
213
+ }
214
+ }
215
+ if (timedOut) {
216
+ done();
217
+ return;
218
+ }
139
219
  if (!routeMatch) {
140
220
  if (chainCompleted && !res.isEnded() && !suppressNotFound) {
141
221
  res.status(404).json({ message: "Not found" });
@@ -195,11 +275,25 @@ class BunRouter {
195
275
  }
196
276
  }
197
277
  class BunApp extends BunRouter {
278
+ constructor() {
279
+ super(...arguments);
280
+ this.settings = new Map();
281
+ }
282
+ set(key, value) {
283
+ this.settings.set(key, value);
284
+ }
285
+ get(key) {
286
+ return this.settings.get(key);
287
+ }
198
288
  createFetchHandler() {
199
289
  return async (request, server) => {
200
290
  const client = server?.requestIP?.(request);
201
- const req = createRequest(request, client?.address);
202
- const res = new BunResponse();
291
+ const cookieJar = request.cookies;
292
+ const handlerTimeoutMs = this.get("handlerTimeoutMs");
293
+ const trustProxy = this.get("trustProxy") === true;
294
+ const ipOverride = trustProxy ? undefined : client?.address;
295
+ const req = createRequest(request, ipOverride);
296
+ const res = new BunResponse(cookieJar, typeof handlerTimeoutMs === "number" ? handlerTimeoutMs : undefined);
203
297
  await this.handle(req, res, () => undefined);
204
298
  if (!res.isEnded()) {
205
299
  res.status(204).end();
@@ -220,8 +314,9 @@ class BunAdapter {
220
314
  }
221
315
  configure(app, _port) {
222
316
  const bunApp = app;
223
- bunApp.use(parseJsonBody);
224
- bunApp.use(parseUrlEncodedBody);
317
+ bunApp.use(createMultipartBodyParser(bunApp));
318
+ bunApp.use(createJsonBodyParser(bunApp));
319
+ bunApp.use(createUrlEncodedBodyParser(bunApp));
225
320
  }
226
321
  listen(app, port, onListen) {
227
322
  const bunApp = app;
@@ -239,33 +334,121 @@ class BunAdapter {
239
334
  }
240
335
  }
241
336
  exports.BunAdapter = BunAdapter;
242
- const parseJsonBody = async (req, _res, next) => {
243
- if (!req.raw || req.body !== undefined) {
244
- return next();
245
- }
246
- const contentType = String(req.headers["content-type"] || "");
247
- if (!contentType.includes("application/json")) {
248
- return next();
249
- }
250
- try {
251
- req.body = await req.raw.json();
252
- }
253
- catch {
254
- req.body = undefined;
255
- }
256
- next();
337
+ const createJsonBodyParser = (app) => {
338
+ return async (req, res, next) => {
339
+ if (!req.raw || req.body !== undefined) {
340
+ return next();
341
+ }
342
+ const contentType = String(req.headers["content-type"] || "");
343
+ if (!contentType.includes("application/json")) {
344
+ return next();
345
+ }
346
+ const limit = getBodyLimit(app);
347
+ const contentLength = parseContentLength(req.headers["content-length"]);
348
+ if (contentLength !== undefined && contentLength > limit) {
349
+ res.status(413).json({ message: "Payload too large" });
350
+ return;
351
+ }
352
+ try {
353
+ req.body = await req.raw.json();
354
+ }
355
+ catch {
356
+ res.status(400).json({ message: "Invalid JSON" });
357
+ return;
358
+ }
359
+ next();
360
+ };
257
361
  };
258
- const parseUrlEncodedBody = async (req, _res, next) => {
259
- if (!req.raw || req.body !== undefined) {
260
- return next();
261
- }
262
- const contentType = String(req.headers["content-type"] || "");
263
- if (!contentType.includes("application/x-www-form-urlencoded")) {
264
- return next();
265
- }
266
- const text = await req.raw.text();
267
- req.body = Object.fromEntries(new URLSearchParams(text));
268
- next();
362
+ const createUrlEncodedBodyParser = (app) => {
363
+ return async (req, res, next) => {
364
+ if (!req.raw || req.body !== undefined) {
365
+ return next();
366
+ }
367
+ const contentType = String(req.headers["content-type"] || "");
368
+ if (!contentType.includes("application/x-www-form-urlencoded")) {
369
+ return next();
370
+ }
371
+ const limit = getBodyLimit(app);
372
+ const contentLength = parseContentLength(req.headers["content-length"]);
373
+ if (contentLength !== undefined && contentLength > limit) {
374
+ res.status(413).json({ message: "Payload too large" });
375
+ return;
376
+ }
377
+ const text = await req.raw.text();
378
+ req.body = Object.fromEntries(new URLSearchParams(text));
379
+ next();
380
+ };
381
+ };
382
+ const createMultipartBodyParser = (app) => {
383
+ return async (req, res, next) => {
384
+ if (!req.raw || req.body !== undefined) {
385
+ return next();
386
+ }
387
+ const contentType = String(req.headers["content-type"] || "");
388
+ if (!contentType.includes("multipart/form-data")) {
389
+ return next();
390
+ }
391
+ const options = normalizeMultipartOptions(app.get("multipart"));
392
+ const lengthHeader = req.headers["content-length"];
393
+ const contentLength = parseContentLength(lengthHeader);
394
+ if (contentLength !== undefined && contentLength > options.maxBodyBytes) {
395
+ res.status(413).json({ message: "Payload too large" });
396
+ return;
397
+ }
398
+ try {
399
+ const formData = await req.raw.formData();
400
+ const fields = {};
401
+ const files = {};
402
+ let fileCount = 0;
403
+ for (const [key, value] of formData.entries()) {
404
+ if (isFile(value)) {
405
+ if (value.size > options.maxFileBytes) {
406
+ res.status(413).json({ message: "Payload too large" });
407
+ return;
408
+ }
409
+ if (!isMimeAllowed(value.type, options.allowedMimeTypes)) {
410
+ res.status(415).json({ message: "Unsupported media type" });
411
+ return;
412
+ }
413
+ fileCount += 1;
414
+ if (fileCount > options.maxFiles) {
415
+ res.status(413).json({ message: "Payload too large" });
416
+ return;
417
+ }
418
+ const bucket = files[key];
419
+ if (bucket) {
420
+ bucket.push(value);
421
+ }
422
+ else {
423
+ files[key] = [value];
424
+ }
425
+ continue;
426
+ }
427
+ const existing = fields[key];
428
+ const textValue = String(value);
429
+ if (existing === undefined) {
430
+ fields[key] = textValue;
431
+ }
432
+ else if (Array.isArray(existing)) {
433
+ existing.push(textValue);
434
+ }
435
+ else {
436
+ fields[key] = [existing, textValue];
437
+ }
438
+ }
439
+ if (Object.keys(fields).length > 0) {
440
+ req.body = fields;
441
+ }
442
+ if (Object.keys(files).length > 0) {
443
+ req.files = files;
444
+ }
445
+ }
446
+ catch {
447
+ res.status(400).json({ message: "Invalid multipart form data" });
448
+ return;
449
+ }
450
+ next();
451
+ };
269
452
  };
270
453
  function createRequest(request, ipOverride) {
271
454
  const url = new URL(request.url);
@@ -306,6 +489,109 @@ function toQueryRecord(search) {
306
489
  }
307
490
  return record;
308
491
  }
492
+ const DEFAULT_MULTIPART_OPTIONS = {
493
+ maxBodyBytes: 10 * 1024 * 1024,
494
+ maxFileBytes: 10 * 1024 * 1024,
495
+ maxFiles: 10,
496
+ };
497
+ function serializeCookie(name, value, options) {
498
+ const parts = [`${name}=${encodeURIComponent(value)}`];
499
+ if (options.maxAge !== undefined) {
500
+ const maxAgeSeconds = Math.floor(options.maxAge / 1000);
501
+ parts.push(`Max-Age=${maxAgeSeconds}`);
502
+ if (!options.expires) {
503
+ parts.push(`Expires=${new Date(Date.now() + options.maxAge).toUTCString()}`);
504
+ }
505
+ }
506
+ if (options.domain) {
507
+ parts.push(`Domain=${options.domain}`);
508
+ }
509
+ if (options.path) {
510
+ parts.push(`Path=${options.path}`);
511
+ }
512
+ if (options.expires) {
513
+ parts.push(`Expires=${options.expires.toUTCString()}`);
514
+ }
515
+ if (options.httpOnly) {
516
+ parts.push("HttpOnly");
517
+ }
518
+ if (options.secure || options.sameSite === "none") {
519
+ parts.push("Secure");
520
+ }
521
+ if (options.sameSite) {
522
+ const normalized = options.sameSite === "none"
523
+ ? "None"
524
+ : options.sameSite === "strict"
525
+ ? "Strict"
526
+ : "Lax";
527
+ parts.push(`SameSite=${normalized}`);
528
+ }
529
+ return parts.join("; ");
530
+ }
531
+ function toCookieJarOptions(options) {
532
+ const sameSite = options.sameSite === "none"
533
+ ? "None"
534
+ : options.sameSite === "strict"
535
+ ? "Strict"
536
+ : options.sameSite === "lax"
537
+ ? "Lax"
538
+ : undefined;
539
+ const maxAge = options.maxAge === undefined
540
+ ? undefined
541
+ : Math.floor(options.maxAge / 1000);
542
+ return {
543
+ maxAge,
544
+ domain: options.domain,
545
+ path: options.path,
546
+ expires: options.expires,
547
+ httpOnly: options.httpOnly,
548
+ secure: options.secure || options.sameSite === "none",
549
+ sameSite,
550
+ };
551
+ }
552
+ function getBodyLimit(app) {
553
+ return normalizeMultipartOptions(app.get("multipart")).maxBodyBytes;
554
+ }
555
+ function normalizeMultipartOptions(input) {
556
+ if (!input || typeof input !== "object") {
557
+ return { ...DEFAULT_MULTIPART_OPTIONS };
558
+ }
559
+ const value = input;
560
+ return {
561
+ maxBodyBytes: value.maxBodyBytes ?? DEFAULT_MULTIPART_OPTIONS.maxBodyBytes,
562
+ maxFileBytes: value.maxFileBytes ?? DEFAULT_MULTIPART_OPTIONS.maxFileBytes,
563
+ maxFiles: value.maxFiles ?? DEFAULT_MULTIPART_OPTIONS.maxFiles,
564
+ allowedMimeTypes: value.allowedMimeTypes,
565
+ };
566
+ }
567
+ function isMimeAllowed(type, allowed) {
568
+ if (!allowed || allowed.length === 0) {
569
+ return true;
570
+ }
571
+ const normalized = type.toLowerCase();
572
+ for (const entry of allowed) {
573
+ const rule = entry.toLowerCase();
574
+ if (rule.endsWith("/*")) {
575
+ const prefix = rule.slice(0, -1);
576
+ if (normalized.startsWith(prefix)) {
577
+ return true;
578
+ }
579
+ continue;
580
+ }
581
+ if (normalized === rule) {
582
+ return true;
583
+ }
584
+ }
585
+ return false;
586
+ }
587
+ function isFile(value) {
588
+ if (!value || typeof value !== "object") {
589
+ return false;
590
+ }
591
+ return (typeof value.arrayBuffer === "function" &&
592
+ typeof value.name === "string" &&
593
+ typeof value.size === "number");
594
+ }
309
595
  function parseCookies(cookieHeader) {
310
596
  if (!cookieHeader) {
311
597
  return undefined;
@@ -316,10 +602,47 @@ function parseCookies(cookieHeader) {
316
602
  if (!name) {
317
603
  return;
318
604
  }
319
- cookies[name] = decodeURIComponent(rest.join("="));
605
+ try {
606
+ cookies[name] = decodeURIComponent(rest.join("="));
607
+ }
608
+ catch {
609
+ cookies[name] = rest.join("=");
610
+ }
320
611
  });
321
612
  return cookies;
322
613
  }
614
+ function parseContentLength(header) {
615
+ if (header === undefined) {
616
+ return undefined;
617
+ }
618
+ const value = Array.isArray(header) ? header[0] : header;
619
+ if (!value) {
620
+ return undefined;
621
+ }
622
+ const parsed = Number.parseInt(value, 10);
623
+ return Number.isNaN(parsed) ? undefined : parsed;
624
+ }
625
+ function readSetCookieHeaders(headers) {
626
+ const bunHeaders = headers;
627
+ const setCookieFromApi = bunHeaders.getSetCookie?.() ?? bunHeaders.getAll?.("Set-Cookie");
628
+ if (setCookieFromApi && setCookieFromApi.length > 0) {
629
+ return setCookieFromApi;
630
+ }
631
+ const setCookies = [];
632
+ headers.forEach((value, key) => {
633
+ if (key.toLowerCase() === "set-cookie") {
634
+ setCookies.push(value);
635
+ }
636
+ });
637
+ return setCookies;
638
+ }
639
+ function getFiles(req, field) {
640
+ const map = (req.files ?? {});
641
+ return map[field] ?? [];
642
+ }
643
+ function getFile(req, field) {
644
+ return getFiles(req, field)[0];
645
+ }
323
646
  function extractIp(headers) {
324
647
  const forwarded = headers["x-forwarded-for"];
325
648
  if (forwarded) {
@@ -1,2 +1,2 @@
1
1
  import "reflect-metadata";
2
- export declare function Controller(basePath: string): (target: Function) => void;
2
+ export declare function Controller(basePath: string): (...args: any[]) => void;
@@ -2,9 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Controller = Controller;
4
4
  const MetadataKeys_1 = require("./MetadataKeys");
5
+ const DecoratorGuards_1 = require("./DecoratorGuards");
5
6
  require("reflect-metadata");
6
7
  function Controller(basePath) {
7
- return function (target) {
8
+ return function (...args) {
9
+ (0, DecoratorGuards_1.assertLegacyDecorator)(args, "@Controller");
10
+ const target = args[0];
8
11
  Reflect.defineMetadata(MetadataKeys_1.MetadataKeys.BASE_PATH, basePath, target);
9
12
  };
10
13
  }
@@ -0,0 +1 @@
1
+ export declare function assertLegacyDecorator(args: any[], decoratorName: string): void;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertLegacyDecorator = assertLegacyDecorator;
4
+ function assertLegacyDecorator(args, decoratorName) {
5
+ const context = args[1];
6
+ if (args.length === 2 &&
7
+ context &&
8
+ typeof context === "object" &&
9
+ "kind" in context) {
10
+ throw new Error(`[ts-express-server] ${decoratorName} is not compatible with ` +
11
+ `standard TypeScript decorators. Enable "experimentalDecorators": true ` +
12
+ `in your tsconfig and ensure your files are included by that config.`);
13
+ }
14
+ }
@@ -11,8 +11,8 @@ export interface IRouter {
11
11
  path: string;
12
12
  handlerName: string | symbol;
13
13
  }
14
- export declare const Get: (path: string) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
15
- export declare const Post: (path: string) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
16
- export declare const Put: (path: string) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
17
- export declare const Delete: (path: string) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
18
- export declare const Patch: (path: string) => (target: any, key: string, descriptor: PropertyDescriptor) => void;
14
+ export declare const Get: (path: string) => (...args: any[]) => void;
15
+ export declare const Post: (path: string) => (...args: any[]) => void;
16
+ export declare const Put: (path: string) => (...args: any[]) => void;
17
+ export declare const Delete: (path: string) => (...args: any[]) => void;
18
+ export declare const Patch: (path: string) => (...args: any[]) => void;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Patch = exports.Delete = exports.Put = exports.Post = exports.Get = exports.Methods = void 0;
4
4
  const MetadataKeys_1 = require("./MetadataKeys");
5
+ const DecoratorGuards_1 = require("./DecoratorGuards");
5
6
  require("reflect-metadata");
6
7
  var Methods;
7
8
  (function (Methods) {
@@ -13,7 +14,10 @@ var Methods;
13
14
  })(Methods || (exports.Methods = Methods = {}));
14
15
  function methodDecorator(method) {
15
16
  return function (path) {
16
- return function (target, key, descriptor) {
17
+ return function (...args) {
18
+ (0, DecoratorGuards_1.assertLegacyDecorator)(args, `@${method.toUpperCase()}`);
19
+ const target = args[0];
20
+ const key = args[1];
17
21
  const routers = Reflect.getMetadata(MetadataKeys_1.MetadataKeys.ROUTERS, target) || [];
18
22
  routers.push({
19
23
  method,
@@ -1,3 +1,3 @@
1
1
  import { ServerHandler } from "../abstract";
2
2
  import "reflect-metadata";
3
- export declare function Use(middleware: ServerHandler | ServerHandler[]): (target: any, key?: string, descriptor?: PropertyDescriptor) => void;
3
+ export declare function Use(middleware: ServerHandler | ServerHandler[]): (...args: any[]) => void;
@@ -2,9 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Use = Use;
4
4
  const MetadataKeys_1 = require("./MetadataKeys");
5
+ const DecoratorGuards_1 = require("./DecoratorGuards");
5
6
  require("reflect-metadata");
6
7
  function Use(middleware) {
7
- return function (target, key, descriptor) {
8
+ return function (...args) {
9
+ (0, DecoratorGuards_1.assertLegacyDecorator)(args, "@Use");
10
+ const target = args[0];
11
+ const key = args[1];
8
12
  const newMiddlewares = Array.isArray(middleware)
9
13
  ? middleware
10
14
  : [middleware];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@abejarano/ts-express-server",
3
3
  "author": "angel bejarano / angel.bejarano@jaspesoft.com",
4
- "version": "1.6.0",
4
+ "version": "1.7.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [