wnodex 0.1.0 → 0.2.1

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.
Files changed (207) hide show
  1. package/.turbo/turbo-build.log +7 -0
  2. package/LICENSE +1 -1
  3. package/README.md +5 -91
  4. package/dist/{schemas/wnodex-config.d.ts → config.d.ts} +14 -9
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +22 -0
  7. package/dist/index.d.ts +68 -38
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +126 -41
  10. package/dist/setup-config.d.ts +3 -0
  11. package/dist/setup-config.d.ts.map +1 -0
  12. package/dist/setup-config.js +9 -0
  13. package/dist/setup-middlewares.d.ts +4 -0
  14. package/dist/setup-middlewares.d.ts.map +1 -0
  15. package/dist/setup-middlewares.js +32 -0
  16. package/package.json +42 -15
  17. package/rolldown.config.ts +20 -0
  18. package/src/config.ts +27 -0
  19. package/src/index.ts +149 -38
  20. package/src/setup-config.ts +17 -0
  21. package/src/setup-middlewares.ts +49 -0
  22. package/tests/body-parser.schema.test.ts +57 -0
  23. package/tests/compression.schema.test.ts +27 -0
  24. package/tests/cookie-parser.schema.test.ts +56 -0
  25. package/tests/cors.schema.test.ts +35 -0
  26. package/tests/helmet.schema.test.ts +33 -0
  27. package/tests/hpp.schema.test.ts +31 -0
  28. package/tests/index.test.ts +105 -0
  29. package/tests/passport.schema.test.ts +33 -0
  30. package/tests/rate-limit.schema.test.ts +56 -0
  31. package/tests/session.schema.test.ts +80 -0
  32. package/tsconfig.json +8 -8
  33. package/vitest.config.ts +13 -0
  34. package/dist/consts/cors.d.ts +0 -15
  35. package/dist/consts/cors.d.ts.map +0 -1
  36. package/dist/consts/cors.js +0 -29
  37. package/dist/consts/error-codes.d.ts +0 -10
  38. package/dist/consts/error-codes.d.ts.map +0 -1
  39. package/dist/consts/error-codes.js +0 -12
  40. package/dist/consts/index.d.ts +0 -8
  41. package/dist/consts/index.d.ts.map +0 -1
  42. package/dist/consts/index.js +0 -10
  43. package/dist/consts/log-levels.d.ts +0 -8
  44. package/dist/consts/log-levels.d.ts.map +0 -1
  45. package/dist/consts/log-levels.js +0 -10
  46. package/dist/consts/node-env.d.ts +0 -7
  47. package/dist/consts/node-env.d.ts.map +0 -1
  48. package/dist/consts/node-env.js +0 -9
  49. package/dist/consts/port.d.ts +0 -6
  50. package/dist/consts/port.d.ts.map +0 -1
  51. package/dist/consts/port.js +0 -26
  52. package/dist/consts/rate-limit.d.ts +0 -9
  53. package/dist/consts/rate-limit.d.ts.map +0 -1
  54. package/dist/consts/rate-limit.js +0 -11
  55. package/dist/consts/session.d.ts +0 -6
  56. package/dist/consts/session.d.ts.map +0 -1
  57. package/dist/consts/session.js +0 -8
  58. package/dist/errors/base-error.d.ts +0 -57
  59. package/dist/errors/base-error.d.ts.map +0 -1
  60. package/dist/errors/base-error.js +0 -93
  61. package/dist/errors/config-error.d.ts +0 -20
  62. package/dist/errors/config-error.d.ts.map +0 -1
  63. package/dist/errors/config-error.js +0 -30
  64. package/dist/errors/http-error.d.ts +0 -17
  65. package/dist/errors/http-error.d.ts.map +0 -1
  66. package/dist/errors/http-error.js +0 -24
  67. package/dist/errors/index.d.ts +0 -5
  68. package/dist/errors/index.d.ts.map +0 -1
  69. package/dist/errors/index.js +0 -7
  70. package/dist/errors/validation-error.d.ts +0 -19
  71. package/dist/errors/validation-error.d.ts.map +0 -1
  72. package/dist/errors/validation-error.js +0 -29
  73. package/dist/helpers/get-node-env.d.ts +0 -13
  74. package/dist/helpers/get-node-env.d.ts.map +0 -1
  75. package/dist/helpers/get-node-env.js +0 -27
  76. package/dist/helpers/index.d.ts +0 -5
  77. package/dist/helpers/index.d.ts.map +0 -1
  78. package/dist/helpers/index.js +0 -7
  79. package/dist/helpers/is-development.d.ts +0 -9
  80. package/dist/helpers/is-development.d.ts.map +0 -1
  81. package/dist/helpers/is-development.js +0 -16
  82. package/dist/helpers/setup-config.d.ts +0 -12
  83. package/dist/helpers/setup-config.d.ts.map +0 -1
  84. package/dist/helpers/setup-config.js +0 -21
  85. package/dist/helpers/setup-middlewares.d.ts +0 -12
  86. package/dist/helpers/setup-middlewares.d.ts.map +0 -1
  87. package/dist/helpers/setup-middlewares.js +0 -45
  88. package/dist/logger.d.ts +0 -3
  89. package/dist/logger.d.ts.map +0 -1
  90. package/dist/logger.js +0 -21
  91. package/dist/middlewares/compression.d.ts +0 -18
  92. package/dist/middlewares/compression.d.ts.map +0 -1
  93. package/dist/middlewares/compression.js +0 -26
  94. package/dist/middlewares/cookie-parser.ts.d.ts +0 -20
  95. package/dist/middlewares/cookie-parser.ts.d.ts.map +0 -1
  96. package/dist/middlewares/cookie-parser.ts.js +0 -33
  97. package/dist/middlewares/cors.d.ts +0 -22
  98. package/dist/middlewares/cors.d.ts.map +0 -1
  99. package/dist/middlewares/cors.js +0 -34
  100. package/dist/middlewares/error-handler.d.ts +0 -21
  101. package/dist/middlewares/error-handler.d.ts.map +0 -1
  102. package/dist/middlewares/error-handler.js +0 -43
  103. package/dist/middlewares/helmet.d.ts +0 -16
  104. package/dist/middlewares/helmet.d.ts.map +0 -1
  105. package/dist/middlewares/helmet.js +0 -28
  106. package/dist/middlewares/hpp.d.ts +0 -18
  107. package/dist/middlewares/hpp.d.ts.map +0 -1
  108. package/dist/middlewares/hpp.js +0 -30
  109. package/dist/middlewares/index.d.ts +0 -10
  110. package/dist/middlewares/index.d.ts.map +0 -1
  111. package/dist/middlewares/index.js +0 -12
  112. package/dist/middlewares/passport.d.ts +0 -16
  113. package/dist/middlewares/passport.d.ts.map +0 -1
  114. package/dist/middlewares/passport.js +0 -27
  115. package/dist/middlewares/rate-limit.d.ts +0 -23
  116. package/dist/middlewares/rate-limit.d.ts.map +0 -1
  117. package/dist/middlewares/rate-limit.js +0 -35
  118. package/dist/middlewares/session.d.ts +0 -16
  119. package/dist/middlewares/session.d.ts.map +0 -1
  120. package/dist/middlewares/session.js +0 -23
  121. package/dist/schemas/compression.d.ts +0 -5
  122. package/dist/schemas/compression.d.ts.map +0 -1
  123. package/dist/schemas/compression.js +0 -5
  124. package/dist/schemas/cookie-parser.d.ts +0 -9
  125. package/dist/schemas/cookie-parser.d.ts.map +0 -1
  126. package/dist/schemas/cookie-parser.js +0 -14
  127. package/dist/schemas/cors.d.ts +0 -6
  128. package/dist/schemas/cors.d.ts.map +0 -1
  129. package/dist/schemas/cors.js +0 -9
  130. package/dist/schemas/error-metadata.d.ts +0 -18
  131. package/dist/schemas/error-metadata.d.ts.map +0 -1
  132. package/dist/schemas/error-metadata.js +0 -12
  133. package/dist/schemas/helmet.d.ts +0 -6
  134. package/dist/schemas/helmet.d.ts.map +0 -1
  135. package/dist/schemas/helmet.js +0 -8
  136. package/dist/schemas/hpp.d.ts +0 -5
  137. package/dist/schemas/hpp.d.ts.map +0 -1
  138. package/dist/schemas/hpp.js +0 -8
  139. package/dist/schemas/index.d.ts +0 -13
  140. package/dist/schemas/index.d.ts.map +0 -1
  141. package/dist/schemas/index.js +0 -15
  142. package/dist/schemas/node-env.d.ts +0 -16
  143. package/dist/schemas/node-env.d.ts.map +0 -1
  144. package/dist/schemas/node-env.js +0 -8
  145. package/dist/schemas/passport.d.ts +0 -6
  146. package/dist/schemas/passport.d.ts.map +0 -1
  147. package/dist/schemas/passport.js +0 -8
  148. package/dist/schemas/port.d.ts +0 -4
  149. package/dist/schemas/port.d.ts.map +0 -1
  150. package/dist/schemas/port.js +0 -16
  151. package/dist/schemas/rate-limit.d.ts +0 -9
  152. package/dist/schemas/rate-limit.d.ts.map +0 -1
  153. package/dist/schemas/rate-limit.js +0 -26
  154. package/dist/schemas/session.d.ts +0 -18
  155. package/dist/schemas/session.d.ts.map +0 -1
  156. package/dist/schemas/session.js +0 -32
  157. package/dist/schemas/wnodex-config.d.ts.map +0 -1
  158. package/dist/schemas/wnodex-config.js +0 -24
  159. package/dist/tsconfig.lib.tsbuildinfo +0 -1
  160. package/dist/wnodex.d.ts +0 -69
  161. package/dist/wnodex.d.ts.map +0 -1
  162. package/dist/wnodex.js +0 -131
  163. package/src/consts/cors.ts +0 -27
  164. package/src/consts/error-codes.ts +0 -9
  165. package/src/consts/index.ts +0 -7
  166. package/src/consts/log-levels.ts +0 -7
  167. package/src/consts/node-env.ts +0 -6
  168. package/src/consts/port.ts +0 -23
  169. package/src/consts/rate-limit.ts +0 -9
  170. package/src/consts/session.ts +0 -6
  171. package/src/errors/base-error.ts +0 -111
  172. package/src/errors/config-error.ts +0 -31
  173. package/src/errors/http-error.ts +0 -21
  174. package/src/errors/index.ts +0 -4
  175. package/src/errors/validation-error.ts +0 -30
  176. package/src/helpers/get-node-env.ts +0 -27
  177. package/src/helpers/index.ts +0 -4
  178. package/src/helpers/is-development.ts +0 -15
  179. package/src/helpers/setup-config.ts +0 -25
  180. package/src/helpers/setup-middlewares.ts +0 -56
  181. package/src/logger.ts +0 -22
  182. package/src/middlewares/compression.ts +0 -32
  183. package/src/middlewares/cookie-parser.ts.ts +0 -37
  184. package/src/middlewares/cors.ts +0 -35
  185. package/src/middlewares/error-handler.ts +0 -54
  186. package/src/middlewares/helmet.ts +0 -29
  187. package/src/middlewares/hpp.ts +0 -31
  188. package/src/middlewares/index.ts +0 -9
  189. package/src/middlewares/passport.ts +0 -30
  190. package/src/middlewares/rate-limit.ts +0 -39
  191. package/src/middlewares/session.ts +0 -25
  192. package/src/schemas/compression.ts +0 -8
  193. package/src/schemas/cookie-parser.ts +0 -21
  194. package/src/schemas/cors.ts +0 -13
  195. package/src/schemas/error-metadata.ts +0 -15
  196. package/src/schemas/helmet.ts +0 -11
  197. package/src/schemas/hpp.ts +0 -9
  198. package/src/schemas/index.ts +0 -12
  199. package/src/schemas/node-env.ts +0 -11
  200. package/src/schemas/passport.ts +0 -11
  201. package/src/schemas/port.ts +0 -22
  202. package/src/schemas/rate-limit.ts +0 -33
  203. package/src/schemas/session.ts +0 -40
  204. package/src/schemas/wnodex-config.ts +0 -26
  205. package/src/wnodex.ts +0 -152
  206. package/tsconfig.lib.json +0 -13
  207. package/tsconfig.tsbuildinfo +0 -1
