@abejarano/ts-express-server 1.7.5 → 1.7.7
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/README.md +22 -21
- package/dist/BootstrapServer.d.ts +1 -3
- package/dist/BootstrapServer.js +1 -8
- package/dist/BootstrapStandardServer.d.ts +6 -9
- package/dist/BootstrapStandardServer.js +4 -28
- package/dist/abstract/ServerTypes.d.ts +2 -3
- package/dist/abstract/ServerTypes.js +0 -1
- package/dist/adapters/BunAdapter.js +116 -9
- package/dist/adapters/index.d.ts +0 -1
- package/dist/adapters/index.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/modules/ControllersModule.js +2 -2
- package/dist/modules/CorsModule.d.ts +2 -2
- package/dist/modules/CorsModule.js +0 -10
- package/dist/modules/FileUploadModule.d.ts +12 -2
- package/dist/modules/FileUploadModule.js +3 -12
- package/dist/modules/RateLimitModule.d.ts +8 -1
- package/dist/modules/RateLimitModule.js +0 -9
- package/dist/modules/SecurityModule.js +0 -8
- package/dist/modules/index.d.ts +0 -1
- package/dist/modules/index.js +0 -1
- package/dist/testing/createDecoratedTestApp.d.ts +1 -2
- package/dist/testing/createDecoratedTestApp.js +1 -2
- package/package.json +15 -33
- package/dist/adapters/ExpressAdapter.d.ts +0 -8
- package/dist/adapters/ExpressAdapter.js +0 -65
- package/dist/createRouter.d.ts +0 -2
- package/dist/createRouter.js +0 -12
- package/dist/modules/RoutesModule.d.ts +0 -17
- package/dist/modules/RoutesModule.js +0 -43
package/README.md
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
# TypeScript Server Framework (
|
|
1
|
+
# TypeScript Server Framework (Bun)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Un framework TypeScript moderno y modular para construir APIs en Bun con una arquitectura limpia, extensible y enfocada en productividad. Separa responsabilidades en modulos, servicios y controladores con decoradores, incluye middlewares esenciales listos para usar y mantiene una experiencia tipada end-to-end.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- 🏗️ **
|
|
8
|
-
- 🚀 **
|
|
9
|
-
- 📦 **
|
|
10
|
-
- 🔄 **
|
|
11
|
-
- ⚡ **
|
|
12
|
-
- 🛡️ **Type
|
|
13
|
-
- 🔧 **Configurable**:
|
|
14
|
-
- 🎨 **
|
|
15
|
-
- ⚙️ **Runtime Choice**: Run on Express (Node) or Bun via `ServerRuntime`
|
|
7
|
+
- 🏗️ **Arquitectura modular**: arma el servidor con modulos reutilizables y reemplazables
|
|
8
|
+
- 🚀 **Servicios de fondo**: inicia procesos y workers junto al servidor
|
|
9
|
+
- 📦 **Modulos incluidos**: CORS, seguridad, rate limit, uploads y contexto de request
|
|
10
|
+
- 🔄 **Apagado limpio**: shutdown ordenado y seguro para modulos/servicios
|
|
11
|
+
- ⚡ **Prioridades**: control total del orden de inicializacion
|
|
12
|
+
- 🛡️ **Type safety real**: tipado fuerte en request, response y decoradores
|
|
13
|
+
- 🔧 **Configurable**: cambia o desactiva piezas sin romper el core
|
|
14
|
+
- 🎨 **Decoradores**: controladores claros, declarativos y faciles de testear
|
|
16
15
|
|
|
17
16
|
## Installation
|
|
18
17
|
|
|
19
18
|
```bash
|
|
20
|
-
|
|
21
|
-
# or
|
|
22
|
-
yarn add @abejarano/ts-express-server
|
|
19
|
+
bun add @abejarano/ts-express-server
|
|
23
20
|
```
|
|
24
21
|
|
|
25
22
|
## Documentation
|
|
@@ -33,17 +30,21 @@ yarn add @abejarano/ts-express-server
|
|
|
33
30
|
- [API Reference](docs/api-reference.md)
|
|
34
31
|
- [Examples](docs/examples.md)
|
|
35
32
|
|
|
36
|
-
##
|
|
33
|
+
## File uploads
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
import { BootstrapServer } from "@abejarano/ts-express-server";
|
|
35
|
+
Uploads are disabled unless `FileUploadModule` is registered. Configure limits and MIME allowlists through the module:
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
server
|
|
37
|
+
```typescript
|
|
38
|
+
import { FileUploadModule } from "@abejarano/ts-express-server";
|
|
39
|
+
|
|
40
|
+
const fileUpload = new FileUploadModule({
|
|
41
|
+
maxBodyBytes: 10 * 1024 * 1024,
|
|
42
|
+
maxFileBytes: 10 * 1024 * 1024,
|
|
43
|
+
maxFiles: 10,
|
|
44
|
+
allowedMimeTypes: ["image/*", "application/pdf"],
|
|
45
|
+
});
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
You can also use `ServerRuntime.Bun` and `ServerRuntime.Express` if you prefer the enum.
|
|
46
|
-
|
|
47
48
|
## Contributing
|
|
48
49
|
|
|
49
50
|
1. Fork the repository
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { BaseServerModule, BaseServerService } from "./abstract";
|
|
2
|
-
import { ServerAdapter, ServerApp, ServerInstance
|
|
2
|
+
import { ServerAdapter, ServerApp, ServerInstance } from "./abstract";
|
|
3
3
|
export interface BootstrapServerOptions {
|
|
4
|
-
runtime?: ServerRuntime;
|
|
5
4
|
adapter?: ServerAdapter;
|
|
6
5
|
}
|
|
7
6
|
export declare class BootstrapServer {
|
|
@@ -29,5 +28,4 @@ export declare class BootstrapServer {
|
|
|
29
28
|
private initializeServices;
|
|
30
29
|
private initializeServerModules;
|
|
31
30
|
private setupGracefulShutdown;
|
|
32
|
-
private createAdapter;
|
|
33
31
|
}
|
package/dist/BootstrapServer.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BootstrapServer = void 0;
|
|
4
|
-
const abstract_1 = require("./abstract");
|
|
5
4
|
const adapters_1 = require("./adapters");
|
|
6
5
|
class BootstrapServer {
|
|
7
6
|
constructor(port, options) {
|
|
8
7
|
this.modules = [];
|
|
9
8
|
this.services = [];
|
|
10
9
|
this.port = port;
|
|
11
|
-
this.adapter = options?.adapter ??
|
|
10
|
+
this.adapter = options?.adapter ?? new adapters_1.BunAdapter();
|
|
12
11
|
this.runtime = this.adapter.runtime;
|
|
13
12
|
this.app = this.adapter.createApp();
|
|
14
13
|
this.adapter.configure(this.app, port);
|
|
@@ -170,11 +169,5 @@ class BootstrapServer {
|
|
|
170
169
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
171
170
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
172
171
|
}
|
|
173
|
-
createAdapter(runtime) {
|
|
174
|
-
if (runtime === abstract_1.ServerRuntime.Bun) {
|
|
175
|
-
return new adapters_1.BunAdapter();
|
|
176
|
-
}
|
|
177
|
-
return new adapters_1.ExpressAdapter();
|
|
178
|
-
}
|
|
179
172
|
}
|
|
180
173
|
exports.BootstrapServer = BootstrapServer;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BootstrapServer } from "./BootstrapServer";
|
|
2
|
-
import { ControllersModule
|
|
3
|
-
import { BaseServerModule, BaseServerService,
|
|
2
|
+
import { ControllersModule } from "./modules";
|
|
3
|
+
import { BaseServerModule, BaseServerService, ServerAdapter } from "./abstract";
|
|
4
4
|
export interface BootstrapStandardServerOptions {
|
|
5
|
-
|
|
5
|
+
adapter?: ServerAdapter;
|
|
6
6
|
modules?: {
|
|
7
7
|
cors?: BaseServerModule | false;
|
|
8
8
|
security?: BaseServerModule | false;
|
|
@@ -13,9 +13,6 @@ export interface BootstrapStandardServerOptions {
|
|
|
13
13
|
};
|
|
14
14
|
services?: BaseServerService[];
|
|
15
15
|
}
|
|
16
|
-
export declare function BootstrapStandardServer(port: number, module:
|
|
17
|
-
export declare function BootstrapStandardServer(port: number, module:
|
|
18
|
-
export declare function BootstrapStandardServer(port: number, module:
|
|
19
|
-
export declare function BootstrapStandardServer(port: number, routes: RoutesModule, controllersModule: ControllersModule, services?: BaseServerService[]): BootstrapServer;
|
|
20
|
-
export declare function BootstrapStandardServer(port: number, routes: RoutesModule, controllersModule: ControllersModule, services: BaseServerService[], options: BootstrapStandardServerOptions): BootstrapServer;
|
|
21
|
-
export declare function BootstrapStandardServer(port: number, routes: RoutesModule, controllersModule: ControllersModule, options: BootstrapStandardServerOptions): BootstrapServer;
|
|
16
|
+
export declare function BootstrapStandardServer(port: number, module: ControllersModule, services?: BaseServerService[]): BootstrapServer;
|
|
17
|
+
export declare function BootstrapStandardServer(port: number, module: ControllersModule, services: BaseServerService[], options: BootstrapStandardServerOptions): BootstrapServer;
|
|
18
|
+
export declare function BootstrapStandardServer(port: number, module: ControllersModule, options: BootstrapStandardServerOptions): BootstrapServer;
|
|
@@ -3,27 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BootstrapStandardServer = BootstrapStandardServer;
|
|
4
4
|
const BootstrapServer_1 = require("./BootstrapServer");
|
|
5
5
|
const modules_1 = require("./modules");
|
|
6
|
-
function BootstrapStandardServer(port, arg2, arg3, arg4
|
|
7
|
-
let routesModule;
|
|
6
|
+
function BootstrapStandardServer(port, arg2, arg3, arg4) {
|
|
8
7
|
let controllersModule;
|
|
9
8
|
let services;
|
|
10
9
|
let options;
|
|
11
|
-
|
|
12
|
-
if (controllersModule && controllersModule !== module) {
|
|
13
|
-
throw new Error("ControllersModule provided multiple times. Pass a single instance only.");
|
|
14
|
-
}
|
|
15
|
-
controllersModule = module;
|
|
16
|
-
};
|
|
17
|
-
if (arg2 instanceof modules_1.RoutesModule) {
|
|
18
|
-
routesModule = arg2;
|
|
19
|
-
}
|
|
20
|
-
else if (arg2 instanceof modules_1.ControllersModule) {
|
|
21
|
-
setControllersModule(arg2);
|
|
22
|
-
routesModule = new modules_1.RoutesModule();
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
throw new Error("Invalid second argument. Must be RoutesModule or ControllersModule");
|
|
26
|
-
}
|
|
10
|
+
controllersModule = arg2;
|
|
27
11
|
const addServices = (value) => {
|
|
28
12
|
if (!value?.length) {
|
|
29
13
|
return;
|
|
@@ -34,10 +18,6 @@ function BootstrapStandardServer(port, arg2, arg3, arg4, arg5) {
|
|
|
34
18
|
if (!value) {
|
|
35
19
|
return;
|
|
36
20
|
}
|
|
37
|
-
if (value instanceof modules_1.ControllersModule) {
|
|
38
|
-
setControllersModule(value);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
21
|
if (Array.isArray(value)) {
|
|
42
22
|
addServices(value);
|
|
43
23
|
return;
|
|
@@ -46,9 +26,8 @@ function BootstrapStandardServer(port, arg2, arg3, arg4, arg5) {
|
|
|
46
26
|
};
|
|
47
27
|
processOptionalArg(arg3);
|
|
48
28
|
processOptionalArg(arg4);
|
|
49
|
-
processOptionalArg(arg5);
|
|
50
29
|
addServices(options?.services);
|
|
51
|
-
const modulesToRegister = [
|
|
30
|
+
const modulesToRegister = [controllersModule];
|
|
52
31
|
const preset = options?.modules;
|
|
53
32
|
const registerModule = (factory, override) => {
|
|
54
33
|
if (override === false) {
|
|
@@ -65,11 +44,8 @@ function BootstrapStandardServer(port, arg2, arg3, arg4, arg5) {
|
|
|
65
44
|
modulesToRegister.push(...preset.extra);
|
|
66
45
|
}
|
|
67
46
|
const server = new BootstrapServer_1.BootstrapServer(port, {
|
|
68
|
-
|
|
47
|
+
adapter: options?.adapter,
|
|
69
48
|
}).addModules(modulesToRegister);
|
|
70
|
-
if (controllersModule) {
|
|
71
|
-
server.addModule(controllersModule);
|
|
72
|
-
}
|
|
73
49
|
if (services) {
|
|
74
50
|
server.addServices(services);
|
|
75
51
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type fileUpload from "express-fileupload";
|
|
2
1
|
export declare enum ServerRuntime {
|
|
3
|
-
Express = "express",
|
|
4
2
|
Bun = "bun"
|
|
5
3
|
}
|
|
6
4
|
export type NextFunction = (err?: unknown) => void;
|
|
@@ -25,6 +23,7 @@ export interface ServerResponse {
|
|
|
25
23
|
send(body: unknown): void | Promise<void>;
|
|
26
24
|
set(name: string, value: string): this;
|
|
27
25
|
header(name: string, value: string): this;
|
|
26
|
+
setHeader?(name: string, value: string): this;
|
|
28
27
|
cookie?(name: string, value: string, options?: {
|
|
29
28
|
maxAge?: number;
|
|
30
29
|
domain?: string;
|
|
@@ -47,7 +46,7 @@ export type BunMultipartFile = {
|
|
|
47
46
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
48
47
|
lastModified?: number;
|
|
49
48
|
};
|
|
50
|
-
export type ServerFile = BunMultipartFile
|
|
49
|
+
export type ServerFile = BunMultipartFile;
|
|
51
50
|
export type ServerFiles = Record<string, ServerFile | ServerFile[]>;
|
|
52
51
|
export type ServerHandlerInput = ServerHandler | ServerHandler[] | ServerRouter;
|
|
53
52
|
export interface ServerRouter {
|
|
@@ -3,6 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ServerRuntime = void 0;
|
|
4
4
|
var ServerRuntime;
|
|
5
5
|
(function (ServerRuntime) {
|
|
6
|
-
ServerRuntime["Express"] = "express";
|
|
7
6
|
ServerRuntime["Bun"] = "bun";
|
|
8
7
|
})(ServerRuntime || (exports.ServerRuntime = ServerRuntime = {}));
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.BunAdapter = void 0;
|
|
4
7
|
exports.getFiles = getFiles;
|
|
5
8
|
exports.getFile = getFile;
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
6
11
|
const ServerTypes_1 = require("../abstract/ServerTypes");
|
|
7
12
|
class BunResponse {
|
|
8
|
-
constructor(cookieJar, handlerTimeoutMs, cookieDefaults) {
|
|
13
|
+
constructor(cookieJar, handlerTimeoutMs, cookieDefaults, downloadRoot) {
|
|
9
14
|
this.statusCode = 200;
|
|
10
15
|
this.statusExplicitlySet = false;
|
|
11
16
|
this.headers = new Headers();
|
|
@@ -15,6 +20,7 @@ class BunResponse {
|
|
|
15
20
|
this.cookieJar = cookieJar;
|
|
16
21
|
this.handlerTimeoutMs = handlerTimeoutMs;
|
|
17
22
|
this.cookieDefaults = cookieDefaults;
|
|
23
|
+
this.downloadRoot = downloadRoot ?? DEFAULT_DOWNLOAD_ROOT;
|
|
18
24
|
this.endPromise = new Promise((resolve) => {
|
|
19
25
|
this.resolveEnd = resolve;
|
|
20
26
|
});
|
|
@@ -44,6 +50,9 @@ class BunResponse {
|
|
|
44
50
|
header(name, value) {
|
|
45
51
|
return this.set(name, value);
|
|
46
52
|
}
|
|
53
|
+
setHeader(name, value) {
|
|
54
|
+
return this.set(name, value);
|
|
55
|
+
}
|
|
47
56
|
cookie(name, value, options = {}) {
|
|
48
57
|
if (this.ended) {
|
|
49
58
|
return this;
|
|
@@ -110,6 +119,40 @@ class BunResponse {
|
|
|
110
119
|
this.ended = true;
|
|
111
120
|
this.resolveEnd?.();
|
|
112
121
|
}
|
|
122
|
+
download(filePath, filename, callback) {
|
|
123
|
+
if (this.ended) {
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const safePath = resolveSafeDownloadPath(this.downloadRoot, filePath);
|
|
128
|
+
const stat = (0, fs_1.statSync)(safePath);
|
|
129
|
+
if (!stat.isFile()) {
|
|
130
|
+
const error = new Error("File not found");
|
|
131
|
+
callback?.(error);
|
|
132
|
+
if (!this.ended) {
|
|
133
|
+
this.status(404).json({ message: "File not found" });
|
|
134
|
+
}
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
const resolvedName = filename && filename.trim().length > 0
|
|
138
|
+
? filename
|
|
139
|
+
: path_1.default.basename(safePath);
|
|
140
|
+
this.headers.set("content-disposition", `attachment; filename="${sanitizeFilename(resolvedName)}"`);
|
|
141
|
+
const fileBuffer = (0, fs_1.readFileSync)(safePath);
|
|
142
|
+
this.rawResponse = new Response(fileBuffer);
|
|
143
|
+
this.ended = true;
|
|
144
|
+
this.resolveEnd?.();
|
|
145
|
+
callback?.();
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
callback?.(error);
|
|
150
|
+
if (!this.ended) {
|
|
151
|
+
this.status(500).json({ message: "File download failed" });
|
|
152
|
+
}
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
113
156
|
isEnded() {
|
|
114
157
|
return this.ended;
|
|
115
158
|
}
|
|
@@ -324,7 +367,7 @@ class BunApp extends BunRouter {
|
|
|
324
367
|
: typeof handlerTimeoutSetting === "number"
|
|
325
368
|
? handlerTimeoutSetting
|
|
326
369
|
: undefined;
|
|
327
|
-
const trustProxy = resolveTrustProxySetting(this
|
|
370
|
+
const trustProxy = resolveTrustProxySetting(this);
|
|
328
371
|
const maxConcurrentRequests = Number(this.get("maxConcurrentRequests") ?? 0);
|
|
329
372
|
if (maxConcurrentRequests > 0 && this.activeRequests >= maxConcurrentRequests) {
|
|
330
373
|
return new Response(JSON.stringify({ message: "Server busy" }), {
|
|
@@ -334,7 +377,7 @@ class BunApp extends BunRouter {
|
|
|
334
377
|
}
|
|
335
378
|
this.activeRequests += 1;
|
|
336
379
|
const req = createRequest(request, client?.address, trustProxy);
|
|
337
|
-
const res = new BunResponse(cookieJar, handlerTimeoutMs, resolveCookieDefaults(this.get("cookieDefaults")));
|
|
380
|
+
const res = new BunResponse(cookieJar, handlerTimeoutMs, resolveCookieDefaults(this.get("cookieDefaults")), resolveDownloadRoot(this.get("downloadRoot")));
|
|
338
381
|
try {
|
|
339
382
|
await this.handle(req, res, () => undefined);
|
|
340
383
|
}
|
|
@@ -470,6 +513,12 @@ const createMultipartBodyParser = (app) => {
|
|
|
470
513
|
if (!contentType.includes("multipart/form-data")) {
|
|
471
514
|
return next();
|
|
472
515
|
}
|
|
516
|
+
if (app.get("fileUploadEnabled") !== true) {
|
|
517
|
+
res
|
|
518
|
+
.status(415)
|
|
519
|
+
.json({ message: "File uploads are disabled. Enable FileUploadModule." });
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
473
522
|
const options = normalizeMultipartOptions(app.get("multipart"));
|
|
474
523
|
const lengthHeader = req.headers["content-length"];
|
|
475
524
|
const contentLength = parseContentLength(lengthHeader);
|
|
@@ -487,6 +536,8 @@ const createMultipartBodyParser = (app) => {
|
|
|
487
536
|
const fields = {};
|
|
488
537
|
const files = {};
|
|
489
538
|
let fileCount = 0;
|
|
539
|
+
let fieldCount = 0;
|
|
540
|
+
let fieldBytes = 0;
|
|
490
541
|
for (const [key, value] of formData.entries()) {
|
|
491
542
|
if (isFile(value)) {
|
|
492
543
|
if (value.size > options.maxFileBytes) {
|
|
@@ -530,6 +581,17 @@ const createMultipartBodyParser = (app) => {
|
|
|
530
581
|
}
|
|
531
582
|
const existing = fields[key];
|
|
532
583
|
const textValue = String(value);
|
|
584
|
+
fieldCount += 1;
|
|
585
|
+
if (fieldCount > options.maxFields) {
|
|
586
|
+
res.status(413).json({ message: "Payload too large" });
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const textBytes = Buffer.byteLength(textValue, "utf8");
|
|
590
|
+
fieldBytes += textBytes;
|
|
591
|
+
if (textBytes > options.maxFieldBytes || fieldBytes > options.maxFieldsBytes) {
|
|
592
|
+
res.status(413).json({ message: "Payload too large" });
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
533
595
|
if (existing === undefined) {
|
|
534
596
|
fields[key] = textValue;
|
|
535
597
|
}
|
|
@@ -598,6 +660,9 @@ const DEFAULT_MULTIPART_OPTIONS = {
|
|
|
598
660
|
maxBodyBytes: 10 * 1024 * 1024,
|
|
599
661
|
maxFileBytes: 10 * 1024 * 1024,
|
|
600
662
|
maxFiles: 10,
|
|
663
|
+
maxFields: 200,
|
|
664
|
+
maxFieldBytes: 64 * 1024,
|
|
665
|
+
maxFieldsBytes: 512 * 1024,
|
|
601
666
|
};
|
|
602
667
|
function serializeCookie(name, value, options) {
|
|
603
668
|
const parts = [`${name}=${encodeURIComponent(value)}`];
|
|
@@ -670,6 +735,9 @@ function normalizeMultipartOptions(input) {
|
|
|
670
735
|
maxBodyBytes: value.maxBodyBytes ?? DEFAULT_MULTIPART_OPTIONS.maxBodyBytes,
|
|
671
736
|
maxFileBytes: value.maxFileBytes ?? DEFAULT_MULTIPART_OPTIONS.maxFileBytes,
|
|
672
737
|
maxFiles: value.maxFiles ?? DEFAULT_MULTIPART_OPTIONS.maxFiles,
|
|
738
|
+
maxFields: value.maxFields ?? DEFAULT_MULTIPART_OPTIONS.maxFields,
|
|
739
|
+
maxFieldBytes: value.maxFieldBytes ?? DEFAULT_MULTIPART_OPTIONS.maxFieldBytes,
|
|
740
|
+
maxFieldsBytes: value.maxFieldsBytes ?? DEFAULT_MULTIPART_OPTIONS.maxFieldsBytes,
|
|
673
741
|
allowedMimeTypes: value.allowedMimeTypes,
|
|
674
742
|
allowedFileSignatures: value.allowedFileSignatures,
|
|
675
743
|
validateFile: value.validateFile,
|
|
@@ -734,6 +802,7 @@ function parseContentLength(header) {
|
|
|
734
802
|
return Number.isNaN(parsed) ? undefined : parsed;
|
|
735
803
|
}
|
|
736
804
|
const DEFAULT_HANDLER_TIMEOUT_MS = 30000;
|
|
805
|
+
const DEFAULT_DOWNLOAD_ROOT = process.cwd();
|
|
737
806
|
function readSetCookieHeaders(headers) {
|
|
738
807
|
const bunHeaders = headers;
|
|
739
808
|
const setCookieFromApi = bunHeaders.getSetCookie?.() ??
|
|
@@ -909,18 +978,23 @@ function applyCookieDefaults(options, defaults) {
|
|
|
909
978
|
return { ...defaults.options, ...options };
|
|
910
979
|
}
|
|
911
980
|
function resolveCookieDefaults(input) {
|
|
981
|
+
const baseDefaults = getDefaultCookieDefaults();
|
|
912
982
|
if (!input || typeof input !== "object") {
|
|
913
|
-
return
|
|
983
|
+
return baseDefaults;
|
|
914
984
|
}
|
|
915
985
|
const defaults = input;
|
|
916
986
|
if (!defaults.options || typeof defaults.options !== "object") {
|
|
917
|
-
return
|
|
987
|
+
return baseDefaults;
|
|
918
988
|
}
|
|
919
|
-
return
|
|
989
|
+
return {
|
|
990
|
+
applyTo: defaults.applyTo ?? baseDefaults.applyTo,
|
|
991
|
+
options: { ...baseDefaults.options, ...defaults.options },
|
|
992
|
+
};
|
|
920
993
|
}
|
|
921
|
-
function resolveTrustProxySetting(
|
|
922
|
-
|
|
923
|
-
|
|
994
|
+
function resolveTrustProxySetting(app) {
|
|
995
|
+
const input = app.get("trustProxy");
|
|
996
|
+
if (typeof input === "boolean") {
|
|
997
|
+
throw new Error("Invalid trustProxy boolean. Use a CIDR allowlist or a custom trust function instead.");
|
|
924
998
|
}
|
|
925
999
|
if (Array.isArray(input) && input.every((entry) => typeof entry === "string")) {
|
|
926
1000
|
return input;
|
|
@@ -937,6 +1011,19 @@ function shouldEnableSecurityHeaders(setting) {
|
|
|
937
1011
|
if (typeof setting === "boolean") {
|
|
938
1012
|
return setting;
|
|
939
1013
|
}
|
|
1014
|
+
return isProduction();
|
|
1015
|
+
}
|
|
1016
|
+
function getDefaultCookieDefaults() {
|
|
1017
|
+
return {
|
|
1018
|
+
applyTo: "session",
|
|
1019
|
+
options: {
|
|
1020
|
+
httpOnly: true,
|
|
1021
|
+
sameSite: "lax",
|
|
1022
|
+
secure: isProduction(),
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function isProduction() {
|
|
940
1027
|
return process?.env?.NODE_ENV === "production";
|
|
941
1028
|
}
|
|
942
1029
|
function createSecurityHeadersMiddleware(_app) {
|
|
@@ -1019,6 +1106,26 @@ function matchesSignature(buffer, kind) {
|
|
|
1019
1106
|
function isValidCookieName(name) {
|
|
1020
1107
|
return /^[!#$%&'*+\-.^_|~0-9A-Za-z]+$/.test(name);
|
|
1021
1108
|
}
|
|
1109
|
+
function sanitizeFilename(value) {
|
|
1110
|
+
return value.replace(/[/\\"]/g, "_");
|
|
1111
|
+
}
|
|
1112
|
+
function resolveDownloadRoot(input) {
|
|
1113
|
+
if (typeof input === "string" && input.trim().length > 0) {
|
|
1114
|
+
return path_1.default.resolve(input);
|
|
1115
|
+
}
|
|
1116
|
+
return DEFAULT_DOWNLOAD_ROOT;
|
|
1117
|
+
}
|
|
1118
|
+
function resolveSafeDownloadPath(root, inputPath) {
|
|
1119
|
+
const resolvedRoot = path_1.default.resolve(root);
|
|
1120
|
+
const resolved = path_1.default.resolve(resolvedRoot, inputPath);
|
|
1121
|
+
const rootPrefix = resolvedRoot === path_1.default.parse(resolvedRoot).root
|
|
1122
|
+
? resolvedRoot
|
|
1123
|
+
: `${resolvedRoot}${path_1.default.sep}`;
|
|
1124
|
+
if (!resolved.startsWith(rootPrefix)) {
|
|
1125
|
+
throw new Error("Invalid path");
|
|
1126
|
+
}
|
|
1127
|
+
return resolved;
|
|
1128
|
+
}
|
|
1022
1129
|
async function runHandlers(handlers, req, res) {
|
|
1023
1130
|
let index = 0;
|
|
1024
1131
|
const dispatch = async () => {
|
package/dist/adapters/index.d.ts
CHANGED
package/dist/adapters/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export type { BootstrapServerOptions } from "./BootstrapServer";
|
|
|
4
4
|
export { BootstrapStandardServer } from "./BootstrapStandardServer";
|
|
5
5
|
export type { BootstrapStandardServerOptions } from "./BootstrapStandardServer";
|
|
6
6
|
export * from "./adapters";
|
|
7
|
-
export * from "./createRouter";
|
|
8
7
|
export * from "./modules";
|
|
9
8
|
export * from "./abstract";
|
|
10
9
|
export * from "./decorators";
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,6 @@ Object.defineProperty(exports, "BootstrapServer", { enumerable: true, get: funct
|
|
|
21
21
|
var BootstrapStandardServer_1 = require("./BootstrapStandardServer");
|
|
22
22
|
Object.defineProperty(exports, "BootstrapStandardServer", { enumerable: true, get: function () { return BootstrapStandardServer_1.BootstrapStandardServer; } });
|
|
23
23
|
__exportStar(require("./adapters"), exports);
|
|
24
|
-
__exportStar(require("./createRouter"), exports);
|
|
25
24
|
__exportStar(require("./modules"), exports);
|
|
26
25
|
__exportStar(require("./abstract"), exports);
|
|
27
26
|
__exportStar(require("./decorators"), exports);
|
|
@@ -24,7 +24,7 @@ class ControllersModule extends abstract_1.BaseServerModule {
|
|
|
24
24
|
if (!basePath) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const adapter = context?.adapter ?? new adapters_1.
|
|
27
|
+
const adapter = context?.adapter ?? new adapters_1.BunAdapter();
|
|
28
28
|
const router = adapter.createRouter();
|
|
29
29
|
// Create a single controller instance per controller class (singleton pattern)
|
|
30
30
|
const controllerInstance = new ControllerClass();
|
|
@@ -109,7 +109,7 @@ class ControllersModule extends abstract_1.BaseServerModule {
|
|
|
109
109
|
break;
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
|
-
// Fallbacks for common
|
|
112
|
+
// Fallbacks for common handler arguments when not explicitly decorated
|
|
113
113
|
if (args[0] === undefined) {
|
|
114
114
|
args[0] = req;
|
|
115
115
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { BaseServerModule } from "../abstract";
|
|
2
2
|
import { ServerApp, ServerContext } from "../abstract";
|
|
3
|
-
import
|
|
3
|
+
import type { CorsOptions } from "cors";
|
|
4
4
|
export declare class CorsModule extends BaseServerModule {
|
|
5
5
|
name: string;
|
|
6
6
|
priority: number;
|
|
7
7
|
private corsOptions;
|
|
8
|
-
constructor(corsOptions?:
|
|
8
|
+
constructor(corsOptions?: CorsOptions);
|
|
9
9
|
getModuleName(): string;
|
|
10
10
|
init(app: ServerApp, context?: ServerContext): void;
|
|
11
11
|
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.CorsModule = void 0;
|
|
7
4
|
const abstract_1 = require("../abstract");
|
|
8
|
-
const abstract_2 = require("../abstract");
|
|
9
|
-
const cors_1 = __importDefault(require("cors"));
|
|
10
5
|
class CorsModule extends abstract_1.BaseServerModule {
|
|
11
6
|
constructor(corsOptions) {
|
|
12
7
|
super();
|
|
@@ -24,11 +19,6 @@ class CorsModule extends abstract_1.BaseServerModule {
|
|
|
24
19
|
return this.name;
|
|
25
20
|
}
|
|
26
21
|
init(app, context) {
|
|
27
|
-
const runtime = context?.runtime ?? abstract_2.ServerRuntime.Express;
|
|
28
|
-
if (runtime === abstract_2.ServerRuntime.Express) {
|
|
29
|
-
app.use((0, cors_1.default)(this.corsOptions));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
22
|
app.use(createCorsMiddleware(this.corsOptions));
|
|
33
23
|
}
|
|
34
24
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { BaseServerModule } from "../abstract";
|
|
2
|
-
import { ServerApp, ServerContext } from "../abstract";
|
|
3
|
-
|
|
2
|
+
import { BunMultipartFile, ServerApp, ServerContext } from "../abstract";
|
|
3
|
+
export type FileUploadOptions = {
|
|
4
|
+
maxBodyBytes?: number;
|
|
5
|
+
maxFileBytes?: number;
|
|
6
|
+
maxFiles?: number;
|
|
7
|
+
maxFields?: number;
|
|
8
|
+
maxFieldBytes?: number;
|
|
9
|
+
maxFieldsBytes?: number;
|
|
10
|
+
allowedMimeTypes?: string[];
|
|
11
|
+
allowedFileSignatures?: Array<"png" | "jpg" | "jpeg" | "pdf">;
|
|
12
|
+
validateFile?: (file: BunMultipartFile) => boolean | Promise<boolean>;
|
|
13
|
+
};
|
|
4
14
|
export declare class FileUploadModule extends BaseServerModule {
|
|
5
15
|
name: string;
|
|
6
16
|
priority: number;
|
|
@@ -2,28 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FileUploadModule = void 0;
|
|
4
4
|
const abstract_1 = require("../abstract");
|
|
5
|
-
const abstract_2 = require("../abstract");
|
|
6
5
|
class FileUploadModule extends abstract_1.BaseServerModule {
|
|
7
6
|
constructor(fileUploadOptions) {
|
|
8
7
|
super();
|
|
9
8
|
this.name = "FileUpload";
|
|
10
9
|
this.priority = -60;
|
|
11
|
-
this.fileUploadOptions = fileUploadOptions
|
|
12
|
-
limits: { fileSize: 50 * 1024 * 1024 },
|
|
13
|
-
useTempFiles: true,
|
|
14
|
-
tempFileDir: "/tmp/",
|
|
15
|
-
};
|
|
10
|
+
this.fileUploadOptions = fileUploadOptions ?? {};
|
|
16
11
|
}
|
|
17
12
|
getModuleName() {
|
|
18
13
|
return this.name;
|
|
19
14
|
}
|
|
20
15
|
init(app, context) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const fileUpload = require("express-fileupload");
|
|
24
|
-
app.use(fileUpload(this.fileUploadOptions));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
16
|
+
app.set?.("fileUploadEnabled", true);
|
|
17
|
+
app.set?.("multipart", this.fileUploadOptions);
|
|
27
18
|
}
|
|
28
19
|
}
|
|
29
20
|
exports.FileUploadModule = FileUploadModule;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { BaseServerModule } from "../abstract";
|
|
2
2
|
import { ServerApp, ServerContext } from "../abstract";
|
|
3
|
-
|
|
3
|
+
export type RateLimitOptions = {
|
|
4
|
+
windowMs?: number;
|
|
5
|
+
limit?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
standardHeaders?: boolean;
|
|
8
|
+
legacyHeaders?: boolean;
|
|
9
|
+
message?: string | Record<string, unknown>;
|
|
10
|
+
};
|
|
4
11
|
export declare class RateLimitModule extends BaseServerModule {
|
|
5
12
|
name: string;
|
|
6
13
|
priority: number;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RateLimitModule = void 0;
|
|
4
4
|
const abstract_1 = require("../abstract");
|
|
5
|
-
const abstract_2 = require("../abstract");
|
|
6
5
|
class RateLimitModule extends abstract_1.BaseServerModule {
|
|
7
6
|
constructor(limiterOptions) {
|
|
8
7
|
super();
|
|
@@ -19,14 +18,6 @@ class RateLimitModule extends abstract_1.BaseServerModule {
|
|
|
19
18
|
return this.name;
|
|
20
19
|
}
|
|
21
20
|
init(app, context) {
|
|
22
|
-
const runtime = context?.runtime ?? abstract_2.ServerRuntime.Express;
|
|
23
|
-
if (runtime === abstract_2.ServerRuntime.Express) {
|
|
24
|
-
const rateLimitModule = require("express-rate-limit");
|
|
25
|
-
const rateLimit = rateLimitModule.default ?? rateLimitModule;
|
|
26
|
-
const limiter = rateLimit(this.limiterOptions);
|
|
27
|
-
app.use(limiter);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
21
|
app.use(createRateLimitMiddleware(this.limiterOptions));
|
|
31
22
|
}
|
|
32
23
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SecurityModule = void 0;
|
|
4
4
|
const abstract_1 = require("../abstract");
|
|
5
|
-
const abstract_2 = require("../abstract");
|
|
6
5
|
class SecurityModule extends abstract_1.BaseServerModule {
|
|
7
6
|
constructor(helmetOptions) {
|
|
8
7
|
super();
|
|
@@ -27,13 +26,6 @@ class SecurityModule extends abstract_1.BaseServerModule {
|
|
|
27
26
|
return this.name;
|
|
28
27
|
}
|
|
29
28
|
init(app, context) {
|
|
30
|
-
const runtime = context?.runtime ?? abstract_2.ServerRuntime.Express;
|
|
31
|
-
if (runtime === abstract_2.ServerRuntime.Express) {
|
|
32
|
-
const helmetModule = require("helmet");
|
|
33
|
-
const helmet = helmetModule.default ?? helmetModule;
|
|
34
|
-
app.use(helmet(this.helmetOptions));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
29
|
app.use(createSecurityMiddleware(this.helmetOptions));
|
|
38
30
|
}
|
|
39
31
|
}
|
package/dist/modules/index.d.ts
CHANGED
package/dist/modules/index.js
CHANGED
|
@@ -19,5 +19,4 @@ __exportStar(require("./ControllersModule"), exports);
|
|
|
19
19
|
__exportStar(require("./FileUploadModule"), exports);
|
|
20
20
|
__exportStar(require("./RateLimitModule"), exports);
|
|
21
21
|
__exportStar(require("./RequestContextModule"), exports);
|
|
22
|
-
__exportStar(require("./RoutesModule"), exports);
|
|
23
22
|
__exportStar(require("./SecurityModule"), exports);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BootstrapServer } from "../BootstrapServer";
|
|
2
2
|
import { ControllersModule } from "../modules";
|
|
3
|
-
import { BaseServerService, ServerApp
|
|
3
|
+
import { BaseServerService, ServerApp } from "../abstract";
|
|
4
4
|
import { BootstrapStandardServerOptions } from "../BootstrapStandardServer";
|
|
5
5
|
type ControllerClass<T = any> = new (...args: any[]) => T;
|
|
6
6
|
export interface DecoratedTestAppOptions {
|
|
@@ -9,7 +9,6 @@ export interface DecoratedTestAppOptions {
|
|
|
9
9
|
port?: number;
|
|
10
10
|
services?: BaseServerService[];
|
|
11
11
|
standardOptions?: BootstrapStandardServerOptions;
|
|
12
|
-
runtime?: ServerRuntime;
|
|
13
12
|
}
|
|
14
13
|
export interface DecoratedTestAppResult {
|
|
15
14
|
app: ServerApp;
|
|
@@ -12,7 +12,7 @@ const mergeOptions = (base, override) => {
|
|
|
12
12
|
...(override.services ?? []),
|
|
13
13
|
];
|
|
14
14
|
return {
|
|
15
|
-
|
|
15
|
+
adapter: override.adapter ?? base.adapter,
|
|
16
16
|
services: mergedServices.length ? mergedServices : undefined,
|
|
17
17
|
modules: {
|
|
18
18
|
...(base.modules ?? {}),
|
|
@@ -34,7 +34,6 @@ async function createDecoratedTestApp(options) {
|
|
|
34
34
|
const mergedOptions = mergeOptions(baseOptions, standardOptions);
|
|
35
35
|
const server = (0, BootstrapStandardServer_1.BootstrapStandardServer)(port, moduleInstance, {
|
|
36
36
|
...mergedOptions,
|
|
37
|
-
runtime: options.runtime ?? mergedOptions.runtime,
|
|
38
37
|
});
|
|
39
38
|
await server.initialize();
|
|
40
39
|
return {
|
package/package.json
CHANGED
|
@@ -1,41 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abejarano/ts-express-server",
|
|
3
3
|
"author": "angel bejarano / angel.bejarano@jaspesoft.com",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.7",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist"
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc -p tsconfig.json",
|
|
12
|
-
"clean": "
|
|
13
|
-
"prepare": "
|
|
14
|
-
"prebuild": "
|
|
15
|
-
"format": "prettier --write .",
|
|
16
|
-
"format:check": "prettier --check .",
|
|
17
|
-
"typecheck": "tsc --noEmit",
|
|
18
|
-
"prepack": "
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"test": "jest",
|
|
23
|
-
"test:watch": "jest --watch",
|
|
24
|
-
"test:coverage": "jest --coverage"
|
|
11
|
+
"build": "bun run tsc -p tsconfig.json",
|
|
12
|
+
"clean": "rm -rf dist",
|
|
13
|
+
"prepare": "bun run build",
|
|
14
|
+
"prebuild": "bun run clean",
|
|
15
|
+
"format": "bun run prettier --write .",
|
|
16
|
+
"format:check": "bun run prettier --check .",
|
|
17
|
+
"typecheck": "bun run tsc --noEmit",
|
|
18
|
+
"prepack": "bun run build",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"test:watch": "bun test --watch",
|
|
21
|
+
"test:coverage": "bun test --coverage"
|
|
25
22
|
},
|
|
26
23
|
"keywords": [
|
|
27
24
|
"server",
|
|
28
25
|
"modular",
|
|
29
|
-
"
|
|
26
|
+
"bun"
|
|
30
27
|
],
|
|
31
28
|
"license": "MIT",
|
|
32
29
|
"dependencies": {
|
|
33
|
-
"body-parser": "^2.2.1",
|
|
34
|
-
"cookie-parser": "^1.4.7",
|
|
35
30
|
"cors": "^2.8.5",
|
|
36
|
-
"express": "^5.2.1",
|
|
37
|
-
"express-fileupload": "^1.5.2",
|
|
38
|
-
"express-rate-limit": "^8.2.1",
|
|
39
31
|
"helmet": "^8.1.0",
|
|
40
32
|
"reflect-metadata": "^0.2.2",
|
|
41
33
|
"uuid": "^13.0.0"
|
|
@@ -43,24 +35,14 @@
|
|
|
43
35
|
"devDependencies": {
|
|
44
36
|
"@semantic-release/changelog": "^6.0.3",
|
|
45
37
|
"@semantic-release/git": "^10.0.1",
|
|
46
|
-
"@types/body-parser": "^1.19.6",
|
|
47
|
-
"@types/cookie-parser": "^1.4.9",
|
|
48
38
|
"@types/cors": "^2.8.19",
|
|
49
|
-
"
|
|
50
|
-
"@types/express-fileupload": "^1.5.1",
|
|
51
|
-
"@types/jest": "^30.0.0",
|
|
52
|
-
"@types/node": "^25.0.3",
|
|
53
|
-
"@types/supertest": "^6.0.3",
|
|
54
|
-
"jest": "^30.2.0",
|
|
39
|
+
"bun-types": "^1.3.5",
|
|
55
40
|
"prettier": "^3.6.2",
|
|
56
|
-
"rimraf": "^6.0.1",
|
|
57
41
|
"semantic-release": "^25.0.2",
|
|
58
|
-
"supertest": "^7.1.4",
|
|
59
|
-
"ts-jest": "^29.4.5",
|
|
60
42
|
"typescript": "^5.9.3"
|
|
61
43
|
},
|
|
62
44
|
"engines": {
|
|
63
|
-
"
|
|
45
|
+
"bun": ">=1.3.5"
|
|
64
46
|
},
|
|
65
47
|
"repository": {
|
|
66
48
|
"type": "git",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ServerAdapter, ServerApp, ServerInstance, ServerRouter, ServerRuntime } from "../abstract/ServerTypes";
|
|
2
|
-
export declare class ExpressAdapter implements ServerAdapter {
|
|
3
|
-
runtime: ServerRuntime;
|
|
4
|
-
createApp(): ServerApp;
|
|
5
|
-
createRouter(): ServerRouter;
|
|
6
|
-
configure(app: ServerApp, port: number): void;
|
|
7
|
-
listen(app: ServerApp, port: number, onListen: () => void): ServerInstance;
|
|
8
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExpressAdapter = void 0;
|
|
4
|
-
const ServerTypes_1 = require("../abstract/ServerTypes");
|
|
5
|
-
let expressModule = null;
|
|
6
|
-
const getExpressModule = () => {
|
|
7
|
-
if (!expressModule) {
|
|
8
|
-
expressModule = require("express");
|
|
9
|
-
}
|
|
10
|
-
return expressModule;
|
|
11
|
-
};
|
|
12
|
-
class ExpressAdapter {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.runtime = ServerTypes_1.ServerRuntime.Express;
|
|
15
|
-
}
|
|
16
|
-
createApp() {
|
|
17
|
-
const express = getExpressModule();
|
|
18
|
-
return express();
|
|
19
|
-
}
|
|
20
|
-
createRouter() {
|
|
21
|
-
const express = getExpressModule();
|
|
22
|
-
return express.Router();
|
|
23
|
-
}
|
|
24
|
-
configure(app, port) {
|
|
25
|
-
const expressApp = app;
|
|
26
|
-
const express = getExpressModule();
|
|
27
|
-
const bodyParser = require("body-parser");
|
|
28
|
-
const cookieParser = require("cookie-parser");
|
|
29
|
-
const jsonParser = express.json();
|
|
30
|
-
expressApp.use((req, res, next) => {
|
|
31
|
-
if (!shouldParseJson(req)) {
|
|
32
|
-
return next();
|
|
33
|
-
}
|
|
34
|
-
return jsonParser(req, res, next);
|
|
35
|
-
});
|
|
36
|
-
expressApp.use(bodyParser.urlencoded({ extended: true }));
|
|
37
|
-
expressApp.use(cookieParser());
|
|
38
|
-
expressApp.set("port", port);
|
|
39
|
-
expressApp.set("trust proxy", 1);
|
|
40
|
-
}
|
|
41
|
-
listen(app, port, onListen) {
|
|
42
|
-
const expressApp = app;
|
|
43
|
-
return expressApp.listen(port, onListen);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
exports.ExpressAdapter = ExpressAdapter;
|
|
47
|
-
const shouldParseJson = (req) => {
|
|
48
|
-
const method = String(req.method || "").toUpperCase();
|
|
49
|
-
if (method === "GET" || method === "HEAD") {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
const lengthHeader = req.headers?.["content-length"];
|
|
53
|
-
if (lengthHeader === undefined) {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
const value = Array.isArray(lengthHeader) ? lengthHeader[0] : lengthHeader;
|
|
57
|
-
if (!value) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
const parsed = Number.parseInt(value, 10);
|
|
61
|
-
if (Number.isNaN(parsed)) {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
return parsed > 0;
|
|
65
|
-
};
|
package/dist/createRouter.d.ts
DELETED
package/dist/createRouter.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createRouter = void 0;
|
|
4
|
-
const abstract_1 = require("./abstract");
|
|
5
|
-
const adapters_1 = require("./adapters");
|
|
6
|
-
const createRouter = (runtime = abstract_1.ServerRuntime.Express) => {
|
|
7
|
-
if (runtime === abstract_1.ServerRuntime.Bun) {
|
|
8
|
-
return new adapters_1.BunAdapter().createRouter();
|
|
9
|
-
}
|
|
10
|
-
return new adapters_1.ExpressAdapter().createRouter();
|
|
11
|
-
};
|
|
12
|
-
exports.createRouter = createRouter;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { BaseServerModule } from "../abstract";
|
|
2
|
-
import { ServerApp, ServerContext, ServerHandler, ServerRouter } from "../abstract";
|
|
3
|
-
export interface RouteConfig {
|
|
4
|
-
path: string;
|
|
5
|
-
router: ServerRouter;
|
|
6
|
-
middleware?: ServerHandler[] | ServerHandler;
|
|
7
|
-
}
|
|
8
|
-
export declare class RoutesModule extends BaseServerModule {
|
|
9
|
-
name: string;
|
|
10
|
-
priority: number;
|
|
11
|
-
private routes;
|
|
12
|
-
constructor(routes?: RouteConfig[]);
|
|
13
|
-
getModuleName(): string;
|
|
14
|
-
addRoute(route: RouteConfig): void;
|
|
15
|
-
addRoutes(routes: RouteConfig[]): void;
|
|
16
|
-
init(app: ServerApp, context?: ServerContext): void;
|
|
17
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RoutesModule = void 0;
|
|
4
|
-
const abstract_1 = require("../abstract");
|
|
5
|
-
const abstract_2 = require("../abstract");
|
|
6
|
-
class RoutesModule extends abstract_1.BaseServerModule {
|
|
7
|
-
constructor(routes = []) {
|
|
8
|
-
super();
|
|
9
|
-
this.name = "Routes";
|
|
10
|
-
this.priority = 10; // Executed after basic middlewares
|
|
11
|
-
this.routes = routes;
|
|
12
|
-
}
|
|
13
|
-
getModuleName() {
|
|
14
|
-
return this.name;
|
|
15
|
-
}
|
|
16
|
-
addRoute(route) {
|
|
17
|
-
this.routes.push({
|
|
18
|
-
...route,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
addRoutes(routes) {
|
|
22
|
-
this.routes.push(...routes);
|
|
23
|
-
}
|
|
24
|
-
init(app, context) {
|
|
25
|
-
if (context?.runtime === abstract_2.ServerRuntime.Bun) {
|
|
26
|
-
console.warn("[RoutesModule] Express routers are not supported on Bun. Migrate to decorated controllers for Bun runtime.");
|
|
27
|
-
}
|
|
28
|
-
this.routes.forEach(({ path, router, middleware }) => {
|
|
29
|
-
const middlewareList = Array.isArray(middleware)
|
|
30
|
-
? middleware
|
|
31
|
-
: middleware
|
|
32
|
-
? [middleware]
|
|
33
|
-
: [];
|
|
34
|
-
if (middlewareList.length > 0) {
|
|
35
|
-
app.use(path, ...middlewareList, router);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
app.use(path, router);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
exports.RoutesModule = RoutesModule;
|