wnodex 0.1.0 → 0.2.2
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/.turbo/turbo-build.log +7 -0
- package/LICENSE +1 -1
- package/README.md +73 -67
- package/dist/{schemas/wnodex-config.d.ts → config.d.ts} +14 -9
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +22 -0
- package/dist/index.d.ts +68 -38
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +126 -41
- package/dist/setup-config.d.ts +3 -0
- package/dist/setup-config.d.ts.map +1 -0
- package/dist/setup-config.js +9 -0
- package/dist/setup-middlewares.d.ts +4 -0
- package/dist/setup-middlewares.d.ts.map +1 -0
- package/dist/setup-middlewares.js +32 -0
- package/package.json +51 -15
- package/rolldown.config.ts +20 -0
- package/src/config.ts +27 -0
- package/src/index.ts +149 -38
- package/src/setup-config.ts +17 -0
- package/src/setup-middlewares.ts +49 -0
- package/tests/body-parser.schema.test.ts +57 -0
- package/tests/compression.schema.test.ts +27 -0
- package/tests/cookie-parser.schema.test.ts +56 -0
- package/tests/cors.schema.test.ts +35 -0
- package/tests/helmet.schema.test.ts +33 -0
- package/tests/hpp.schema.test.ts +31 -0
- package/tests/index.test.ts +105 -0
- package/tests/passport.schema.test.ts +33 -0
- package/tests/rate-limit.schema.test.ts +56 -0
- package/tests/session.schema.test.ts +80 -0
- package/tsconfig.json +8 -8
- package/vitest.config.ts +13 -0
- package/dist/consts/cors.d.ts +0 -15
- package/dist/consts/cors.d.ts.map +0 -1
- package/dist/consts/cors.js +0 -29
- package/dist/consts/error-codes.d.ts +0 -10
- package/dist/consts/error-codes.d.ts.map +0 -1
- package/dist/consts/error-codes.js +0 -12
- package/dist/consts/index.d.ts +0 -8
- package/dist/consts/index.d.ts.map +0 -1
- package/dist/consts/index.js +0 -10
- package/dist/consts/log-levels.d.ts +0 -8
- package/dist/consts/log-levels.d.ts.map +0 -1
- package/dist/consts/log-levels.js +0 -10
- package/dist/consts/node-env.d.ts +0 -7
- package/dist/consts/node-env.d.ts.map +0 -1
- package/dist/consts/node-env.js +0 -9
- package/dist/consts/port.d.ts +0 -6
- package/dist/consts/port.d.ts.map +0 -1
- package/dist/consts/port.js +0 -26
- package/dist/consts/rate-limit.d.ts +0 -9
- package/dist/consts/rate-limit.d.ts.map +0 -1
- package/dist/consts/rate-limit.js +0 -11
- package/dist/consts/session.d.ts +0 -6
- package/dist/consts/session.d.ts.map +0 -1
- package/dist/consts/session.js +0 -8
- package/dist/errors/base-error.d.ts +0 -57
- package/dist/errors/base-error.d.ts.map +0 -1
- package/dist/errors/base-error.js +0 -93
- package/dist/errors/config-error.d.ts +0 -20
- package/dist/errors/config-error.d.ts.map +0 -1
- package/dist/errors/config-error.js +0 -30
- package/dist/errors/http-error.d.ts +0 -17
- package/dist/errors/http-error.d.ts.map +0 -1
- package/dist/errors/http-error.js +0 -24
- package/dist/errors/index.d.ts +0 -5
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js +0 -7
- package/dist/errors/validation-error.d.ts +0 -19
- package/dist/errors/validation-error.d.ts.map +0 -1
- package/dist/errors/validation-error.js +0 -29
- package/dist/helpers/get-node-env.d.ts +0 -13
- package/dist/helpers/get-node-env.d.ts.map +0 -1
- package/dist/helpers/get-node-env.js +0 -27
- package/dist/helpers/index.d.ts +0 -5
- package/dist/helpers/index.d.ts.map +0 -1
- package/dist/helpers/index.js +0 -7
- package/dist/helpers/is-development.d.ts +0 -9
- package/dist/helpers/is-development.d.ts.map +0 -1
- package/dist/helpers/is-development.js +0 -16
- package/dist/helpers/setup-config.d.ts +0 -12
- package/dist/helpers/setup-config.d.ts.map +0 -1
- package/dist/helpers/setup-config.js +0 -21
- package/dist/helpers/setup-middlewares.d.ts +0 -12
- package/dist/helpers/setup-middlewares.d.ts.map +0 -1
- package/dist/helpers/setup-middlewares.js +0 -45
- package/dist/logger.d.ts +0 -3
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -21
- package/dist/middlewares/compression.d.ts +0 -18
- package/dist/middlewares/compression.d.ts.map +0 -1
- package/dist/middlewares/compression.js +0 -26
- package/dist/middlewares/cookie-parser.ts.d.ts +0 -20
- package/dist/middlewares/cookie-parser.ts.d.ts.map +0 -1
- package/dist/middlewares/cookie-parser.ts.js +0 -33
- package/dist/middlewares/cors.d.ts +0 -22
- package/dist/middlewares/cors.d.ts.map +0 -1
- package/dist/middlewares/cors.js +0 -34
- package/dist/middlewares/error-handler.d.ts +0 -21
- package/dist/middlewares/error-handler.d.ts.map +0 -1
- package/dist/middlewares/error-handler.js +0 -43
- package/dist/middlewares/helmet.d.ts +0 -16
- package/dist/middlewares/helmet.d.ts.map +0 -1
- package/dist/middlewares/helmet.js +0 -28
- package/dist/middlewares/hpp.d.ts +0 -18
- package/dist/middlewares/hpp.d.ts.map +0 -1
- package/dist/middlewares/hpp.js +0 -30
- package/dist/middlewares/index.d.ts +0 -10
- package/dist/middlewares/index.d.ts.map +0 -1
- package/dist/middlewares/index.js +0 -12
- package/dist/middlewares/passport.d.ts +0 -16
- package/dist/middlewares/passport.d.ts.map +0 -1
- package/dist/middlewares/passport.js +0 -27
- package/dist/middlewares/rate-limit.d.ts +0 -23
- package/dist/middlewares/rate-limit.d.ts.map +0 -1
- package/dist/middlewares/rate-limit.js +0 -35
- package/dist/middlewares/session.d.ts +0 -16
- package/dist/middlewares/session.d.ts.map +0 -1
- package/dist/middlewares/session.js +0 -23
- package/dist/schemas/compression.d.ts +0 -5
- package/dist/schemas/compression.d.ts.map +0 -1
- package/dist/schemas/compression.js +0 -5
- package/dist/schemas/cookie-parser.d.ts +0 -9
- package/dist/schemas/cookie-parser.d.ts.map +0 -1
- package/dist/schemas/cookie-parser.js +0 -14
- package/dist/schemas/cors.d.ts +0 -6
- package/dist/schemas/cors.d.ts.map +0 -1
- package/dist/schemas/cors.js +0 -9
- package/dist/schemas/error-metadata.d.ts +0 -18
- package/dist/schemas/error-metadata.d.ts.map +0 -1
- package/dist/schemas/error-metadata.js +0 -12
- package/dist/schemas/helmet.d.ts +0 -6
- package/dist/schemas/helmet.d.ts.map +0 -1
- package/dist/schemas/helmet.js +0 -8
- package/dist/schemas/hpp.d.ts +0 -5
- package/dist/schemas/hpp.d.ts.map +0 -1
- package/dist/schemas/hpp.js +0 -8
- package/dist/schemas/index.d.ts +0 -13
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -15
- package/dist/schemas/node-env.d.ts +0 -16
- package/dist/schemas/node-env.d.ts.map +0 -1
- package/dist/schemas/node-env.js +0 -8
- package/dist/schemas/passport.d.ts +0 -6
- package/dist/schemas/passport.d.ts.map +0 -1
- package/dist/schemas/passport.js +0 -8
- package/dist/schemas/port.d.ts +0 -4
- package/dist/schemas/port.d.ts.map +0 -1
- package/dist/schemas/port.js +0 -16
- package/dist/schemas/rate-limit.d.ts +0 -9
- package/dist/schemas/rate-limit.d.ts.map +0 -1
- package/dist/schemas/rate-limit.js +0 -26
- package/dist/schemas/session.d.ts +0 -18
- package/dist/schemas/session.d.ts.map +0 -1
- package/dist/schemas/session.js +0 -32
- package/dist/schemas/wnodex-config.d.ts.map +0 -1
- package/dist/schemas/wnodex-config.js +0 -24
- package/dist/tsconfig.lib.tsbuildinfo +0 -1
- package/dist/wnodex.d.ts +0 -69
- package/dist/wnodex.d.ts.map +0 -1
- package/dist/wnodex.js +0 -131
- package/src/consts/cors.ts +0 -27
- package/src/consts/error-codes.ts +0 -9
- package/src/consts/index.ts +0 -7
- package/src/consts/log-levels.ts +0 -7
- package/src/consts/node-env.ts +0 -6
- package/src/consts/port.ts +0 -23
- package/src/consts/rate-limit.ts +0 -9
- package/src/consts/session.ts +0 -6
- package/src/errors/base-error.ts +0 -111
- package/src/errors/config-error.ts +0 -31
- package/src/errors/http-error.ts +0 -21
- package/src/errors/index.ts +0 -4
- package/src/errors/validation-error.ts +0 -30
- package/src/helpers/get-node-env.ts +0 -27
- package/src/helpers/index.ts +0 -4
- package/src/helpers/is-development.ts +0 -15
- package/src/helpers/setup-config.ts +0 -25
- package/src/helpers/setup-middlewares.ts +0 -56
- package/src/logger.ts +0 -22
- package/src/middlewares/compression.ts +0 -32
- package/src/middlewares/cookie-parser.ts.ts +0 -37
- package/src/middlewares/cors.ts +0 -35
- package/src/middlewares/error-handler.ts +0 -54
- package/src/middlewares/helmet.ts +0 -29
- package/src/middlewares/hpp.ts +0 -31
- package/src/middlewares/index.ts +0 -9
- package/src/middlewares/passport.ts +0 -30
- package/src/middlewares/rate-limit.ts +0 -39
- package/src/middlewares/session.ts +0 -25
- package/src/schemas/compression.ts +0 -8
- package/src/schemas/cookie-parser.ts +0 -21
- package/src/schemas/cors.ts +0 -13
- package/src/schemas/error-metadata.ts +0 -15
- package/src/schemas/helmet.ts +0 -11
- package/src/schemas/hpp.ts +0 -9
- package/src/schemas/index.ts +0 -12
- package/src/schemas/node-env.ts +0 -11
- package/src/schemas/passport.ts +0 -11
- package/src/schemas/port.ts +0 -22
- package/src/schemas/rate-limit.ts +0 -33
- package/src/schemas/session.ts +0 -40
- package/src/schemas/wnodex-config.ts +0 -26
- package/src/wnodex.ts +0 -152
- package/tsconfig.lib.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
package/package.json
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wnodex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"private": false,
|
|
5
|
-
"
|
|
5
|
+
"description": "An extensible and robust Express.js server framework designed for effortless customization and rapid deployment with sensible defaults.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"wnodex",
|
|
8
|
+
"express",
|
|
9
|
+
"framework",
|
|
10
|
+
"typescript",
|
|
11
|
+
"nodejs",
|
|
12
|
+
"server",
|
|
13
|
+
"http",
|
|
14
|
+
"web",
|
|
15
|
+
"security",
|
|
16
|
+
"middleware"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/wnodex/wnodex#readme",
|
|
6
19
|
"bugs": {
|
|
7
|
-
"url": "https://github.com/
|
|
20
|
+
"url": "https://github.com/wnodex/wnodex/issues"
|
|
8
21
|
},
|
|
9
22
|
"repository": {
|
|
10
23
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/
|
|
24
|
+
"url": "git+https://github.com/wnodex/wnodex.git",
|
|
12
25
|
"directory": "packages/wnodex"
|
|
13
26
|
},
|
|
14
27
|
"license": "MIT",
|
|
15
|
-
"
|
|
28
|
+
"type": "module",
|
|
16
29
|
"exports": {
|
|
17
30
|
"./package.json": "./package.json",
|
|
18
31
|
".": {
|
|
@@ -25,30 +38,53 @@
|
|
|
25
38
|
"module": "./dist/index.js",
|
|
26
39
|
"types": "./dist/index.d.ts",
|
|
27
40
|
"dependencies": {
|
|
28
|
-
"
|
|
41
|
+
"@types/body-parser": "^1.19.6",
|
|
42
|
+
"body-parser": "^2.2.2",
|
|
29
43
|
"cookie-parser": "^1.4.7",
|
|
30
|
-
"cors": "^2.8.
|
|
31
|
-
"express": "^5.1
|
|
44
|
+
"cors": "^2.8.6",
|
|
45
|
+
"express": "^5.2.1",
|
|
32
46
|
"express-rate-limit": "^8.2.1",
|
|
33
|
-
"express-session": "^1.
|
|
47
|
+
"express-session": "^1.19.0",
|
|
34
48
|
"helmet": "^8.1.0",
|
|
35
49
|
"hpp": "^0.2.3",
|
|
36
50
|
"passport": "^0.7.0",
|
|
37
|
-
"pino": "^10.
|
|
38
|
-
"pino-pretty": "^13.1.
|
|
39
|
-
"
|
|
40
|
-
"
|
|
51
|
+
"pino": "^10.3.0",
|
|
52
|
+
"pino-pretty": "^13.1.3",
|
|
53
|
+
"zod": "^4.3.6",
|
|
54
|
+
"@wnodex/body-parser": "0.2.2",
|
|
55
|
+
"@wnodex/cookie-parser": "0.2.2",
|
|
56
|
+
"@wnodex/cors": "0.2.2",
|
|
57
|
+
"@wnodex/errors": "0.2.2",
|
|
58
|
+
"@wnodex/hpp": "0.2.2",
|
|
59
|
+
"@wnodex/compression": "0.2.2",
|
|
60
|
+
"@wnodex/passport": "0.2.2",
|
|
61
|
+
"@wnodex/logger": "0.2.2",
|
|
62
|
+
"@wnodex/helmet": "0.2.2",
|
|
63
|
+
"@wnodex/session": "0.2.2",
|
|
64
|
+
"@wnodex/rate-limit": "0.2.2"
|
|
41
65
|
},
|
|
42
66
|
"devDependencies": {
|
|
43
67
|
"@types/compression": "^1.8.1",
|
|
44
68
|
"@types/cookie-parser": "^1.4.10",
|
|
45
69
|
"@types/cors": "^2.8.19",
|
|
46
|
-
"@types/express": "^5.0.
|
|
70
|
+
"@types/express": "^5.0.6",
|
|
47
71
|
"@types/express-session": "^1.18.2",
|
|
48
72
|
"@types/hpp": "^0.2.7",
|
|
49
|
-
"@types/
|
|
73
|
+
"@types/node": "^25.0.10",
|
|
74
|
+
"@types/passport": "^1.0.17",
|
|
75
|
+
"@types/supertest": "^6.0.3",
|
|
76
|
+
"rolldown": "1.0.0-rc.1",
|
|
77
|
+
"supertest": "^7.2.2",
|
|
78
|
+
"typescript": "5.9.2",
|
|
79
|
+
"vitest": "^4.0.18",
|
|
80
|
+
"@wnodex/typescript-config": "0.2.2"
|
|
50
81
|
},
|
|
51
82
|
"publishConfig": {
|
|
52
83
|
"access": "public"
|
|
84
|
+
},
|
|
85
|
+
"scripts": {
|
|
86
|
+
"build": "rolldown -c && tsc",
|
|
87
|
+
"test": "vitest run",
|
|
88
|
+
"test:watch": "vitest"
|
|
53
89
|
}
|
|
54
90
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from 'rolldown';
|
|
2
|
+
|
|
3
|
+
export default defineConfig([
|
|
4
|
+
{
|
|
5
|
+
input: ['src/index.ts'],
|
|
6
|
+
output: {
|
|
7
|
+
format: 'esm',
|
|
8
|
+
dir: 'dist',
|
|
9
|
+
entryFileNames: '[name].js',
|
|
10
|
+
chunkFileNames: '[name]-[hash].js',
|
|
11
|
+
assetFileNames: '[name]-[hash][extname]',
|
|
12
|
+
},
|
|
13
|
+
platform: 'node',
|
|
14
|
+
external: (id) => {
|
|
15
|
+
if (id.startsWith('node:')) return true;
|
|
16
|
+
if (id.startsWith('.') || id.startsWith('/')) return false;
|
|
17
|
+
return true;
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
]);
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { BodyParserOptionsSchema } from '@wnodex/body-parser';
|
|
3
|
+
import { CompressionOptionsSchema } from '@wnodex/compression';
|
|
4
|
+
import { CookieParserOptionsSchema } from '@wnodex/cookie-parser';
|
|
5
|
+
import { CorsOptionsSchema } from '@wnodex/cors';
|
|
6
|
+
import { HelmetOptionsSchema } from '@wnodex/helmet';
|
|
7
|
+
import { HppOptionsSchema } from '@wnodex/hpp';
|
|
8
|
+
import { PassportOptionsSchema } from '@wnodex/passport';
|
|
9
|
+
import { RateLimitOptionsSchema } from '@wnodex/rate-limit';
|
|
10
|
+
import { SessionOptionsSchema } from '@wnodex/session';
|
|
11
|
+
|
|
12
|
+
export const WnodexConfigSchema = z.object({
|
|
13
|
+
port: z.union([z.number(), z.string()]).optional().default(3000),
|
|
14
|
+
bodyParsers: BodyParserOptionsSchema,
|
|
15
|
+
helmet: HelmetOptionsSchema,
|
|
16
|
+
cors: CorsOptionsSchema,
|
|
17
|
+
compression: CompressionOptionsSchema,
|
|
18
|
+
rateLimit: RateLimitOptionsSchema,
|
|
19
|
+
cookieParser: CookieParserOptionsSchema,
|
|
20
|
+
hpp: HppOptionsSchema,
|
|
21
|
+
session: SessionOptionsSchema,
|
|
22
|
+
passport: PassportOptionsSchema,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type WnodexConfig = z.infer<typeof WnodexConfigSchema>;
|
|
26
|
+
export type WnodexConfigInput = z.input<typeof WnodexConfigSchema>;
|
|
27
|
+
export type WnodexConfigOutput = z.output<typeof WnodexConfigSchema>;
|
package/src/index.ts
CHANGED
|
@@ -1,38 +1,149 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import { Server } from 'node:http';
|
|
2
|
+
|
|
3
|
+
import express, { type Application } from 'express';
|
|
4
|
+
|
|
5
|
+
import type { Logger } from 'pino';
|
|
6
|
+
import { logger } from '@wnodex/logger';
|
|
7
|
+
|
|
8
|
+
import { type WnodexConfigInput, type WnodexConfigOutput } from './config.js';
|
|
9
|
+
import { setupConfig } from './setup-config.js';
|
|
10
|
+
import { setupMiddlewares } from './setup-middlewares.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main application class for the Wnodex server.
|
|
14
|
+
*
|
|
15
|
+
* Handles Express app instantiation, configuration validation,
|
|
16
|
+
* middleware setup, logging, error handling, server startup, and graceful shutdown.
|
|
17
|
+
*/
|
|
18
|
+
export class Wnodex {
|
|
19
|
+
private readonly app: Application;
|
|
20
|
+
private readonly config: WnodexConfigOutput;
|
|
21
|
+
private readonly logger: Logger;
|
|
22
|
+
private server?: Server;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Constructs a new Wnodex server instance.
|
|
26
|
+
* Initializes the Express app, logger, validates and stores configuration, and applies middlewares.
|
|
27
|
+
* @param config Configuration input for Wnodex, validated by WnodexConfigSchema.
|
|
28
|
+
* @example
|
|
29
|
+
* const wnodex = new Wnodex({ port: 3000 });
|
|
30
|
+
*/
|
|
31
|
+
constructor(config: WnodexConfigInput) {
|
|
32
|
+
this.app = express();
|
|
33
|
+
|
|
34
|
+
// Logger
|
|
35
|
+
this.logger = logger;
|
|
36
|
+
this.app.set('logger', logger);
|
|
37
|
+
|
|
38
|
+
// Config
|
|
39
|
+
this.config = setupConfig(config);
|
|
40
|
+
|
|
41
|
+
// Global Middlewares
|
|
42
|
+
setupMiddlewares(this.app, this.config);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Provides access to the application's logger instance.
|
|
47
|
+
* @returns Logger instance.
|
|
48
|
+
* @example
|
|
49
|
+
* const log = wnodex.getLogger();
|
|
50
|
+
*/
|
|
51
|
+
public getLogger(): Logger {
|
|
52
|
+
return this.logger;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the validated Wnodex configuration.
|
|
57
|
+
* @returns WnodexConfigOutput object.
|
|
58
|
+
* @example
|
|
59
|
+
* const config = wnodex.getConfig();
|
|
60
|
+
*/
|
|
61
|
+
public getConfig(): WnodexConfigOutput {
|
|
62
|
+
return this.config;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Public getter for the express app instance.
|
|
67
|
+
* @returns The express application instance.
|
|
68
|
+
* @example
|
|
69
|
+
* const app = Wnodex.getApp();
|
|
70
|
+
*/
|
|
71
|
+
public getApp(): Application {
|
|
72
|
+
return this.app;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// --- Wnodex Start Helper ---
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Starts the Wnodex server and listens on the specified port.
|
|
79
|
+
* Resolves when the server is ready.
|
|
80
|
+
* @returns Promise that resolves once server is running.
|
|
81
|
+
* @example
|
|
82
|
+
* await wnodex.start();
|
|
83
|
+
*/
|
|
84
|
+
public start(): Promise<void> {
|
|
85
|
+
const logger = this.getLogger();
|
|
86
|
+
const { port } = this.getConfig();
|
|
87
|
+
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
this.server = this.app.listen(port, () => {
|
|
90
|
+
logger.info(`Server running @ http://localhost:${port}`);
|
|
91
|
+
resolve();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Attach error handler immediately after server creation
|
|
95
|
+
this.server?.on('error', (err) => {
|
|
96
|
+
logger.error(err, 'Server error:');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// --- Wnodex Graceful Shutdown ---
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Gracefully shuts down the Wnodex server.
|
|
105
|
+
* Stops accepting new connections, allows active connections to finish,
|
|
106
|
+
* runs optional asynchronous cleanup chores, and closes the server.
|
|
107
|
+
* @param chores An optional async callback function to perform cleanup tasks
|
|
108
|
+
* before shutdown (e.g., closing DB connections, clearing cache). This function is awaited before closing the server.
|
|
109
|
+
*
|
|
110
|
+
* @returns Promise that resolves when the server has stopped gracefully.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* await wnodex.shutdown(async () => {
|
|
114
|
+
* await db.close();
|
|
115
|
+
* await cache.clear();
|
|
116
|
+
* });
|
|
117
|
+
*/
|
|
118
|
+
public async shutdown(chores?: () => Promise<void> | void): Promise<void> {
|
|
119
|
+
const logger = this.getLogger();
|
|
120
|
+
|
|
121
|
+
if (!this.server) {
|
|
122
|
+
logger.warn('Server not running.');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
logger.info('Shutdown initiated...');
|
|
127
|
+
|
|
128
|
+
if (chores) {
|
|
129
|
+
try {
|
|
130
|
+
await chores();
|
|
131
|
+
} catch (error) {
|
|
132
|
+
logger.error(error, 'Error during cleanup chores');
|
|
133
|
+
// Proceed with shutdown even if chores fail
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
this.server!.close((err) => {
|
|
139
|
+
if (err) {
|
|
140
|
+
logger.error(err, 'Error during server shutdown');
|
|
141
|
+
reject(err);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
logger.info('Server stopped gracefully.');
|
|
145
|
+
resolve();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ConfigError } from '@wnodex/errors';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
WnodexConfigInput,
|
|
5
|
+
WnodexConfigOutput,
|
|
6
|
+
WnodexConfigSchema,
|
|
7
|
+
} from './config.js';
|
|
8
|
+
|
|
9
|
+
export const setupConfig = (config: WnodexConfigInput): WnodexConfigOutput => {
|
|
10
|
+
const result = WnodexConfigSchema.safeParse(config);
|
|
11
|
+
|
|
12
|
+
if (!result.success) {
|
|
13
|
+
throw new ConfigError('Invalid wnodex configuration', result.error);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return result.data;
|
|
17
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Application } from 'express';
|
|
2
|
+
|
|
3
|
+
import { configureBodyParsers } from '@wnodex/body-parser';
|
|
4
|
+
import { configureCompression } from '@wnodex/compression';
|
|
5
|
+
import { configureCookieParser } from '@wnodex/cookie-parser';
|
|
6
|
+
import { configureCors } from '@wnodex/cors';
|
|
7
|
+
import { errorHandler } from '@wnodex/errors';
|
|
8
|
+
import { configureHelmet } from '@wnodex/helmet';
|
|
9
|
+
import { configureHpp } from '@wnodex/hpp';
|
|
10
|
+
import { configurePassport } from '@wnodex/passport';
|
|
11
|
+
import { configureRateLimit } from '@wnodex/rate-limit';
|
|
12
|
+
import { configureSession } from '@wnodex/session';
|
|
13
|
+
|
|
14
|
+
import { WnodexConfigOutput } from './config.js';
|
|
15
|
+
|
|
16
|
+
export const setupMiddlewares = (
|
|
17
|
+
app: Application,
|
|
18
|
+
config: WnodexConfigOutput
|
|
19
|
+
): void => {
|
|
20
|
+
// Helmet
|
|
21
|
+
configureHelmet(app, config.helmet);
|
|
22
|
+
|
|
23
|
+
// CORS
|
|
24
|
+
configureCors(app, config.cors);
|
|
25
|
+
|
|
26
|
+
// Body Parsers
|
|
27
|
+
configureBodyParsers(app, config.bodyParsers);
|
|
28
|
+
|
|
29
|
+
// cookie-parser
|
|
30
|
+
configureCookieParser(app, config.cookieParser);
|
|
31
|
+
|
|
32
|
+
// compression
|
|
33
|
+
configureCompression(app, config.compression);
|
|
34
|
+
|
|
35
|
+
// express-rate-limit
|
|
36
|
+
configureRateLimit(app, config.rateLimit);
|
|
37
|
+
|
|
38
|
+
// hpp
|
|
39
|
+
configureHpp(app, config.hpp);
|
|
40
|
+
|
|
41
|
+
// express-session - Session management
|
|
42
|
+
configureSession(app, config.session);
|
|
43
|
+
|
|
44
|
+
// passport - Authentication middleware
|
|
45
|
+
configurePassport(app, config.passport);
|
|
46
|
+
|
|
47
|
+
// Error Handler (keep it last)
|
|
48
|
+
app.use(errorHandler);
|
|
49
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseBodyParserOptions } from '../../body-parser/src/parse-options';
|
|
4
|
+
|
|
5
|
+
describe('BodyParserOptionsSchema', () => {
|
|
6
|
+
it('should return default when input is undefined', () => {
|
|
7
|
+
const options = parseBodyParserOptions();
|
|
8
|
+
expect(options).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return true when input is true', () => {
|
|
12
|
+
const options = parseBodyParserOptions(true);
|
|
13
|
+
expect(options).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false when input is false', () => {
|
|
17
|
+
const options = parseBodyParserOptions(false);
|
|
18
|
+
expect(options).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return an empty object when input is an empty object', () => {
|
|
22
|
+
const options = parseBodyParserOptions({});
|
|
23
|
+
expect(options).toEqual({});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return the json options when provided', () => {
|
|
27
|
+
const jsonOptions = { limit: '10mb' };
|
|
28
|
+
const options = parseBodyParserOptions({ json: jsonOptions });
|
|
29
|
+
expect(options).toEqual({ json: jsonOptions });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should return the urlencoded options when provided', () => {
|
|
33
|
+
const urlencodedOptions = { extended: false };
|
|
34
|
+
const options = parseBodyParserOptions({ urlencoded: urlencodedOptions });
|
|
35
|
+
expect(options).toEqual({ urlencoded: urlencodedOptions });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return both json and urlencoded options when provided', () => {
|
|
39
|
+
const jsonOptions = { limit: '10mb' };
|
|
40
|
+
const urlencodedOptions = { extended: false };
|
|
41
|
+
const options = parseBodyParserOptions({
|
|
42
|
+
json: jsonOptions,
|
|
43
|
+
urlencoded: urlencodedOptions,
|
|
44
|
+
});
|
|
45
|
+
expect(options).toEqual({
|
|
46
|
+
json: jsonOptions,
|
|
47
|
+
urlencoded: urlencodedOptions,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should throw an error for invalid input', () => {
|
|
52
|
+
// @ts-expect-error - Testing invalid input
|
|
53
|
+
expect(() => parseBodyParserOptions(123)).toThrow(
|
|
54
|
+
'Invalid body-parser options'
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseCompressionOptions } from '../../compression/src/parse-options';
|
|
4
|
+
|
|
5
|
+
describe('CompressionOptionsSchema', () => {
|
|
6
|
+
it('should return default when input is undefined', () => {
|
|
7
|
+
const options = parseCompressionOptions();
|
|
8
|
+
expect(options).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return true when input is true', () => {
|
|
12
|
+
const options = parseCompressionOptions(true);
|
|
13
|
+
expect(options).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false when input is false', () => {
|
|
17
|
+
const options = parseCompressionOptions(false);
|
|
18
|
+
expect(options).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should throw an error for invalid input', () => {
|
|
22
|
+
// @ts-expect-error - Testing invalid input
|
|
23
|
+
expect(() => parseCompressionOptions(123)).toThrow(
|
|
24
|
+
'Invalid compression options'
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseCookieParserOptions } from '../../cookie-parser/src/parse-options';
|
|
4
|
+
|
|
5
|
+
describe('CookieParserOptionsSchema', () => {
|
|
6
|
+
it('should return default when input is undefined', () => {
|
|
7
|
+
const options = parseCookieParserOptions();
|
|
8
|
+
expect(options).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return true when input is true', () => {
|
|
12
|
+
const options = parseCookieParserOptions(true);
|
|
13
|
+
expect(options).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false when input is false', () => {
|
|
17
|
+
const options = parseCookieParserOptions(false);
|
|
18
|
+
expect(options).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return the secret when a string is provided', () => {
|
|
22
|
+
const secret = 'my-secret';
|
|
23
|
+
const options = parseCookieParserOptions({ secret });
|
|
24
|
+
expect(options).toEqual({ secret });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return the secret when an array is provided', () => {
|
|
28
|
+
const secret = ['my-secret-1', 'my-secret-2'];
|
|
29
|
+
const options = parseCookieParserOptions({ secret });
|
|
30
|
+
expect(options).toEqual({ secret });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should return the secret and options when provided', () => {
|
|
34
|
+
const secret = 'my-secret';
|
|
35
|
+
const cookieOptions = { maxAge: 1000 };
|
|
36
|
+
const options = parseCookieParserOptions({
|
|
37
|
+
secret,
|
|
38
|
+
options: cookieOptions,
|
|
39
|
+
});
|
|
40
|
+
expect(options).toEqual({ secret, options: cookieOptions });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should throw an error for invalid input', () => {
|
|
44
|
+
// @ts-expect-error - Testing invalid input
|
|
45
|
+
expect(() => parseCookieParserOptions(123)).toThrow(
|
|
46
|
+
'Invalid cookie-parser options'
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should throw an error for an empty object', () => {
|
|
51
|
+
// @ts-expect-error - Testing invalid input
|
|
52
|
+
expect(() => parseCookieParserOptions({})).toThrow(
|
|
53
|
+
'Invalid cookie-parser options'
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_CORS_OPTIONS } from '../../cors/src/defaults';
|
|
4
|
+
import { parseCorsOptions } from '../../cors/src/parse-options';
|
|
5
|
+
|
|
6
|
+
describe('CorsOptionsSchema', () => {
|
|
7
|
+
it('should return default when input is undefined', () => {
|
|
8
|
+
const options = parseCorsOptions();
|
|
9
|
+
expect(options).toEqual(DEFAULT_CORS_OPTIONS);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return true when input is true', () => {
|
|
13
|
+
const options = parseCorsOptions(true);
|
|
14
|
+
expect(options).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should return false when input is false', () => {
|
|
18
|
+
const options = parseCorsOptions(false);
|
|
19
|
+
expect(options).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return the custom options when provided', () => {
|
|
23
|
+
const customOptions = {
|
|
24
|
+
origin: 'https://example.com',
|
|
25
|
+
methods: ['GET', 'POST'],
|
|
26
|
+
};
|
|
27
|
+
const options = parseCorsOptions(customOptions);
|
|
28
|
+
expect(options).toEqual(customOptions);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should throw an error for invalid input', () => {
|
|
32
|
+
// @ts-expect-error - Testing invalid input
|
|
33
|
+
expect(() => parseCorsOptions(123)).toThrow('Invalid CORS options');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseHelmetOptions } from '../../helmet/src/parse-options';
|
|
4
|
+
|
|
5
|
+
describe('HelmetOptionsSchema', () => {
|
|
6
|
+
it('should return default when input is undefined', () => {
|
|
7
|
+
const options = parseHelmetOptions();
|
|
8
|
+
expect(options).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return true when input is true', () => {
|
|
12
|
+
const options = parseHelmetOptions(true);
|
|
13
|
+
expect(options).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false when input is false', () => {
|
|
17
|
+
const options = parseHelmetOptions(false);
|
|
18
|
+
expect(options).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return the custom options when provided', () => {
|
|
22
|
+
const customOptions = {
|
|
23
|
+
contentSecurityPolicy: false,
|
|
24
|
+
};
|
|
25
|
+
const options = parseHelmetOptions(customOptions);
|
|
26
|
+
expect(options).toEqual(customOptions);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should throw an error for invalid input', () => {
|
|
30
|
+
// @ts-expect-error - Testing invalid input
|
|
31
|
+
expect(() => parseHelmetOptions(123)).toThrow('Invalid Helmet options');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { parseHppOptions } from '../../hpp/src/parse-options';
|
|
4
|
+
|
|
5
|
+
describe('HppOptionsSchema', () => {
|
|
6
|
+
it('should return default when input is undefined', () => {
|
|
7
|
+
const options = parseHppOptions();
|
|
8
|
+
expect(options).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return true when input is true', () => {
|
|
12
|
+
const options = parseHppOptions(true);
|
|
13
|
+
expect(options).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false when input is false', () => {
|
|
17
|
+
const options = parseHppOptions(false);
|
|
18
|
+
expect(options).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return the whitelist array when provided', () => {
|
|
22
|
+
const whitelist = ['param1', 'param2'];
|
|
23
|
+
const options = parseHppOptions(whitelist);
|
|
24
|
+
expect(options).toEqual(whitelist);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should throw an error for invalid input', () => {
|
|
28
|
+
// @ts-expect-error - Testing invalid input
|
|
29
|
+
expect(() => parseHppOptions(123)).toThrow('Invalid Hpp options');
|
|
30
|
+
});
|
|
31
|
+
});
|