@@ -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
- export * from './consts/cors.js';
2
- export * from './consts/error-codes.js';
3
- export * from './consts/log-levels.js';
4
- export * from './consts/node-env.js';
5
- export * from './consts/port.js';
6
- export * from './consts/rate-limit.js';
7
- export * from './consts/session.js';
8
- export * from './errors/base-error.js';
9
- export * from './errors/config-error.js';
10
- export * from './errors/http-error.js';
11
- export * from './errors/validation-error.js';
12
- export * from './helpers/get-node-env.js';
13
- export * from './helpers/is-development.js';
14
- export * from './helpers/setup-config.js';
15
- export * from './helpers/setup-middlewares.js';
16
- export * from './logger.js';
17
- export * from './middlewares/compression.js';
18
- export * from './middlewares/cookie-parser.ts.js';
19
- export * from './middlewares/cors.js';
20
- export * from './middlewares/error-handler.js';
21
- export * from './middlewares/helmet.js';
22
- export * from './middlewares/hpp.js';
23
- export * from './middlewares/passport.js';
24
- export * from './middlewares/rate-limit.js';
25
- export * from './middlewares/session.js';
26
- export * from './schemas/compression.js';
27
- export * from './schemas/cookie-parser.js';
28
- export * from './schemas/cors.js';
29
- export * from './schemas/error-metadata.js';
30
- export * from './schemas/helmet.js';
31
- export * from './schemas/hpp.js';
32
- export * from './schemas/node-env.js';
33
- export * from './schemas/passport.js';
34
- export * from './schemas/port.js';
35
- export * from './schemas/rate-limit.js';
36
- export * from './schemas/session.js';
37
- export * from './schemas/wnodex-config.js';
38
- export * from './wnodex.js';
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
+ });
@@ -0,0 +1,105 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import supertest from 'supertest';
4
+
5
+ import { Wnodex } from '../src/index.js';
6
+
7
+ describe('Wnodex', () => {
8
+ let wnodex: Wnodex;
9
+
10
+ beforeEach(() => {
11
+ // To see the logs, uncomment the following line
12
+ // vi.spyOn(console, 'log').mockImplementation(() => {});
13
+ });
14
+
15
+ it('should create a new Wnodex instance', () => {
16
+ wnodex = new Wnodex({ port: 3000 });
17
+ expect(wnodex).toBeInstanceOf(Wnodex);
18
+ });
19
+
20
+ it('should get the express app instance', () => {
21
+ wnodex = new Wnodex({ port: 3000 });
22
+ const app = wnodex.getApp();
23
+ expect(app).toBeDefined();
24
+ });
25
+
26
+ it('should get the config', () => {
27
+ const config = { port: 3001 };
28
+ wnodex = new Wnodex(config);
29
+ const wnodexConfig = wnodex.getConfig();
30
+ expect(wnodexConfig.port).toBe(3001);
31
+ });
32
+
33
+ it('should get the logger', () => {
34
+ wnodex = new Wnodex({ port: 3000 });
35
+ const logger = wnodex.getLogger();
36
+ expect(logger).toBeDefined();
37
+ });
38
+
39
+ it('should start and shutdown the server', async () => {
40
+ wnodex = new Wnodex({ port: 3002 });
41
+ const logger = wnodex.getLogger();
42
+ const infoSpy = vi.spyOn(logger, 'info');
43
+
44
+ await wnodex.start();
45
+ expect(infoSpy).toHaveBeenCalledWith(
46
+ 'Server running @ http://localhost:3002'
47
+ );
48
+
49
+ await wnodex.shutdown();
50
+ expect(infoSpy).toHaveBeenCalledWith('Shutdown initiated...');
51
+ expect(infoSpy).toHaveBeenCalledWith('Server stopped gracefully.');
52
+ });
53
+
54
+ it('should respond to a basic request', async () => {
55
+ wnodex = new Wnodex({ port: 3003 });
56
+ const app = wnodex.getApp();
57
+
58
+ app.get('/test', (req, res) => {
59
+ res.status(200).send('OK');
60
+ });
61
+
62
+ await wnodex.start();
63
+
64
+ const response = await supertest(app).get('/test');
65
+ expect(response.status).toBe(200);
66
+ expect(response.text).toBe('OK');
67
+ await wnodex.shutdown();
68
+ });
69
+
70
+ it('should not throw when shutdown is called on a non-running server', async () => {
71
+ wnodex = new Wnodex({ port: 3000 });
72
+ const logger = wnodex.getLogger();
73
+ const warnSpy = vi.spyOn(logger, 'warn');
74
+
75
+ await wnodex.shutdown();
76
+
77
+ expect(warnSpy).toHaveBeenCalledWith('Server not running.');
78
+ });
79
+
80
+ it('should call cleanup chores on shutdown', async () => {
81
+ wnodex = new Wnodex({ port: 3004 });
82
+ const chores = vi.fn().mockImplementation(() => Promise.resolve());
83
+
84
+ await wnodex.start();
85
+ await wnodex.shutdown(chores);
86
+
87
+ expect(chores).toHaveBeenCalled();
88
+ });
89
+
90
+ it('should handle errors during cleanup chores', async () => {
91
+ wnodex = new Wnodex({ port: 3005 });
92
+ const logger = wnodex.getLogger();
93
+ const errorSpy = vi.spyOn(logger, 'error');
94
+ const chores = vi.fn().mockRejectedValue(new Error('Cleanup failed'));
95
+
96
+ await wnodex.start();
97
+ await wnodex.shutdown(chores);
98
+
99
+ expect(chores).toHaveBeenCalled();
100
+ expect(errorSpy).toHaveBeenCalledWith(
101
+ expect.any(Error),
102
+ 'Error during cleanup chores'
103
+ );
104
+ });
105
+ });