@seip/blue-bird 0.3.3 → 0.3.5

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 (43) hide show
  1. package/.env_example +23 -13
  2. package/LICENSE +21 -21
  3. package/README.md +79 -79
  4. package/backend/index.js +12 -12
  5. package/backend/routes/api.js +34 -34
  6. package/backend/routes/frontend.js +1 -8
  7. package/core/app.js +359 -359
  8. package/core/auth.js +69 -69
  9. package/core/cache.js +35 -35
  10. package/core/cli/component.js +42 -42
  11. package/core/cli/init.js +120 -118
  12. package/core/cli/react.js +383 -411
  13. package/core/cli/route.js +42 -42
  14. package/core/cli/scaffolding-auth.js +967 -0
  15. package/core/config.js +41 -41
  16. package/core/debug.js +248 -248
  17. package/core/logger.js +80 -80
  18. package/core/middleware.js +27 -27
  19. package/core/router.js +134 -134
  20. package/core/swagger.js +24 -24
  21. package/core/template.js +288 -288
  22. package/core/upload.js +76 -76
  23. package/core/validate.js +291 -290
  24. package/frontend/index.html +28 -22
  25. package/frontend/resources/js/App.jsx +28 -42
  26. package/frontend/resources/js/Main.jsx +17 -17
  27. package/frontend/resources/js/blue-bird/components/Button.jsx +67 -0
  28. package/frontend/resources/js/blue-bird/components/Card.jsx +17 -0
  29. package/frontend/resources/js/blue-bird/components/DataTable.jsx +126 -0
  30. package/frontend/resources/js/blue-bird/components/Input.jsx +21 -0
  31. package/frontend/resources/js/blue-bird/components/Label.jsx +12 -0
  32. package/frontend/resources/js/blue-bird/components/Modal.jsx +27 -0
  33. package/frontend/resources/js/blue-bird/components/Translate.jsx +12 -0
  34. package/frontend/resources/js/blue-bird/components/Typography.jsx +25 -0
  35. package/frontend/resources/js/blue-bird/contexts/LanguageContext.jsx +29 -0
  36. package/frontend/resources/js/blue-bird/contexts/SnackbarContext.jsx +38 -0
  37. package/frontend/resources/js/blue-bird/contexts/ThemeContext.jsx +49 -0
  38. package/frontend/resources/js/blue-bird/locales/en.json +30 -0
  39. package/frontend/resources/js/blue-bird/locales/es.json +30 -0
  40. package/frontend/resources/js/pages/About.jsx +33 -15
  41. package/frontend/resources/js/pages/Home.jsx +93 -68
  42. package/package.json +56 -55
  43. package/vite.config.js +21 -21
