kaelum 1.3.6 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,258 +1,261 @@
1
- <div align="center">
2
-
3
- <h1>Kaelum</h1>
4
-
5
- [![npm version](https://img.shields.io/npm/v/kaelum)](https://www.npmjs.com/package/kaelum)
6
- [![Build Status](https://github.com/MatheusCampagnolo/kaelum/actions/workflows/deploy-docs.yml/badge.svg)](https://github.com/MatheusCampagnolo/kaelum/actions)
7
- [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
8
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://matheuscampagnolo.github.io/kaelum/)
9
-
10
- **Kaelum.js** — Minimalist Node.js framework to simplify creation of web pages and REST APIs.
11
- Designed for students and developers who want a fast, opinionated project scaffold and a small, friendly API that encapsulates common Express.js boilerplate.
12
-
13
- 👉 [**Read the full documentation here**](https://matheuscampagnolo.github.io/kaelum/)
14
-
15
- **If Kaelum helps you, consider supporting its development:**
16
-
17
- <a href='https://ko-fi.com/Z8Z51NK4KT' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi6.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
18
-
19
- </div>
20
-
21
- ## 🚀 Quick start
22
-
23
- Create a new project (interactive):
24
-
25
- ```bash
26
- npx kaelum create
27
- ```
28
-
29
- Or create non-interactively (project name + template):
30
-
31
- ```bash
32
- npx kaelum create my-app --template web
33
- # or
34
- npx kaelum create my-api --template api
35
- ```
36
-
37
- Then:
38
-
39
- ```bash
40
- cd my-app
41
- npm install
42
- npm start
43
- ```
44
-
45
- > No need to install Kaelum globally — `npx` handles execution.
46
-
47
- ---
48
-
49
- ## 📦 What Kaelum provides
50
-
51
- - CLI that scaffolds a ready-to-run project (Web or API template) using an opinionated **MVC** structure.
52
- - Thin abstraction layer over **Express.js** that:
53
-
54
- - automates JSON / URL-encoded parsing by default,
55
- - automatically configures common security middlewares via `setConfig` (CORS, Helmet),
56
- - exposes a small, easy-to-learn API for routes, middleware and configuration.
57
-
58
- - Small set of helpers for common tasks: `start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`, and more.
59
-
60
- Kaelum aims to reduce the initial setup burden while keeping flexibility for advanced users.
61
-
62
- ---
63
-
64
- ## 📁 Template structures
65
-
66
- ### Web template (`--template web`)
67
-
68
- ```
69
- my-web-app/
70
- ├── public/ # Static files (CSS, JS)
71
- │ └── style.css
72
- ├── views/ # HTML templates
73
- │ └── index.html
74
- ├── controllers/ # Controller logic (MVC)
75
- │ └── .gitkeep
76
- ├── middlewares/ # Custom middlewares
77
- │ └── logger.js
78
- ├── routes.js # Route definitions (example uses Kaelum helpers)
79
- ├── app.js # Server initialization (uses Kaelum API)
80
- └── package.json
81
- ```
82
-
83
- ### API template (`--template api`)
84
-
85
- ```
86
- my-api-app/
87
- ├── controllers/
88
- │ └── usersController.js
89
- ├── middlewares/
90
- │ └── authMock.js
91
- ├── routes.js
92
- ├── app.js
93
- └── package.json
94
- ```
95
-
96
- ---
97
-
98
- ## 🧩 Core API
99
-
100
- > Kaelum exposes a factory — use `require('kaelum')` and call it to get an app instance:
101
-
102
- ```js
103
- const kaelum = require("kaelum");
104
- const app = kaelum();
105
- ```
106
-
107
- ### `app.setConfig(options)`
108
-
109
- Enable/disable common features:
110
-
111
- ```js
112
- app.setConfig({
113
- cors: true, // apply CORS (requires cors package in dependencies)
114
- helmet: true, // apply Helmet
115
- static: "public", // serve static files from "public"
116
- bodyParser: true, // default: enabled (JSON + urlencoded)
117
- logs: false, // enable request logging via morgan (if installed)
118
- port: 3000, // prefered port (used when calling app.start() without port)
119
- });
120
- ```
121
-
122
- - `setConfig` persists settings to the Kaelum config and will install/remove Kaelum-managed middlewares.
123
- - Kaelum enables JSON/urlencoded parsing by default so beginners won't forget to parse request bodies.
124
-
125
- ---
126
-
127
- ### `app.start(port, callback)`
128
-
129
- Starts the HTTP server. If `port` is omitted, Kaelum reads `port` from `setConfig` or falls back to `3000`.
130
-
131
- ```js
132
- app.start(3000, () => console.log("Running"));
133
- ```
134
-
135
- ---
136
-
137
- ### `app.addRoute(path, handlers)` and `app.apiRoute(resource, handlers)`
138
-
139
- Register routes easily:
140
-
141
- ```js
142
- app.addRoute("/home", {
143
- get: (req, res) => res.send("Welcome!"),
144
- post: (req, res) => res.send("Posted!"),
145
- });
146
-
147
- // apiRoute builds RESTy resources with nested subpaths:
148
- app.apiRoute("users", {
149
- get: listUsers,
150
- post: createUser,
151
- "/:id": {
152
- get: getUserById,
153
- put: updateUser,
154
- delete: deleteUser,
155
- },
156
- });
157
- ```
158
-
159
- `addRoute` also accepts a single handler function (assumed `GET`).
160
-
161
- ---
162
-
163
- ### `app.setMiddleware(...)`
164
-
165
- Flexible helper to register middleware(s):
166
-
167
- ```js
168
- // single middleware
169
- app.setMiddleware(require("helmet")());
170
-
171
- // array of middlewares
172
- app.setMiddleware([mw1, mw2]);
173
-
174
- // mount middleware on a path
175
- app.setMiddleware("/admin", authMiddleware);
176
- ```
177
-
178
- ---
179
-
180
- ### `app.redirect(from, to, status)`
181
-
182
- Register a redirect route:
183
-
184
- ```js
185
- app.redirect("/old-url", "/new-url", 302);
186
- ```
187
-
188
- ---
189
-
190
- ### `app.healthCheck(path = '/health')`
191
-
192
- Adds a health endpoint returning `{ status: 'OK', uptime, timestamp, pid }`.
193
-
194
- ---
195
-
196
- ### `app.useErrorHandler(options)`
197
-
198
- Attach Kaelum's default JSON error handler:
199
-
200
- ```js
201
- app.useErrorHandler({ exposeStack: false });
202
- ```
203
-
204
- It will return standardized JSON for errors and log server-side errors (5xx) to `console.error`.
205
-
206
- ---
207
-
208
- ## 🔧 Local development & contributing
209
-
210
- ```bash
211
- git clone https://github.com/MatheusCampagnolo/kaelum.git
212
- cd kaelum
213
- npm install
214
- npm link
215
- ```
216
-
217
- Now you can test the CLI locally:
218
-
219
- ```bash
220
- npx kaelum create my-test --template web
221
- ```
222
-
223
- ---
224
-
225
- ## 📝 Why Kaelum?
226
-
227
- - Reduces repetitive boilerplate required to start Node/Express web projects.
228
- - Opinionated scaffolding (MVC) helps beginners adopt better structure.
229
- - Keeps a small API surface: easy to teach and document.
230
- - Extensible `setConfig` and middleware helpers allow adding features without exposing Express internals.
231
-
232
- ---
233
-
234
- ## ✅ Current status
235
-
236
- > Kaelum is under active development.
237
- > CLI scaffolds web and API templates, and the framework includes the MVP helpers (`start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`) and security toggles for `cors` and `helmet`.
238
-
239
- ---
240
-
241
- ## 📚 Links
242
-
243
- - [GitHub](https://github.com/MatheusCampagnolo/kaelum)
244
- - [npm](https://www.npmjs.com/package/kaelum)
245
- - [Documentation](https://matheuscampagnolo.github.io/kaelum/)
246
-
247
- ---
248
-
249
- ## 🧾 License
250
-
251
- MIT — see [LICENSE](LICENSE).
252
-
253
- ---
254
-
255
- ## ✍️ Notes for maintainers
256
-
257
- - Templates use `commonjs` (`require` / `module.exports`).
258
- - Update template dependencies to reference the correct Kaelum version when releasing new npm versions.
1
+ <div align="center">
2
+
3
+ <h1>Kaelum</h1>
4
+
5
+ [![npm version](https://img.shields.io/npm/v/kaelum)](https://www.npmjs.com/package/kaelum)
6
+ [![Build Status](https://github.com/MatheusCampagnolo/kaelum/actions/workflows/deploy-docs.yml/badge.svg)](https://github.com/MatheusCampagnolo/kaelum/actions)
7
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
8
+ [![Docs](https://img.shields.io/badge/docs-online-blue)](https://matheuscampagnolo.github.io/kaelum/)
9
+
10
+ **Kaelum.js** — Minimalist Node.js framework to simplify creation of web pages and REST APIs.
11
+ Designed for students and developers who want a fast, opinionated project scaffold and a small, friendly API that encapsulates common Express.js boilerplate.
12
+
13
+ 👉 [**Read the full documentation here**](https://matheuscampagnolo.github.io/kaelum/)
14
+
15
+ **If Kaelum helps you, consider supporting its development:**
16
+
17
+ <a href='https://ko-fi.com/Z8Z51NK4KT' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi6.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
18
+
19
+ </div>
20
+
21
+ ## 🚀 Quick start
22
+
23
+ Create a new project (interactive):
24
+
25
+ ```bash
26
+ npx kaelum create
27
+ ```
28
+
29
+ Or create non-interactively (project name + template):
30
+
31
+ ```bash
32
+ npx kaelum create my-app --template web
33
+ # or
34
+ npx kaelum create my-api --template api
35
+ ```
36
+
37
+ Then:
38
+
39
+ ```bash
40
+ cd my-app
41
+ npm install
42
+ npm start
43
+ ```
44
+
45
+ > No need to install Kaelum globally — `npx` handles execution.
46
+
47
+ ---
48
+
49
+ ## 📦 What Kaelum provides
50
+
51
+ - CLI that scaffolds a ready-to-run project (Web or API template) using an opinionated **MVC** structure.
52
+ - Thin abstraction layer over **Express.js** that:
53
+
54
+ - automates JSON / URL-encoded parsing by default,
55
+ - automatically loads environment variables from `.env`,
56
+ - automatically configures common security middlewares via `setConfig` (CORS, Helmet),
57
+ - simplifies view engine setup via `setConfig`,
58
+ - exposes a small, easy-to-learn API for routes, middleware and configuration.
59
+
60
+ - Small set of helpers for common tasks: `start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`, and more.
61
+
62
+ Kaelum aims to reduce the initial setup burden while keeping flexibility for advanced users.
63
+
64
+ ---
65
+
66
+ ## 📁 Template structures
67
+
68
+ ### Web template (`--template web`)
69
+
70
+ ```
71
+ my-web-app/
72
+ ├── public/ # Static files (CSS, JS)
73
+ │ └── style.css
74
+ ├── views/ # HTML templates
75
+ │ └── index.html
76
+ ├── controllers/ # Controller logic (MVC)
77
+ │ └── .gitkeep
78
+ ├── middlewares/ # Custom middlewares
79
+ │ └── logger.js
80
+ ├── routes.js # Route definitions (example uses Kaelum helpers)
81
+ ├── app.js # Server initialization (uses Kaelum API)
82
+ └── package.json
83
+ ```
84
+
85
+ ### API template (`--template api`)
86
+
87
+ ```
88
+ my-api-app/
89
+ ├── controllers/
90
+ │ └── usersController.js
91
+ ├── middlewares/
92
+ │ └── authMock.js
93
+ ├── routes.js
94
+ ├── app.js
95
+ └── package.json
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 🧩 Core API
101
+
102
+ > Kaelum exposes a factory — use `require('kaelum')` and call it to get an app instance:
103
+
104
+ ```js
105
+ const kaelum = require("kaelum");
106
+ const app = kaelum();
107
+ ```
108
+
109
+ ### `app.setConfig(options)`
110
+
111
+ Enable/disable common features:
112
+
113
+ ```js
114
+ app.setConfig({
115
+ cors: true, // apply CORS (requires cors package in dependencies)
116
+ helmet: true, // apply Helmet
117
+ static: "public", // serve static files from "public"
118
+ bodyParser: true, // default: enabled (JSON + urlencoded)
119
+ logs: false, // enable request logging via morgan (if installed)
120
+ port: 3000, // prefered port (used when calling app.start() without port)
121
+ views: { engine: 'ejs', path: './views' } // configure view engine
122
+ });
123
+ ```
124
+
125
+ - `setConfig` persists settings to the Kaelum config and will install/remove Kaelum-managed middlewares.
126
+ - Kaelum enables JSON/urlencoded parsing by default so beginners won't forget to parse request bodies.
127
+
128
+ ---
129
+
130
+ ### `app.start(port, callback)`
131
+
132
+ Starts the HTTP server. If `port` is omitted, Kaelum reads `port` from `setConfig` or falls back to `3000`.
133
+
134
+ ```js
135
+ app.start(3000, () => console.log("Running"));
136
+ ```
137
+
138
+ ---
139
+
140
+ ### `app.addRoute(path, handlers)` and `app.apiRoute(resource, handlers)`
141
+
142
+ Register routes easily:
143
+
144
+ ```js
145
+ app.addRoute("/home", {
146
+ get: (req, res) => res.send("Welcome!"),
147
+ post: (req, res) => res.send("Posted!"),
148
+ });
149
+
150
+ // apiRoute builds RESTy resources with nested subpaths:
151
+ app.apiRoute("users", {
152
+ get: listUsers,
153
+ post: createUser,
154
+ "/:id": {
155
+ get: getUserById,
156
+ put: updateUser,
157
+ delete: deleteUser,
158
+ },
159
+ });
160
+ ```
161
+
162
+ `addRoute` also accepts a single handler function (assumed `GET`).
163
+
164
+ ---
165
+
166
+ ### `app.setMiddleware(...)`
167
+
168
+ Flexible helper to register middleware(s):
169
+
170
+ ```js
171
+ // single middleware
172
+ app.setMiddleware(require("helmet")());
173
+
174
+ // array of middlewares
175
+ app.setMiddleware([mw1, mw2]);
176
+
177
+ // mount middleware on a path
178
+ app.setMiddleware("/admin", authMiddleware);
179
+ ```
180
+
181
+ ---
182
+
183
+ ### `app.redirect(from, to, status)`
184
+
185
+ Register a redirect route:
186
+
187
+ ```js
188
+ app.redirect("/old-url", "/new-url", 302);
189
+ ```
190
+
191
+ ---
192
+
193
+ ### `app.healthCheck(path = '/health')`
194
+
195
+ Adds a health endpoint returning `{ status: 'OK', uptime, timestamp, pid }`.
196
+
197
+ ---
198
+
199
+ ### `app.useErrorHandler(options)`
200
+
201
+ Attach Kaelum's default JSON error handler:
202
+
203
+ ```js
204
+ app.useErrorHandler({ exposeStack: false });
205
+ ```
206
+
207
+ It will return standardized JSON for errors and log server-side errors (5xx) to `console.error`.
208
+
209
+ ---
210
+
211
+ ## 🔧 Local development & contributing
212
+
213
+ ```bash
214
+ git clone https://github.com/MatheusCampagnolo/kaelum.git
215
+ cd kaelum
216
+ npm install
217
+ npm link
218
+ ```
219
+
220
+ Now you can test the CLI locally:
221
+
222
+ ```bash
223
+ npx kaelum create my-test --template web
224
+ ```
225
+
226
+ ---
227
+
228
+ ## 📝 Why Kaelum?
229
+
230
+ - Reduces repetitive boilerplate required to start Node/Express web projects.
231
+ - Opinionated scaffolding (MVC) helps beginners adopt better structure.
232
+ - Keeps a small API surface: easy to teach and document.
233
+ - Extensible — `setConfig` and middleware helpers allow adding features without exposing Express internals.
234
+
235
+ ---
236
+
237
+ ## Current status
238
+
239
+ > Kaelum is under active development.
240
+ > CLI scaffolds web and API templates, and the framework includes the MVP helpers (`start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`) and security toggles for `cors` and `helmet`.
241
+
242
+ ---
243
+
244
+ ## 📚 Links
245
+
246
+ - [GitHub](https://github.com/MatheusCampagnolo/kaelum)
247
+ - [npm](https://www.npmjs.com/package/kaelum)
248
+ - [Documentation](https://matheuscampagnolo.github.io/kaelum/)
249
+
250
+ ---
251
+
252
+ ## 🧾 License
253
+
254
+ MIT — see [LICENSE](LICENSE).
255
+
256
+ ---
257
+
258
+ ## ✍️ Notes for maintainers
259
+
260
+ - Templates use `commonjs` (`require` / `module.exports`).
261
+ - Update template dependencies to reference the correct Kaelum version when releasing new npm versions.
@@ -4,7 +4,7 @@
4
4
  "description": "Exemplo de app API gerado pela CLI Kaelum",
5
5
  "scripts": {
6
6
  "start": "node app.js",
7
- "dev": "nodemon app.js"
7
+ "dev": "node --watch app.js"
8
8
  },
9
9
  "keywords": [
10
10
  "kaelum",
@@ -13,12 +13,10 @@
13
13
  "author": "",
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "kaelum": "^1.3.0",
16
+ "kaelum": "^1.4.0",
17
17
  "cors": "^2.8.5",
18
18
  "helmet": "^6.0.0",
19
19
  "morgan": "^1.10.0"
20
20
  },
21
- "devDependencies": {
22
- "nodemon": "^2.0.22"
23
- }
21
+ "devDependencies": {}
24
22
  }
@@ -4,7 +4,7 @@
4
4
  "description": "Exemplo de app gerado pela CLI Kaelum (web template)",
5
5
  "scripts": {
6
6
  "start": "node app.js",
7
- "dev": "nodemon app.js"
7
+ "dev": "node --watch app.js"
8
8
  },
9
9
  "keywords": [
10
10
  "kaelum",
@@ -13,11 +13,9 @@
13
13
  "author": "",
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "kaelum": "^1.3.0",
16
+ "kaelum": "^1.4.0",
17
17
  "cors": "^2.8.5",
18
18
  "helmet": "^6.0.0"
19
19
  },
20
- "devDependencies": {
21
- "nodemon": "^2.0.22"
22
- }
20
+ "devDependencies": {}
23
21
  }
package/core/setConfig.js CHANGED
@@ -1,255 +1,271 @@
1
- // core/setConfig.js
2
- // Kaelum centralized configuration helper.
3
- // - Supports toggling CORS, Helmet, static folder, Morgan logs, bodyParser, and port.
4
- // - Persists merged config to app locals (app.set("kaelum:config", ...)).
5
- // - Keeps references to Kaelum-installed middleware so toggles (false) remove them.
6
-
7
- const path = require("path");
8
-
9
- function tryRequire(name) {
10
- try {
11
- return require(name);
12
- } catch (e) {
13
- return null;
14
- }
15
- }
16
-
17
- /**
18
- * Merge new options into existing stored config
19
- * @param {Object} app
20
- * @param {Object} options
21
- */
22
- function persistConfig(app, options = {}) {
23
- const prev = app.locals.kaelumConfig || {};
24
- const merged = Object.assign({}, prev, options);
25
- app.locals.kaelumConfig = merged;
26
- app.set("kaelum:config", merged);
27
- return merged;
28
- }
29
-
30
- /**
31
- * Remove a middleware function reference from express stack
32
- * @param {Object} app
33
- * @param {Function} fn
34
- */
35
- function removeMiddlewareByFn(app, fn) {
36
- if (!app || !app._router || !Array.isArray(app._router.stack)) return;
37
- app._router.stack = app._router.stack.filter((layer) => layer.handle !== fn);
38
- }
39
-
40
- /**
41
- * Remove static middleware previously installed by Kaelum (if any)
42
- * @param {Object} app
43
- */
44
- function removeKaelumStatic(app) {
45
- const prev = app.locals && app.locals._kaelum_static;
46
- if (prev) {
47
- removeMiddlewareByFn(app, prev);
48
- app.locals._kaelum_static = null;
49
- }
50
- }
51
-
52
- /**
53
- * Remove body parsers previously installed by Kaelum
54
- * @param {Object} app
55
- */
56
- function removeKaelumBodyParsers(app) {
57
- const arr = app.locals && app.locals._kaelum_bodyparsers;
58
- if (Array.isArray(arr)) {
59
- arr.forEach((fn) => removeMiddlewareByFn(app, fn));
60
- app.locals._kaelum_bodyparsers = [];
61
- }
62
- }
63
-
64
- /**
65
- * Remove morgan logger if previously set
66
- * @param {Object} app
67
- */
68
- function removeKaelumLogger(app) {
69
- const prev = app.locals && app.locals._kaelum_logger;
70
- if (prev) {
71
- removeMiddlewareByFn(app, prev);
72
- app.locals._kaelum_logger = null;
73
- }
74
- }
75
-
76
- /**
77
- * Remove Kaelum-installed CORS middleware (if any)
78
- * @param {Object} app
79
- */
80
- function removeKaelumCors(app) {
81
- const prev = app.locals && app.locals._kaelum_cors;
82
- if (prev) {
83
- removeMiddlewareByFn(app, prev);
84
- app.locals._kaelum_cors = null;
85
- }
86
- }
87
-
88
- /**
89
- * Remove Kaelum-installed Helmet middleware (if any)
90
- * @param {Object} app
91
- */
92
- function removeKaelumHelmet(app) {
93
- const prev = app.locals && app.locals._kaelum_helmet;
94
- if (prev) {
95
- removeMiddlewareByFn(app, prev);
96
- app.locals._kaelum_helmet = null;
97
- }
98
- }
99
-
100
- /**
101
- * Apply configuration options to the app
102
- * @param {Object} app - express app instance
103
- * @param {Object} options - supported keys: cors, helmet, static, logs, port, bodyParser
104
- */
105
- function setConfig(app, options = {}) {
106
- if (!app) throw new Error("setConfig requires an app instance");
107
-
108
- // persist/merge config
109
- const cfg = persistConfig(app, options);
110
-
111
- // --- CORS ---
112
- if (options.hasOwnProperty("cors")) {
113
- if (options.cors) {
114
- const cors = tryRequire("cors");
115
- const corsOpts = options.cors === true ? {} : options.cors;
116
- if (!cors) {
117
- console.warn(
118
- "Kaelum: cors package not installed. Skipping CORS setup."
119
- );
120
- } else {
121
- // remove previous Kaelum-installed cors if exists
122
- removeKaelumCors(app);
123
-
124
- // create middleware function and store reference so it can be removed later
125
- const corsFn = cors(corsOpts);
126
- app.locals._kaelum_cors = corsFn;
127
- app.use(corsFn);
128
- console.log("🛡️ CORS activated.");
129
- }
130
- } else {
131
- // disable Kaelum-installed CORS middleware if present
132
- removeKaelumCors(app);
133
- console.log("🛡️ CORS disabled (Kaelum-managed).");
134
- }
135
- }
136
-
137
- // --- Helmet ---
138
- if (options.hasOwnProperty("helmet")) {
139
- if (options.helmet) {
140
- const helmet = tryRequire("helmet");
141
- const helmetOpts = options.helmet === true ? {} : options.helmet;
142
- if (!helmet) {
143
- console.warn(
144
- "Kaelum: helmet package not installed. Skipping Helmet setup."
145
- );
146
- } else {
147
- // remove previous Kaelum-installed helmet if exists
148
- removeKaelumHelmet(app);
149
-
150
- const helmetFn = helmet(helmetOpts);
151
- app.locals._kaelum_helmet = helmetFn;
152
- app.use(helmetFn);
153
- console.log("🛡️ Helmet activated.");
154
- }
155
- } else {
156
- // disable Kaelum-installed Helmet middleware if present
157
- removeKaelumHelmet(app);
158
- console.log("🛡️ Helmet disabled (Kaelum-managed).");
159
- }
160
- }
161
-
162
- // --- Static folder handling ---
163
- if (options.hasOwnProperty("static")) {
164
- // remove previous Kaelum static
165
- removeKaelumStatic(app);
166
-
167
- if (options.static) {
168
- const expressStatic =
169
- tryRequire("express").static || require("express").static;
170
- // resolve to absolute path relative to project root if necessary
171
- const dir =
172
- typeof options.static === "string"
173
- ? path.resolve(process.cwd(), options.static)
174
- : path.join(process.cwd(), "public");
175
- const staticFn = expressStatic(dir);
176
- app.locals._kaelum_static = staticFn;
177
- app.use(staticFn);
178
- console.log(`📁 Static files served from ${dir}`);
179
- } else {
180
- // static === false -> nothing to add (static removed)
181
- console.log("📁 Static serving disabled.");
182
- }
183
- }
184
-
185
- // --- Body parser toggle ---
186
- if (options.hasOwnProperty("bodyParser")) {
187
- if (options.bodyParser === false) {
188
- // remove Kaelum-installed body parsers
189
- removeKaelumBodyParsers(app);
190
- console.log("📦 Body parsers disabled.");
191
- } else {
192
- // ensure body parsers are installed (if not present)
193
- if (
194
- !app.locals._kaelum_bodyparsers ||
195
- app.locals._kaelum_bodyparsers.length === 0
196
- ) {
197
- const jsonParser = tryRequire("express").json();
198
- const urlencodedParser = tryRequire("express").urlencoded({
199
- extended: true,
200
- });
201
- app.locals._kaelum_bodyparsers = [jsonParser, urlencodedParser];
202
- app.use(jsonParser);
203
- app.use(urlencodedParser);
204
- console.log("📦 Body parsers enabled (JSON + URL-encoded).");
205
- }
206
- }
207
- }
208
-
209
- // --- Logs (morgan) ---
210
- if (options.hasOwnProperty("logs")) {
211
- // remove previous logger first
212
- removeKaelumLogger(app);
213
-
214
- if (options.logs) {
215
- const morgan = tryRequire("morgan");
216
- if (!morgan) {
217
- console.warn("Kaelum: morgan package not installed. Skipping logs.");
218
- } else {
219
- // simple dev format by default; could be configured
220
- const logger = morgan("dev");
221
- app.locals._kaelum_logger = logger;
222
- app.use(logger);
223
- console.log("📊 Request logging enabled (morgan).");
224
- }
225
- } else {
226
- console.log("📊 Request logging disabled.");
227
- }
228
- }
229
-
230
- // --- Port persisted in config (start will read it) ---
231
- if (options.hasOwnProperty("port")) {
232
- const p = options.port;
233
- if (p === false || p === null) {
234
- // unset
235
- const merged = Object.assign({}, app.locals.kaelumConfig);
236
- delete merged.port;
237
- app.locals.kaelumConfig = merged;
238
- app.set("kaelum:config", merged);
239
- console.log("🔌 Port preference cleared from Kaelum config.");
240
- } else if (typeof p === "number" || typeof p === "string") {
241
- // persist port as number if possible
242
- const asNum = Number(p);
243
- app.locals.kaelumConfig.port = Number.isNaN(asNum) ? p : asNum;
244
- app.set("kaelum:config", app.locals.kaelumConfig);
245
- console.log(
246
- `🔌 Port set to ${app.locals.kaelumConfig.port} in Kaelum config.`
247
- );
248
- }
249
- }
250
-
251
- // Return the full merged config for convenience
252
- return app.locals.kaelumConfig;
253
- }
254
-
1
+ // core/setConfig.js
2
+ // Kaelum centralized configuration helper.
3
+ // - Supports toggling CORS, Helmet, static folder, Morgan logs, bodyParser, and port.
4
+ // - Persists merged config to app locals (app.set("kaelum:config", ...)).
5
+ // - Keeps references to Kaelum-installed middleware so toggles (false) remove them.
6
+
7
+ const path = require("path");
8
+
9
+ function tryRequire(name) {
10
+ try {
11
+ return require(name);
12
+ } catch (e) {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Merge new options into existing stored config
19
+ * @param {Object} app
20
+ * @param {Object} options
21
+ */
22
+ function persistConfig(app, options = {}) {
23
+ const prev = app.locals.kaelumConfig || {};
24
+ const merged = Object.assign({}, prev, options);
25
+ app.locals.kaelumConfig = merged;
26
+ app.set("kaelum:config", merged);
27
+ return merged;
28
+ }
29
+
30
+ /**
31
+ * Remove a middleware function reference from express stack
32
+ * @param {Object} app
33
+ * @param {Function} fn
34
+ */
35
+ function removeMiddlewareByFn(app, fn) {
36
+ if (!app || !app._router || !Array.isArray(app._router.stack)) return;
37
+ app._router.stack = app._router.stack.filter((layer) => layer.handle !== fn);
38
+ }
39
+
40
+ /**
41
+ * Remove static middleware previously installed by Kaelum (if any)
42
+ * @param {Object} app
43
+ */
44
+ function removeKaelumStatic(app) {
45
+ const prev = app.locals && app.locals._kaelum_static;
46
+ if (prev) {
47
+ removeMiddlewareByFn(app, prev);
48
+ app.locals._kaelum_static = null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Remove body parsers previously installed by Kaelum
54
+ * @param {Object} app
55
+ */
56
+ function removeKaelumBodyParsers(app) {
57
+ const arr = app.locals && app.locals._kaelum_bodyparsers;
58
+ if (Array.isArray(arr)) {
59
+ arr.forEach((fn) => removeMiddlewareByFn(app, fn));
60
+ app.locals._kaelum_bodyparsers = [];
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Remove morgan logger if previously set
66
+ * @param {Object} app
67
+ */
68
+ function removeKaelumLogger(app) {
69
+ const prev = app.locals && app.locals._kaelum_logger;
70
+ if (prev) {
71
+ removeMiddlewareByFn(app, prev);
72
+ app.locals._kaelum_logger = null;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Remove Kaelum-installed CORS middleware (if any)
78
+ * @param {Object} app
79
+ */
80
+ function removeKaelumCors(app) {
81
+ const prev = app.locals && app.locals._kaelum_cors;
82
+ if (prev) {
83
+ removeMiddlewareByFn(app, prev);
84
+ app.locals._kaelum_cors = null;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Remove Kaelum-installed Helmet middleware (if any)
90
+ * @param {Object} app
91
+ */
92
+ function removeKaelumHelmet(app) {
93
+ const prev = app.locals && app.locals._kaelum_helmet;
94
+ if (prev) {
95
+ removeMiddlewareByFn(app, prev);
96
+ app.locals._kaelum_helmet = null;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Apply configuration options to the app
102
+ * @param {Object} app - express app instance
103
+ * @param {Object} options - supported keys: cors, helmet, static, logs, port, bodyParser
104
+ */
105
+ function setConfig(app, options = {}) {
106
+ if (!app) throw new Error("setConfig requires an app instance");
107
+
108
+ // persist/merge config
109
+ const cfg = persistConfig(app, options);
110
+
111
+ // --- CORS ---
112
+ if (options.hasOwnProperty("cors")) {
113
+ if (options.cors) {
114
+ const cors = tryRequire("cors");
115
+ const corsOpts = options.cors === true ? {} : options.cors;
116
+ if (!cors) {
117
+ console.warn(
118
+ "Kaelum: cors package not installed. Skipping CORS setup."
119
+ );
120
+ } else {
121
+ // remove previous Kaelum-installed cors if exists
122
+ removeKaelumCors(app);
123
+
124
+ // create middleware function and store reference so it can be removed later
125
+ const corsFn = cors(corsOpts);
126
+ app.locals._kaelum_cors = corsFn;
127
+ app.use(corsFn);
128
+ console.log("🛡️ CORS activated.");
129
+ }
130
+ } else {
131
+ // disable Kaelum-installed CORS middleware if present
132
+ removeKaelumCors(app);
133
+ console.log("🛡️ CORS disabled (Kaelum-managed).");
134
+ }
135
+ }
136
+
137
+ // --- Helmet ---
138
+ if (options.hasOwnProperty("helmet")) {
139
+ if (options.helmet) {
140
+ const helmet = tryRequire("helmet");
141
+ const helmetOpts = options.helmet === true ? {} : options.helmet;
142
+ if (!helmet) {
143
+ console.warn(
144
+ "Kaelum: helmet package not installed. Skipping Helmet setup."
145
+ );
146
+ } else {
147
+ // remove previous Kaelum-installed helmet if exists
148
+ removeKaelumHelmet(app);
149
+
150
+ const helmetFn = helmet(helmetOpts);
151
+ app.locals._kaelum_helmet = helmetFn;
152
+ app.use(helmetFn);
153
+ console.log("🛡️ Helmet activated.");
154
+ }
155
+ } else {
156
+ // disable Kaelum-installed Helmet middleware if present
157
+ removeKaelumHelmet(app);
158
+ console.log("🛡️ Helmet disabled (Kaelum-managed).");
159
+ }
160
+ }
161
+
162
+ // --- Static folder handling ---
163
+ if (options.hasOwnProperty("static")) {
164
+ // remove previous Kaelum static
165
+ removeKaelumStatic(app);
166
+
167
+ if (options.static) {
168
+ const expressStatic =
169
+ tryRequire("express").static || require("express").static;
170
+ // resolve to absolute path relative to project root if necessary
171
+ const dir =
172
+ typeof options.static === "string"
173
+ ? path.resolve(process.cwd(), options.static)
174
+ : path.join(process.cwd(), "public");
175
+ const staticFn = expressStatic(dir);
176
+ app.locals._kaelum_static = staticFn;
177
+ app.use(staticFn);
178
+ console.log(`📁 Static files served from ${dir}`);
179
+ } else {
180
+ // static === false -> nothing to add (static removed)
181
+ console.log("📁 Static serving disabled.");
182
+ }
183
+ }
184
+
185
+ // --- Body parser toggle ---
186
+ if (options.hasOwnProperty("bodyParser")) {
187
+ if (options.bodyParser === false) {
188
+ // remove Kaelum-installed body parsers
189
+ removeKaelumBodyParsers(app);
190
+ console.log("📦 Body parsers disabled.");
191
+ } else {
192
+ // ensure body parsers are installed (if not present)
193
+ if (
194
+ !app.locals._kaelum_bodyparsers ||
195
+ app.locals._kaelum_bodyparsers.length === 0
196
+ ) {
197
+ const jsonParser = tryRequire("express").json();
198
+ const urlencodedParser = tryRequire("express").urlencoded({
199
+ extended: true,
200
+ });
201
+ app.locals._kaelum_bodyparsers = [jsonParser, urlencodedParser];
202
+ app.use(jsonParser);
203
+ app.use(urlencodedParser);
204
+ console.log("📦 Body parsers enabled (JSON + URL-encoded).");
205
+ }
206
+ }
207
+ }
208
+
209
+ // --- Logs (morgan) ---
210
+ if (options.hasOwnProperty("logs")) {
211
+ // remove previous logger first
212
+ removeKaelumLogger(app);
213
+
214
+ if (options.logs) {
215
+ const morgan = tryRequire("morgan");
216
+ if (!morgan) {
217
+ console.warn("Kaelum: morgan package not installed. Skipping logs.");
218
+ } else {
219
+ // simple dev format by default; could be configured
220
+ const logger = morgan("dev");
221
+ app.locals._kaelum_logger = logger;
222
+ app.use(logger);
223
+ console.log("📊 Request logging enabled (morgan).");
224
+ }
225
+ } else {
226
+ console.log("📊 Request logging disabled.");
227
+ }
228
+ }
229
+
230
+ // --- Port persisted in config (start will read it) ---
231
+ if (options.hasOwnProperty("port")) {
232
+ const p = options.port;
233
+ if (p === false || p === null) {
234
+ // unset
235
+ const merged = Object.assign({}, app.locals.kaelumConfig);
236
+ delete merged.port;
237
+ app.locals.kaelumConfig = merged;
238
+ app.set("kaelum:config", merged);
239
+ console.log("🔌 Port preference cleared from Kaelum config.");
240
+ } else if (typeof p === "number" || typeof p === "string") {
241
+ // persist port as number if possible
242
+ const asNum = Number(p);
243
+ app.locals.kaelumConfig.port = Number.isNaN(asNum) ? p : asNum;
244
+ app.set("kaelum:config", app.locals.kaelumConfig);
245
+ console.log(
246
+ `🔌 Port set to ${app.locals.kaelumConfig.port} in Kaelum config.`
247
+ );
248
+ }
249
+ }
250
+
251
+ // --- View Engine ---
252
+ if (options.hasOwnProperty("views")) {
253
+ const v = options.views;
254
+ if (v && typeof v === "object") {
255
+ if (v.engine) {
256
+ app.set("view engine", v.engine);
257
+ console.log(`🎨 View engine set to: ${v.engine}`);
258
+ }
259
+ if (v.path) {
260
+ const p = path.resolve(process.cwd(), v.path);
261
+ app.set("views", p);
262
+ console.log(`🎨 Views directory set to: ${p}`);
263
+ }
264
+ }
265
+ }
266
+
267
+ // Return the full merged config for convenience
268
+ return app.locals.kaelumConfig;
269
+ }
270
+
255
271
  module.exports = setConfig;
package/createApp.js CHANGED
@@ -6,6 +6,7 @@
6
6
  // - exposes existing core helpers (start, addRoute, setMiddleware, apiRoute)
7
7
  // - exposes error handler helper app.useErrorHandler()
8
8
 
9
+ require("dotenv").config();
9
10
  const express = require("express");
10
11
  const path = require("path");
11
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaelum",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "description": "A minimalist Node.js framework for building web pages and APIs with simplicity and speed.",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -27,6 +27,7 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "cors": "^2.8.5",
30
+ "dotenv": "^17.2.3",
30
31
  "ejs": "^3.1.10",
31
32
  "express": "^4.18.2",
32
33
  "fs-extra": "^11.3.0",