package/core/app.js CHANGED
@@ -1,359 +1,359 @@
1
- import express from "express"
2
- import cors from "cors"
3
- import path from "path"
4
- import chalk from "chalk"
5
- import cookieParser from "cookie-parser"
6
- import rateLimit from "express-rate-limit"
7
- import xss from "xss"
8
- import helmet from "helmet"
9
- import Config from "./config.js"
10
- import Logger from "./logger.js"
11
- import Debug from "./debug.js"
12
-
13
-
14
- const __dirname = Config.dirname()
15
- const props = Config.props()
16
-
17
- /**
18
- * Main Application class to manage Express server, routes, and middlewares.
19
- */
20
- class App {
21
- /**
22
- * Initializes the App instance with the provided options.
23
- * @param {Object} [options] - Configuration options for the application.
24
- * @param {Array<{path: string, router: import('express').Router}>} [options.routes=[]] - Array of route objects containing path and router components.
25
- * @param {Object} [options.cors={}] - CORS configuration options.
26
- * @param {Array<Function>} [options.middlewares=[]] - Array of middleware functions to be applied.
27
- * @param {number|string} [options.port=3000] - Server port.
28
- * @param {string} [options.host="http://localhost"] - Server host URL.
29
- * @param {boolean} [options.logger=true] - Whether to enable the request logger.
30
- * @param {boolean} [options.notFound=true] - Whether to enable the default 404 handler.
31
- * @param {boolean} [options.json=true] - Whether to enable JSON body parsing.
32
- * @param {boolean} [options.urlencoded=true] - Whether to enable URL-encoded body parsing.
33
- * @param {Object} [options.static={path: null, options: {}}] - Static file configuration.
34
- * @param {boolean} [options.cookieParser=true] - Whether to enable cookie parsing.
35
- * @param {boolean|Object} [options.rateLimit=false] - Enable global rate limiting.
36
- * @param {boolean|Object} [options.helmet=true] - Enable Helmet security headers.
37
- * @param {boolean} [options.xssClean=true] - Enable XSS body sanitization.
38
- * @param {boolean|Object} [options.swagger=false] - Enable swagger
39
- * @example
40
- * const app = new App({
41
- * routes: [],
42
- * cors: {}, // { origin: "https://domain:port" }
43
- * middlewares: [],
44
- * port: 3000,
45
- * host: "http://localhost",
46
- * logger: true,
47
- * notFound: true,
48
- * json: true,
49
- * urlencoded: true,
50
- * static: {
51
- * path: "public",
52
- * options: {}
53
- * },
54
- * cookieParser: true,
55
- * rateLimit: {
56
- * windowMs: 10 * 60 * 1000,
57
- * max: 50
58
- * },
59
- * helmet:true,
60
- * xssClean:true,
61
- * swagger:{
62
- * info: {
63
- * title: "Blue Bird API",
64
- * version: "1.0.0",
65
- * description: "Blue Bird Framework API Documentation"
66
- * },
67
- * url : "http://localhost:8000"
68
- * }
69
- * });
70
- */
71
- constructor(options = {
72
- routes: [],
73
- cors: {},
74
- middlewares: [],
75
- port: null,
76
- host: null,
77
- logger: true,
78
- notFound: true,
79
- json: true,
80
- urlencoded: true,
81
- static: {
82
- path: null,
83
- options: {}
84
- },
85
- cookieParser: true,
86
- rateLimit: false,
87
- helmet: false,
88
- xssClean: true,
89
- swagger: false
90
-
91
- }) {
92
- this.app = express()
93
- this.routes = options.routes || []
94
- this.cors = options.cors || {}
95
- this.middlewares = options.middlewares || []
96
- this.port = options.port || props.port
97
- this.host = options.host || props.host
98
- this.logger = options.logger ?? true
99
- this.notFound = options.notFound ?? true
100
- this.json = options.json ?? true
101
- this.urlencoded = options.urlencoded ?? true
102
- this.static = options.static || props.static
103
- this.cookieParser = options.cookieParser ?? true
104
- this.rateLimit = options.rateLimit ?? false
105
- this.helmet = options.helmet ?? true
106
- this.xssClean = options.xssClean ?? true
107
- this.swagger = options.swagger ?? false
108
- this.dispatch()
109
-
110
- }
111
-
112
- /**
113
- * Registers a custom middleware or module in the Express application.
114
- * @param {Function|import('express').Router} record - The middleware function or Express router to register.
115
- * @example
116
- * app.use((req, res, next) => {
117
- * console.log("Middleware");
118
- * next();
119
- * });
120
- */
121
- use(record) {
122
- this.app.use(record)
123
- }
124
- /**
125
- * Sets a configuration value in the Express application.
126
- * @param {string} key - The configuration key.
127
- * @param {*} value - The value to set for the configuration key.
128
- * @example
129
- * app.set("port", 3000);
130
- */
131
- set(key, value) {
132
- this.app.set(key, value)
133
- }
134
-
135
- /**
136
- * Bootstraps the application by configuring global middlewares and routes.
137
- * Sets up JSON parsing, URL encoding, CORS, and custom middlewares.
138
- */
139
- async dispatch() {
140
- if (this.json) this.app.use(express.json())
141
- if (this.urlencoded) this.app.use(express.urlencoded({ extended: true }))
142
- if (this.cookieParser) this.app.use(cookieParser())
143
- if (this.static.path) this.app.use(express.static(path.join(__dirname, this.static.path), this.static.options))
144
-
145
- this.app.use(cors(this.cors))
146
- if (this.rateLimit) {
147
- if (!this.app.get('trust proxy')) {
148
- this.app.set('trust proxy', 1);
149
- }
150
- const defaultRateLimit = {
151
- windowMs: 15 * 60 * 1000,
152
- max: 100,
153
- standardHeaders: true,
154
- legacyHeaders: false,
155
- message: {
156
- success: false,
157
- message: "Too many requests, please try again later."
158
- }
159
- };
160
- const optionsRateLimiter = {
161
- ...defaultRateLimit,
162
- ...(typeof this.rateLimit === "object" ? this.rateLimit : {})
163
- };
164
-
165
- if (props.debug) {
166
- optionsRateLimiter.skip = (req) =>
167
- req.path.startsWith("/debug");
168
- }
169
-
170
- const limiter = rateLimit(optionsRateLimiter);
171
-
172
- this.app.use(limiter);
173
- }
174
- if (this.helmet) {
175
-
176
- const defaultHelmetOptions = {
177
- contentSecurityPolicy: props.debug
178
- ? false
179
- : undefined
180
- };
181
-
182
- const helmetOptions = {
183
- ...defaultHelmetOptions,
184
- ...(typeof this.helmet === "object" ? this.helmet : {})
185
- };
186
-
187
- this.app.use(helmet(helmetOptions));
188
- }
189
-
190
- if (this.xssClean) {
191
- this.app.use(this.xssMiddleware());
192
- }
193
- this.middlewares.map(middleware => {
194
- this.app.use(middleware)
195
- })
196
-
197
- if (this.logger) this.middlewareLogger()
198
-
199
- this.app.use((req, res, next) => {
200
- res.setHeader('X-Powered-By', 'Blue Bird');
201
- next();
202
- });
203
-
204
- if (props.debug) {
205
- Debug.middlewareMetrics(this.app);
206
- }
207
- this.errorHandler();
208
-
209
- if (this.swagger) {
210
- const { default: Swagger } = await import("./swagger.js")
211
- const defaultSwaggerOptions = {
212
- info: {
213
- title: "Blue Bird API",
214
- version: "1.0.0",
215
- description: "Blue Bird Framework API Documentation"
216
- },
217
- url: `${this.host}:${this.port}`,
218
- route: "/docs"
219
- };
220
-
221
- const swaggerOptions = {
222
- ...defaultSwaggerOptions,
223
- ...(typeof this.swagger === "object" ? this.swagger : {})
224
- };
225
-
226
- Swagger.init(this.app, swaggerOptions);
227
- }
228
-
229
- this.dispatchRoutes()
230
-
231
- if (this.notFound) this.notFoundDefault()
232
- }
233
-
234
-
235
- /**
236
- * Middleware that logs incoming HTTP requests to the console and to a log file.
237
- */
238
- middlewareLogger() {
239
- this.app.use((req, res, next) => {
240
- const method = req.method
241
- const url = req.url.replace(/(password|token|authorization)=([^&]+)/gi, "$1=***")
242
- const params = Object.keys(req.params).length > 0 ? ` ${JSON.stringify(req.params)}` : ""
243
- const ip = req.ip
244
- const now = new Date().toISOString()
245
- const time = `${now.split("T")[0]} ${now.split("T")[1].split(".")[0]}`
246
- let message = ` ${time} -${ip} -[${method}] ${url} ${params}`
247
- const logger = new Logger()
248
- logger.info(message)
249
- if (props.debug) {
250
- message = `${chalk.bold.green(time)} - ${chalk.bold.cyan(ip)} -[${chalk.bold.red(method)}] ${chalk.bold.blue(url)} ${chalk.bold.yellow(params)}`
251
- console.log(message)
252
- }
253
- next()
254
- })
255
- }
256
- errorHandler() {
257
- this.app.use((err, req, res, next) => {
258
- const logger = new Logger();
259
- logger.error(err.stack || err.message);
260
-
261
- if (props.debug) {
262
- return res.status(err.status || 500).json({
263
- success: false,
264
- message: err.message,
265
- stack: err.stack
266
- });
267
- }
268
-
269
- return res.status(err.status || 500).json({
270
- success: false
271
- });
272
- });
273
- }
274
-
275
- sanitizeObject(obj) {
276
- if (typeof obj === "string") return xss(obj);
277
-
278
- if (Array.isArray(obj)) {
279
- return obj.map(item => this.sanitizeObject(item));
280
- }
281
-
282
- if (typeof obj === "object" && obj !== null) {
283
- const sanitized = {};
284
- for (const key in obj) {
285
- sanitized[key] = this.sanitizeObject(obj[key]);
286
- }
287
- return sanitized;
288
- }
289
-
290
- return obj;
291
- }
292
-
293
- xssMiddleware() {
294
- return (req, res, next) => {
295
-
296
- if (req.body && typeof req.body === "object") {
297
- this.mutateSanitized(req.body);
298
- }
299
-
300
- if (req.query && typeof req.query === "object") {
301
- this.mutateSanitized(req.query);
302
- }
303
-
304
- if (req.params && typeof req.params === "object") {
305
- this.mutateSanitized(req.params);
306
- }
307
-
308
- next();
309
- };
310
- }
311
- mutateSanitized(obj) {
312
- for (const key in obj) {
313
- if (typeof obj[key] === "string") {
314
- obj[key] = xss(obj[key]);
315
- } else if (typeof obj[key] === "object" && obj[key] !== null) {
316
- this.mutateSanitized(obj[key]);
317
- }
318
- }
319
- }
320
- /**
321
- * Iterates through the stored routes and attaches them to the Express application instance.
322
- */
323
- dispatchRoutes() {
324
- if (props.debug) {
325
- const debug = new Debug();
326
- const debugRouter = debug.getRouter();
327
- this.app.use(debugRouter.path, debugRouter.router);
328
- }
329
- this.routes.map(route => {
330
- this.app.use(route.path, route.router)
331
- })
332
-
333
-
334
- }
335
- /**
336
- * Default 404 handler for unmatched routes.
337
- * Returns a JSON response with a "Not Found" message.
338
- */
339
- notFoundDefault() {
340
- this.app.use((req, res) => {
341
- return res.status(404).json({ message: "Not Found" })
342
- });
343
- }
344
- /**
345
- * Starts the HTTP server and begins listening for incoming connections.
346
- */
347
- run() {
348
- this.app.listen(this.port, () => {
349
- console.log(
350
- chalk.bold.blue('Blue Bird Server Online\n') +
351
- chalk.bold.cyan('Host: ') + chalk.green(`${this.host}:${this.port}`) + '\n' +
352
- chalk.gray('────────────────────────────────')
353
- );
354
- });
355
- }
356
- }
357
-
358
- export default App
359
-
1
+ import express from "express"
2
+ import cors from "cors"
3
+ import path from "path"
4
+ import chalk from "chalk"
5
+ import cookieParser from "cookie-parser"
6
+ import rateLimit from "express-rate-limit"
7
+ import xss from "xss"
8
+ import helmet from "helmet"
9
+ import Config from "./config.js"
10
+ import Logger from "./logger.js"
11
+ import Debug from "./debug.js"
12
+
13
+
14
+ const __dirname = Config.dirname()
15
+ const props = Config.props()
16
+
17
+ /**
18
+ * Main Application class to manage Express server, routes, and middlewares.
19
+ */
20
+ class App {
21
+ /**
22
+ * Initializes the App instance with the provided options.
23
+ * @param {Object} [options] - Configuration options for the application.
24
+ * @param {Array<{path: string, router: import('express').Router}>} [options.routes=[]] - Array of route objects containing path and router components.
25
+ * @param {Object} [options.cors={}] - CORS configuration options.
26
+ * @param {Array<Function>} [options.middlewares=[]] - Array of middleware functions to be applied.
27
+ * @param {number|string} [options.port=3000] - Server port.
28
+ * @param {string} [options.host="http://localhost"] - Server host URL.
29
+ * @param {boolean} [options.logger=true] - Whether to enable the request logger.
30
+ * @param {boolean} [options.notFound=true] - Whether to enable the default 404 handler.
31
+ * @param {boolean} [options.json=true] - Whether to enable JSON body parsing.
32
+ * @param {boolean} [options.urlencoded=true] - Whether to enable URL-encoded body parsing.
33
+ * @param {Object} [options.static={path: null, options: {}}] - Static file configuration.
34
+ * @param {boolean} [options.cookieParser=true] - Whether to enable cookie parsing.
35
+ * @param {boolean|Object} [options.rateLimit=false] - Enable global rate limiting.
36
+ * @param {boolean|Object} [options.helmet=true] - Enable Helmet security headers.
37
+ * @param {boolean} [options.xssClean=true] - Enable XSS body sanitization.
38
+ * @param {boolean|Object} [options.swagger=false] - Enable swagger
39
+ * @example
40
+ * const app = new App({
41
+ * routes: [],
42
+ * cors: {}, // { origin: "https://domain:port" }
43
+ * middlewares: [],
44
+ * port: 3000,
45
+ * host: "http://localhost",
46
+ * logger: true,
47
+ * notFound: true,
48
+ * json: true,
49
+ * urlencoded: true,
50
+ * static: {
51
+ * path: "public",
52
+ * options: {}
53
+ * },
54
+ * cookieParser: true,
55
+ * rateLimit: {
56
+ * windowMs: 10 * 60 * 1000,
57
+ * max: 50
58
+ * },
59
+ * helmet:true,
60
+ * xssClean:true,
61
+ * swagger:{
62
+ * info: {
63
+ * title: "Blue Bird API",
64
+ * version: "1.0.0",
65
+ * description: "Blue Bird Framework API Documentation"
66
+ * },
67
+ * url : "http://localhost:8000"
68
+ * }
69
+ * });
70
+ */
71
+ constructor(options = {
72
+ routes: [],
73
+ cors: {},
74
+ middlewares: [],
75
+ port: null,
76
+ host: null,
77
+ logger: true,
78
+ notFound: true,
79
+ json: true,
80
+ urlencoded: true,
81
+ static: {
82
+ path: null,
83
+ options: {}
84
+ },
85
+ cookieParser: true,
86
+ rateLimit: false,
87
+ helmet: true,
88
+ xssClean: true,
89
+ swagger: false
90
+ }) {
91
+ this.app = express()
92
+ this.routes = options.routes || []
93
+ this.cors = options.cors || {}
94
+ this.middlewares = options.middlewares || []
95
+ this.port = options.port || props.port
96
+ this.host = options.host || props.host
97
+ this.logger = options.logger ?? true
98
+ this.notFound = options.notFound ?? true
99
+ this.json = options.json ?? true
100
+ this.urlencoded = options.urlencoded ?? true
101
+ this.static = options.static || props.static
102
+ this.cookieParser = options.cookieParser ?? true
103
+ this.rateLimit = options.rateLimit ?? false
104
+ this.helmet = options.helmet ?? true
105
+ this.xssClean = options.xssClean ?? true
106
+ this.swagger = options.swagger ?? false
107
+ this.dispatch()
108
+
109
+ }
110
+
111
+ /**
112
+ * Registers a custom middleware or module in the Express application.
113
+ * @param {Function|import('express').Router} record - The middleware function or Express router to register.
114
+ * @example
115
+ * app.use((req, res, next) => {
116
+ * console.log("Middleware");
117
+ * next();
118
+ * });
119
+ */
120
+ use(record) {
121
+ this.app.use(record)
122
+ }
123
+ /**
124
+ * Sets a configuration value in the Express application.
125
+ * @param {string} key - The configuration key.
126
+ * @param {*} value - The value to set for the configuration key.
127
+ * @example
128
+ * app.set("port", 3000);
129
+ */
130
+ set(key, value) {
131
+ this.app.set(key, value)
132
+ }
133
+
134
+ /**
135
+ * Bootstraps the application by configuring global middlewares and routes.
136
+ * Sets up JSON parsing, URL encoding, CORS, and custom middlewares.
137
+ */
138
+ async dispatch() {
139
+ if (this.json) this.app.use(express.json())
140
+ if (this.urlencoded) this.app.use(express.urlencoded({ extended: true }))
141
+ if (this.cookieParser) this.app.use(cookieParser())
142
+ if (this.static.path) this.app.use(express.static(path.join(__dirname, this.static.path), this.static.options))
143
+
144
+ this.app.use(cors(this.cors))
145
+ if (this.rateLimit) {
146
+ if (!this.app.get('trust proxy')) {
147
+ this.app.set('trust proxy', 1);
148
+ }
149
+ const defaultRateLimit = {
150
+ windowMs: 15 * 60 * 1000,
151
+ max: 100,
152
+ standardHeaders: true,
153
+ legacyHeaders: false,
154
+ message: {
155
+ success: false,
156
+ message: "Too many requests, please try again later."
157
+ }
158
+ };
159
+ const optionsRateLimiter = {
160
+ ...defaultRateLimit,
161
+ ...(typeof this.rateLimit === "object" ? this.rateLimit : {})
162
+ };
163
+
164
+ if (props.debug) {
165
+ optionsRateLimiter.skip = (req) =>
166
+ req.path.startsWith("/debug");
167
+ }
168
+
169
+ const limiter = rateLimit(optionsRateLimiter);
170
+
171
+ this.app.use(limiter);
172
+ }
173
+ if (this.helmet) {
174
+
175
+ const defaultHelmetOptions = {
176
+ contentSecurityPolicy: props.debug
177
+ ? false
178
+ : undefined
179
+ };
180
+
181
+ const helmetOptions = {
182
+ ...defaultHelmetOptions,
183
+ ...(typeof this.helmet === "object" ? this.helmet : {})
184
+ };
185
+
186
+ this.app.use(helmet(helmetOptions));
187
+ }
188
+
189
+ if (this.xssClean) {
190
+ this.app.use(this.xssMiddleware());
191
+ }
192
+ this.middlewares.map(middleware => {
193
+ this.app.use(middleware)
194
+ })
195
+
196
+ if (this.logger) this.middlewareLogger()
197
+
198
+ this.app.use((req, res, next) => {
199
+ res.setHeader('X-Powered-By', 'Blue Bird');
200
+ next();
201
+ });
202
+
203
+ if (props.debug) {
204
+ Debug.middlewareMetrics(this.app);
205
+ }
206
+ this.errorHandler();
207
+
208
+ if (this.swagger) {
209
+ const { default: Swagger } = await import("./swagger.js")
210
+ const defaultSwaggerOptions = {
211
+ info: {
212
+ title: "Blue Bird API",
213
+ version: "1.0.0",
214
+ description: "Blue Bird Framework API Documentation"
215
+ },
216
+ url: `${this.host}:${this.port}`,
217
+ route: "/docs"
218
+ };
219
+
220
+ const swaggerOptions = {
221
+ ...defaultSwaggerOptions,
222
+ ...(typeof this.swagger === "object" ? this.swagger : {})
223
+ };
224
+
225
+ Swagger.init(this.app, swaggerOptions);
226
+ }
227
+
228
+ this.dispatchRoutes()
229
+
230
+ if (this.notFound) this.notFoundDefault()
231
+ }
232
+
233
+
234
+ /**
235
+ * Middleware that logs incoming HTTP requests to the console and to a log file.
236
+ */
237
+ middlewareLogger() {
238
+ const logger = new Logger()
239
+ this.app.use((req, res, next) => {
240
+ const method = req.method
241
+ const url = req.url.replace(/(password|token|authorization)=([^&]+)/gi, "$1=***")
242
+ const params = Object.keys(req.params).length > 0 ? ` ${JSON.stringify(req.params)}` : ""
243
+ const ip = req.ip
244
+ const now = new Date().toISOString()
245
+ const time = `${now.split("T")[0]} ${now.split("T")[1].split(".")[0]}`
246
+ let message = ` ${time} -${ip} -[${method}] ${url} ${params}`
247
+
248
+ logger.info(message)
249
+ if (props.debug) {
250
+ message = `${chalk.bold.green(time)} - ${chalk.bold.cyan(ip)} -[${chalk.bold.red(method)}] ${chalk.bold.blue(url)} ${chalk.bold.yellow(params)}`
251
+ console.log(message)
252
+ }
253
+ next()
254
+ })
255
+ }
256
+ errorHandler() {
257
+ this.app.use((err, req, res, next) => {
258
+ const logger = new Logger();
259
+ logger.error(err.stack || err.message);
260
+
261
+ if (props.debug) {
262
+ return res.status(err.status || 500).json({
263
+ success: false,
264
+ message: err.message,
265
+ stack: err.stack
266
+ });
267
+ }
268
+
269
+ return res.status(err.status || 500).json({
270
+ success: false
271
+ });
272
+ });
273
+ }
274
+
275
+ sanitizeObject(obj) {
276
+ if (typeof obj === "string") return xss(obj);
277
+
278
+ if (Array.isArray(obj)) {
279
+ return obj.map(item => this.sanitizeObject(item));
280
+ }
281
+
282
+ if (typeof obj === "object" && obj !== null) {
283
+ const sanitized = {};
284
+ for (const key in obj) {
285
+ sanitized[key] = this.sanitizeObject(obj[key]);
286
+ }
287
+ return sanitized;
288
+ }
289
+
290
+ return obj;
291
+ }
292
+
293
+ xssMiddleware() {
294
+ return (req, res, next) => {
295
+
296
+ if (req.body && typeof req.body === "object") {
297
+ this.mutateSanitized(req.body);
298
+ }
299
+
300
+ if (req.query && typeof req.query === "object") {
301
+ this.mutateSanitized(req.query);
302
+ }
303
+
304
+ if (req.params && typeof req.params === "object") {
305
+ this.mutateSanitized(req.params);
306
+ }
307
+
308
+ next();
309
+ };
310
+ }
311
+ mutateSanitized(obj) {
312
+ for (const key in obj) {
313
+ if (typeof obj[key] === "string") {
314
+ obj[key] = xss(obj[key]);
315
+ } else if (typeof obj[key] === "object" && obj[key] !== null) {
316
+ this.mutateSanitized(obj[key]);
317
+ }
318
+ }
319
+ }
320
+ /**
321
+ * Iterates through the stored routes and attaches them to the Express application instance.
322
+ */
323
+ dispatchRoutes() {
324
+ if (props.debug) {
325
+ const debug = new Debug();
326
+ const debugRouter = debug.getRouter();
327
+ this.app.use(debugRouter.path, debugRouter.router);
328
+ }
329
+ this.routes.map(route => {
330
+ this.app.use(route.path, route.router)
331
+ })
332
+
333
+
334
+ }
335
+ /**
336
+ * Default 404 handler for unmatched routes.
337
+ * Returns a JSON response with a "Not Found" message.
338
+ */
339
+ notFoundDefault() {
340
+ this.app.use((req, res) => {
341
+ return res.status(404).json({ message: "Not Found" })
342
+ });
343
+ }
344
+ /**
345
+ * Starts the HTTP server and begins listening for incoming connections.
346
+ */
347
+ run() {
348
+ this.app.listen(this.port, () => {
349
+ console.log(
350
+ chalk.bold.blue('Blue Bird Server Online\n') +
351
+ chalk.bold.cyan('Host: ') + chalk.green(`${this.host}:${this.port}`) + '\n' +
352
+ chalk.gray('────────────────────────────────')
353
+ );
354
+ });
355
+ }
356
+ }
357
+
358
+ export default App
359
+