kaelum 1.4.3 → 1.4.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.
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ docs
3
+ coverage
4
+ package-lock.json
5
+ *.md
package/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "es5",
5
+ "printWidth": 90,
6
+ "tabWidth": 2
7
+ }
package/.versionrc.js ADDED
@@ -0,0 +1,20 @@
1
+ module.exports = {
2
+ infile: 'docs/misc/changelog.md',
3
+ types: [
4
+ { type: 'feat', section: 'Features' },
5
+ { type: 'fix', section: 'Bug Fixes' },
6
+ { type: 'perf', section: 'Performance Improvements' },
7
+ { type: 'revert', section: 'Reverts' },
8
+ { type: 'docs', section: 'Documentation', hidden: false },
9
+ { type: 'style', section: 'Styles', hidden: true },
10
+ { type: 'chore', section: 'Miscellaneous', hidden: false },
11
+ { type: 'refactor', section: 'Code Refactoring', hidden: false },
12
+ { type: 'test', section: 'Tests', hidden: true },
13
+ { type: 'build', section: 'Build System', hidden: true },
14
+ { type: 'ci', section: 'CI/CD', hidden: true },
15
+ ],
16
+ commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}',
17
+ compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}',
18
+ issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}',
19
+ userUrlFormat: '{{host}}/{{user}}'
20
+ };
@@ -0,0 +1,57 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ * Using welcoming and inclusive language
20
+ * Being respectful of differing viewpoints and experiences
21
+ * Gracefully accepting constructive criticism
22
+ * Focusing on what is best for the community
23
+ * Showing empathy toward other community members
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
28
+ * Trolling, insulting or derogatory comments, and personal or political attacks
29
+ * Public or private harassment
30
+ * Publishing others' private information without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
32
+
33
+ ## Enforcement Responsibilities
34
+
35
+ Community leaders are responsible for clarifying and enforcing our standards of
36
+ acceptable behavior and will take appropriate and fair corrective action in
37
+ response to any behavior that they deem inappropriate, threatening, offensive,
38
+ or harmful.
39
+
40
+ ## Scope
41
+
42
+ This Code of Conduct applies within all community spaces, and also applies when
43
+ an individual is officially representing the community in public spaces.
44
+
45
+ ## Enforcement
46
+
47
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
48
+ reported to the community leaders responsible for enforcement at
49
+ **campagno.matheus@gmail.com**.
50
+
51
+ All complaints will be reviewed and investigated promptly and fairly.
52
+
53
+ ## Attribution
54
+
55
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
56
+ version 2.1, available at
57
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
@@ -0,0 +1,79 @@
1
+ # Contributing to Kaelum
2
+
3
+ Thank you for your interest in contributing to Kaelum! Every contribution helps make the framework better.
4
+
5
+ ## Getting Started
6
+
7
+ 1. **Fork** the repository on GitHub
8
+ 2. **Clone** your fork locally:
9
+ ```bash
10
+ git clone https://github.com/YOUR_USERNAME/kaelum.git
11
+ cd kaelum
12
+ ```
13
+ 3. **Install** dependencies:
14
+ ```bash
15
+ npm install
16
+ ```
17
+ 4. **Run tests** to make sure everything works:
18
+ ```bash
19
+ npm test
20
+ ```
21
+
22
+ ## Development Workflow
23
+
24
+ 1. Create a new branch from `main`:
25
+ ```bash
26
+ git checkout -b feat/your-feature
27
+ ```
28
+ 2. Make your changes
29
+ 3. Write or update tests as needed
30
+ 4. Run `npm test` to verify
31
+ 5. Commit using [Conventional Commits](https://www.conventionalcommits.org/):
32
+ ```bash
33
+ git commit -m "feat(core): add new feature"
34
+ ```
35
+ 6. Push and open a Pull Request
36
+
37
+ ## Commit Convention
38
+
39
+ We follow **Conventional Commits**:
40
+
41
+ | Prefix | Usage |
42
+ |--------|-------|
43
+ | `feat` | New feature |
44
+ | `fix` | Bug fix |
45
+ | `docs` | Documentation only |
46
+ | `refactor` | Code change that neither fixes a bug nor adds a feature |
47
+ | `test` | Adding or updating tests |
48
+ | `chore` | Maintenance tasks |
49
+ | `perf` | Performance improvements |
50
+
51
+ ## Pull Request Guidelines
52
+
53
+ - Describe **what** changed and **why**
54
+ - Reference related issues (e.g., `Closes #42`)
55
+ - Keep PRs focused — one feature or fix per PR
56
+ - Ensure all tests pass
57
+ - Update documentation if applicable
58
+
59
+ ## Reporting Bugs
60
+
61
+ Use the [Bug Report](https://github.com/kaelumjs/kaelum/issues/new?template=bug_report.md) issue template. Include:
62
+
63
+ - Steps to reproduce
64
+ - Expected vs actual behavior
65
+ - Node.js and Kaelum versions
66
+ - Relevant logs or error messages
67
+
68
+ ## Suggesting Features
69
+
70
+ Use the [Feature Request](https://github.com/kaelumjs/kaelum/issues/new?template=feature_request.md) issue template. Describe:
71
+
72
+ - The problem you're trying to solve
73
+ - Your proposed solution
74
+ - Any alternatives you considered
75
+
76
+ ## Code of Conduct
77
+
78
+ This project follows the [Contributor Covenant Code of Conduct](./CODE_OF_CONDUCT.md).
79
+ By participating, you agree to abide by its terms.
package/README.md CHANGED
@@ -1,281 +1,260 @@
1
1
  <div align="center">
2
2
 
3
+ <img src="docs/public/logo-black.svg" alt="Kaelum" width="120" />
4
+
3
5
  <h1>Kaelum</h1>
4
6
 
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/)
7
+ <p><strong>Fast, minimalist Node.js framework for web apps & REST APIs</strong></p>
9
8
 
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.
9
+ [![npm version](https://img.shields.io/npm/v/kaelum?color=blue)](https://www.npmjs.com/package/kaelum)
10
+ [![npm downloads](https://img.shields.io/npm/dm/kaelum?color=green)](https://www.npmjs.com/package/kaelum)
11
+ [![CI](https://github.com/kaelumjs/kaelum/actions/workflows/test.yml/badge.svg)](https://github.com/kaelumjs/kaelum/actions)
12
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
12
13
 
13
- 👉 [**Read the full documentation here**](https://matheuscampagnolo.github.io/kaelum/)
14
+ [📚 Documentation](https://kaelumjs.vercel.app) · [🐛 Report Bug](https://github.com/kaelumjs/kaelum/issues/new?template=bug_report.md) · [💡 Request Feature](https://github.com/kaelumjs/kaelum/issues/new?template=feature_request.md)
14
15
 
15
- **If Kaelum helps you, consider supporting its development:**
16
+ </div>
16
17
 
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
+ ---
18
19
 
19
- </div>
20
+ ## Why Kaelum?
20
21
 
21
- ## 🚀 Quick start
22
+ <table>
23
+ <tr>
24
+ <td width="50%">
22
25
 
23
- Create a new project (interactive):
26
+ **Without Kaelum (raw Express)**
24
27
 
25
- ```bash
26
- npx kaelum create
28
+ ```js
29
+ const express = require("express");
30
+ const cors = require("cors");
31
+ const helmet = require("helmet");
32
+ const morgan = require("morgan");
33
+ const path = require("path");
34
+
35
+ const app = express();
36
+ app.use(express.json());
37
+ app.use(express.urlencoded({ extended: true }));
38
+ app.use(cors());
39
+ app.use(helmet());
40
+ app.use(morgan("dev"));
41
+ app.use(express.static(path.join(__dirname, "public")));
42
+ app.set("view engine", "ejs");
43
+
44
+ app.get("/users", listUsers);
45
+ app.post("/users", createUser);
46
+ app.get("/users/:id", getUser);
47
+
48
+ app.listen(3000);
27
49
  ```
28
50
 
29
- Or create non-interactively (project name + template):
51
+ </td>
52
+ <td width="50%">
30
53
 
31
- ```bash
32
- npx kaelum create my-app --template web
33
- # or
34
- npx kaelum create my-api --template api
35
- ```
54
+ **With Kaelum** ✨
36
55
 
37
- Then:
56
+ ```js
57
+ const kaelum = require("kaelum");
58
+ const app = kaelum();
38
59
 
39
- ```bash
40
- cd my-app
41
- npm install
42
- npm start
60
+ app.setConfig({
61
+ cors: true,
62
+ helmet: true,
63
+ logs: "dev",
64
+ port: 3000,
65
+ });
66
+
67
+ app.apiRoute("users", {
68
+ get: listUsers,
69
+ post: createUser,
70
+ "/:id": { get: getUser },
71
+ });
72
+
73
+ app.start();
43
74
  ```
44
75
 
45
- > No need to install Kaelum globally — `npx` handles execution.
76
+ </td>
77
+ </tr>
78
+ </table>
79
+
80
+ > **Less boilerplate. Same Express power. Better DX.**
46
81
 
47
82
  ---
48
83
 
49
- ## 📦 What Kaelum provides
84
+ ## Quick Start
50
85
 
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:
86
+ ```bash
87
+ # Scaffold a new project
88
+ npx kaelum create my-app --template web
53
89
 
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.
90
+ # Or an API project
91
+ npx kaelum create my-api --template api
59
92
 
60
- - Small set of helpers for common tasks: `start`, `addRoute`, `apiRoute`, `setConfig`, `static`, `redirect`, `healthCheck`, `useErrorHandler`, and more.
93
+ # Run it
94
+ cd my-app && npm install && npm start
95
+ ```
61
96
 
62
- Kaelum aims to reduce the initial setup burden while keeping flexibility for advanced users.
97
+ > No global install needed `npx` handles everything.
63
98
 
64
99
  ---
65
100
 
66
- ## 📁 Template structures
101
+ ## Features
67
102
 
68
- ### Web template (`--template web`)
103
+ | Feature | Description |
104
+ |---------|-------------|
105
+ | 🚀 **Zero-Config Start** | JSON parsing, static files, EJS views — all pre-configured |
106
+ | 🌳 **Tree Routing** | Recursive nested routes with `addRoute` and `apiRoute` |
107
+ | 🔒 **Security Built-in** | One-toggle CORS, Helmet, and XSS protection |
108
+ | 🛠️ **CLI Scaffolding** | `npx kaelum create` with Web and API templates |
109
+ | 📦 **Dual Module** | Works with both `require()` and `import` |
110
+ | 🏥 **Health Checks** | Built-in `/health` endpoint with readiness probes |
111
+ | ⚡ **Middleware Manager** | Track, add, and remove middleware programmatically |
112
+ | 🔄 **Redirects** | Declarative redirect maps with single, array, or object syntax |
113
+ | 🛡️ **Error Handler** | Standardized JSON/HTML error responses with hooks |
69
114
 
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
- │ └── pagesController.js
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
- ```
115
+ ---
84
116
 
85
- ### API template (`--template api`)
117
+ ## 📦 Installation
86
118
 
119
+ ```bash
120
+ npm install kaelum
87
121
  ```
88
- my-api-app/
89
- ├── controllers/
90
- │ └── usersController.js
91
- ├── middlewares/
92
- │ └── authMock.js
93
- ├── routes.js
94
- ├── app.js
95
- └── package.json
122
+
123
+ ```js
124
+ // CommonJS
125
+ const kaelum = require("kaelum");
126
+ const app = kaelum();
127
+
128
+ // ESM
129
+ import kaelum from "kaelum";
130
+ const app = kaelum();
96
131
  ```
97
132
 
98
133
  ---
99
134
 
100
- ## 🧩 Core API
101
-
102
- > Kaelum exposes a factory — use `require` (CommonJS) or `import` (ESM) to get an app instance:
103
-
104
- ```js
105
- // CommonJS
106
- const kaelum = require("kaelum");
107
- const app = kaelum();
108
-
109
- // ESM
110
- import kaelum from "kaelum";
111
- const app = kaelum();
112
- ```
135
+ ## 🧩 API Overview
113
136
 
114
137
  ### `app.setConfig(options)`
115
138
 
116
- Enable/disable common features:
117
-
118
139
  ```js
119
140
  app.setConfig({
120
- cors: true, // apply CORS (requires cors package in dependencies)
121
- helmet: true, // apply Helmet
122
- static: "public", // serve static files from "public"
123
- bodyParser: true, // default: enabled (JSON + urlencoded)
124
- logs: false, // enable request logging via morgan (if installed)
125
- port: 3000, // prefered port (used when calling app.start() without port)
126
- views: { engine: 'ejs', path: './views' } // configure view engine
141
+ cors: true, // enable CORS
142
+ helmet: true, // HTTP security headers
143
+ static: "public", // serve static files
144
+ logs: "dev", // morgan request logging
145
+ bodyParser: true, // JSON + urlencoded (default: on)
146
+ port: 3000, // preferred port
147
+ views: { engine: "ejs", path: "./views" },
127
148
  });
128
149
  ```
129
150
 
130
- - `setConfig` persists settings to the Kaelum config and will install/remove Kaelum-managed middlewares.
131
- - Kaelum enables JSON/urlencoded parsing by default so beginners won't forget to parse request bodies.
132
-
133
- ---
134
-
135
- ### `app.start(port, callback)`
136
-
137
- Starts the HTTP server. If `port` is omitted, Kaelum reads `port` from `setConfig` or falls back to `3000`.
151
+ ### `app.addRoute(path, handlers)`
138
152
 
139
153
  ```js
140
- app.start(3000, () => console.log("Running"));
154
+ app.addRoute("/dashboard", {
155
+ get: (req, res) => res.render("dashboard"),
156
+ post: handleForm,
157
+ "/settings": {
158
+ get: showSettings,
159
+ put: updateSettings,
160
+ },
161
+ });
141
162
  ```
142
163
 
143
- ---
144
-
145
- ### `app.addRoute(path, handlers)` and `app.apiRoute(resource, handlers)`
146
-
147
- Register routes easily:
164
+ ### `app.apiRoute(resource, handlers)`
148
165
 
149
166
  ```js
150
- app.addRoute("/home", {
151
- get: (req, res) => res.send("Welcome!"),
152
- post: (req, res) => res.send("Posted!"),
153
- });
154
-
155
- // apiRoute builds RESTy resources with recursive nested subpaths:
156
- app.apiRoute("users", {
157
- get: listUsers,
158
- post: createUser,
167
+ app.apiRoute("products", {
168
+ get: listAll,
169
+ post: create,
159
170
  "/:id": {
160
- get: getUserById,
161
- put: updateUser,
162
- delete: deleteUser,
163
- "/posts": {
164
- get: getUserPosts // GET /users/:id/posts
165
- }
171
+ get: getById,
172
+ put: update,
173
+ delete: remove,
174
+ "/reviews": {
175
+ get: getReviews, // GET /products/:id/reviews
176
+ post: addReview,
177
+ },
166
178
  },
167
179
  });
168
180
  ```
169
181
 
170
- `addRoute` also accepts a single handler function (assumed `GET`).
171
-
172
- ---
173
-
174
- ### `app.setMiddleware(...)`
175
-
176
- Flexible helper to register middleware(s):
182
+ ### Other Helpers
177
183
 
178
184
  ```js
179
- // single middleware
180
- app.setMiddleware(require("helmet")());
181
-
182
- // array of middlewares
183
- app.setMiddleware([mw1, mw2]);
184
-
185
- // mount middleware on a path
186
- app.setMiddleware("/admin", authMiddleware);
185
+ app.start(3000); // start server
186
+ app.setMiddleware("/admin", authMiddleware); // scoped middleware
187
+ app.redirect("/old", "/new", 301); // redirects
188
+ app.healthCheck("/health"); // health endpoint
189
+ app.useErrorHandler({ exposeStack: false }); // error handling
187
190
  ```
188
191
 
189
192
  ---
190
193
 
191
- ### `app.redirect(from, to, status)`
194
+ ## 📁 Project Templates
192
195
 
193
- Register a redirect route:
196
+ ### Web Template
194
197
 
195
- ```js
196
- app.redirect("/old-url", "/new-url", 302);
198
+ ```
199
+ my-web-app/
200
+ ├── public/ # Static assets
201
+ ├── views/ # EJS templates
202
+ ├── controllers/ # Route logic (MVC)
203
+ ├── middlewares/ # Custom middleware
204
+ ├── routes.js # Route definitions
205
+ ├── app.js # Entry point
206
+ └── package.json
197
207
  ```
198
208
 
199
- ---
200
-
201
- ### `app.healthCheck(path = '/health')`
202
-
203
- Adds a health endpoint returning `{ status: 'OK', uptime, timestamp, pid }`.
204
-
205
- ---
206
-
207
- ### `app.useErrorHandler(options)`
208
-
209
- Attach Kaelum's default JSON error handler:
209
+ ### API Template
210
210
 
211
- ```js
212
- app.useErrorHandler({ exposeStack: false });
213
211
  ```
214
-
215
- It will return standardized JSON for errors and log server-side errors (5xx) to `console.error`.
212
+ my-api/
213
+ ├── controllers/ # Business logic
214
+ ├── middlewares/ # Auth, validation
215
+ ├── routes.js # API routes
216
+ ├── app.js # Entry point
217
+ └── package.json
218
+ ```
216
219
 
217
220
  ---
218
221
 
219
- ## 🧪 Running Tests
220
-
221
- Kaelum includes a unit test suite using **Jest**. To run the tests:
222
+ ## 🧪 Testing
222
223
 
223
224
  ```bash
224
- npm test
225
+ npm test # run all tests
226
+ npm run lint # check code with ESLint
227
+ npm run format # format code with Prettier
225
228
  ```
226
229
 
227
- This checks core functionality including `setConfig`, routes, and error handlers.
228
-
229
230
  ---
230
231
 
231
- ## 🔧 Local development & contributing
232
-
233
- ```bash
234
- git clone https://github.com/MatheusCampagnolo/kaelum.git
235
- cd kaelum
236
- npm install
237
- npm link
238
- ```
232
+ ## 🤝 Contributing
239
233
 
240
- Now you can test the CLI locally:
234
+ We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a PR.
241
235
 
242
- ```bash
243
- npx kaelum create my-test --template web
244
- ```
236
+ See also: [Code of Conduct](CODE_OF_CONDUCT.md) · [Security Policy](SECURITY.md)
245
237
 
246
238
  ---
247
239
 
248
- ## 📝 Why Kaelum?
240
+ ## 🌐 Ecosystem
249
241
 
250
- - Reduces repetitive boilerplate required to start Node/Express web projects.
251
- - Opinionated scaffolding (MVC) helps beginners adopt better structure.
252
- - Keeps a small API surface: easy to teach and document.
253
- - Extensible `setConfig` and middleware helpers allow adding features without exposing Express internals.
242
+ | Package | Description |
243
+ |---------|-------------|
244
+ | [kaelum](https://www.npmjs.com/package/kaelum) | Core framework |
245
+ | [kaelumjs/docs](https://github.com/kaelumjs/docs) | Documentation site |
246
+ | [kaelumjs/.github](https://github.com/kaelumjs/.github) | Shared community standards |
254
247
 
255
248
  ---
256
249
 
257
- ## Current status
258
-
259
- > Kaelum is under active development.
260
- > 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`.
261
-
262
- ---
250
+ ## Support
263
251
 
264
- ## 📚 Links
252
+ If Kaelum helps you, consider supporting its development:
265
253
 
266
- - [GitHub](https://github.com/MatheusCampagnolo/kaelum)
267
- - [npm](https://www.npmjs.com/package/kaelum)
268
- - [Documentation](https://matheuscampagnolo.github.io/kaelum/)
254
+ <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>
269
255
 
270
256
  ---
271
257
 
272
- ## 🧾 License
258
+ ## 📝 License
273
259
 
274
260
  MIT — see [LICENSE](LICENSE).
275
-
276
- ---
277
-
278
- ## ✍️ Notes for maintainers
279
-
280
- - Templates use `commonjs` (`require` / `module.exports`).
281
- - Update template dependencies to reference the correct Kaelum version when releasing new npm versions.
package/SECURITY.md ADDED
@@ -0,0 +1,42 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |---------|-----------|
7
+ | 1.4.x | ✅ Active |
8
+ | < 1.4 | ❌ End of life |
9
+
10
+ ## Reporting a Vulnerability
11
+
12
+ If you discover a security vulnerability, please report it responsibly.
13
+
14
+ **Do NOT open a public GitHub issue for security vulnerabilities.**
15
+
16
+ Instead, please email us at: **campagno.matheus@gmail.com**
17
+
18
+ Include:
19
+
20
+ - A description of the vulnerability
21
+ - Steps to reproduce the issue
22
+ - Potential impact
23
+ - Suggested fix (if any)
24
+
25
+ ## Response Timeline
26
+
27
+ - **Acknowledgment**: Within 48 hours
28
+ - **Initial assessment**: Within 1 week
29
+ - **Fix & release**: Depending on severity, typically within 2 weeks
30
+
31
+ ## Disclosure Policy
32
+
33
+ - We will coordinate with you on disclosure timing
34
+ - We will credit reporters in the release notes (unless you prefer anonymity)
35
+ - We follow [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_disclosure) practices
36
+
37
+ ## Security Best Practices for Users
38
+
39
+ - Always use the latest version of Kaelum
40
+ - Keep your dependencies up to date (`npm audit`)
41
+ - Never expose `exposeStack: true` in production
42
+ - Use `helmet` via `setConfig({ helmet: true })` for HTTP security headers
package/cli/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  const { createProject } = require("./create");
3
3
  const argv = process.argv.slice(2);
4
4
 
@@ -22,4 +22,4 @@ app.useErrorHandler({ exposeStack: false });
22
22
 
23
23
  // start server
24
24
  const PORT = process.env.PORT || 4000;
25
- app.start(PORT);
25
+ app.start(PORT);
@@ -19,4 +19,4 @@
19
19
  "morgan": "^1.10.0"
20
20
  },
21
21
  "devDependencies": {}
22
- }
22
+ }
@@ -23,4 +23,4 @@ app.useErrorHandler({ exposeStack: false });
23
23
 
24
24
  // Start server (explicit port for template demo)
25
25
  const PORT = process.env.PORT || 3000;
26
- app.start(PORT);
26
+ app.start(PORT);
@@ -18,4 +18,4 @@
18
18
  "helmet": "^6.0.0"
19
19
  },
20
20
  "devDependencies": {}
21
- }
21
+ }
@@ -42,4 +42,4 @@
42
42
  </section>
43
43
  </main>
44
44
  </body>
45
- </html>
45
+ </html>
package/cli/utils.js CHANGED
@@ -55,4 +55,4 @@ async function copyTemplate(sourceDir, targetDir, projectName) {
55
55
  }
56
56
  }
57
57
 
58
- module.exports = { copyTemplate };
58
+ module.exports = { copyTemplate };
package/core/addRoute.js CHANGED
@@ -58,7 +58,6 @@ function wrapHandler(fn) {
58
58
  * @returns {string}
59
59
  */
60
60
  function joinPaths(basePath, key) {
61
- if (!basePath.endsWith("/")) basePath = basePath;
62
61
  // remove trailing slash from basePath (except if basePath === '/')
63
62
  if (basePath !== "/" && basePath.endsWith("/")) {
64
63
  basePath = basePath.slice(0, -1);
@@ -142,4 +141,4 @@ function addRoute(app, basePath, handlers = {}) {
142
141
  }
143
142
  }
144
143
 
145
- module.exports = addRoute;
144
+ module.exports = addRoute;
package/core/apiRoute.js CHANGED
@@ -132,4 +132,4 @@ function apiRoute(app, resource, handlers = {}) {
132
132
  );
133
133
  }
134
134
 
135
- module.exports = apiRoute;
135
+ module.exports = apiRoute;
@@ -111,18 +111,26 @@ function errorHandlerFactory(options = {}) {
111
111
  if (req && req.accepts && req.accepts("html") && !req.accepts("json")) {
112
112
  // simple HTML response for browsers preferring HTML
113
113
  const title = `Error ${status}`;
114
+ // sanitize to prevent XSS when injecting into HTML
115
+ const escapeHtml = (str) =>
116
+ String(str)
117
+ .replace(/&/g, "&amp;")
118
+ .replace(/</g, "&lt;")
119
+ .replace(/>/g, "&gt;")
120
+ .replace(/"/g, "&quot;");
121
+ const safeMessage = escapeHtml(payload.error.message);
122
+ const safeStack =
123
+ exposeStack && payload.error.stack
124
+ ? `<pre>${escapeHtml(payload.error.stack)}</pre>`
125
+ : "";
114
126
  const body = `
115
127
  <!doctype html>
116
128
  <html>
117
129
  <head><meta charset="utf-8"/><title>${title}</title></head>
118
130
  <body>
119
131
  <h1>${title}</h1>
120
- <p>${payload.error.message}</p>
121
- ${
122
- exposeStack && payload.error.stack
123
- ? `<pre>${payload.error.stack}</pre>`
124
- : ""
125
- }
132
+ <p>${safeMessage}</p>
133
+ ${safeStack}
126
134
  </body>
127
135
  </html>`;
128
136
  res.status(status).type("html").send(body);
@@ -136,4 +144,4 @@ function errorHandlerFactory(options = {}) {
136
144
 
137
145
  // Export both default and named to keep compatibility with different import styles
138
146
  module.exports = errorHandlerFactory;
139
- module.exports.errorHandler = errorHandlerFactory;
147
+ module.exports.errorHandler = errorHandlerFactory;
@@ -201,4 +201,4 @@ function registerHealth(app, opts = {}) {
201
201
  return handler;
202
202
  }
203
203
 
204
- module.exports = registerHealth;
204
+ module.exports = registerHealth;
package/core/redirect.js CHANGED
@@ -174,4 +174,4 @@ function redirect(app, fromOrMap, toOrStatus, maybeStatus) {
174
174
  return registered.length ? registered : null;
175
175
  }
176
176
 
177
- module.exports = redirect;
177
+ module.exports = redirect;
package/core/setConfig.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // - Keeps references to Kaelum-installed middleware so toggles (false) remove them.
6
6
 
7
7
  const path = require("path");
8
+ const { removeMiddlewareByFn } = require("./utils");
8
9
 
9
10
  function tryRequire(name) {
10
11
  try {
@@ -27,15 +28,7 @@ function persistConfig(app, options = {}) {
27
28
  return merged;
28
29
  }
29
30
 
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
- }
31
+ // removeMiddlewareByFn imported from ./utils.js
39
32
 
40
33
  /**
41
34
  * Remove static middleware previously installed by Kaelum (if any)
@@ -268,4 +261,4 @@ function setConfig(app, options = {}) {
268
261
  return app.locals.kaelumConfig;
269
262
  }
270
263
 
271
- module.exports = setConfig;
264
+ module.exports = setConfig;
@@ -187,4 +187,4 @@ setMiddleware.remove = function (app, path) {
187
187
  : [];
188
188
  };
189
189
 
190
- module.exports = setMiddleware;
190
+ module.exports = setMiddleware;
package/core/start.js CHANGED
@@ -112,4 +112,4 @@ function start(app, port, cb) {
112
112
  return server;
113
113
  }
114
114
 
115
- module.exports = start;
115
+ module.exports = start;
package/core/utils.js ADDED
@@ -0,0 +1,23 @@
1
+ // core/utils.js
2
+ // Shared utility functions used across Kaelum core modules.
3
+
4
+ /**
5
+ * Remove a middleware function reference from the Express internal router stack.
6
+ * Only removes layers whose handle matches the given function reference.
7
+ *
8
+ * @param {Object} app - Express app instance
9
+ * @param {Function} fn - middleware function reference to remove
10
+ */
11
+ function removeMiddlewareByFn(app, fn) {
12
+ if (
13
+ !app ||
14
+ !app._router ||
15
+ !Array.isArray(app._router.stack)
16
+ )
17
+ return;
18
+ app._router.stack = app._router.stack.filter(
19
+ (layer) => layer.handle !== fn
20
+ );
21
+ }
22
+
23
+ module.exports = { removeMiddlewareByFn };
package/createApp.js CHANGED
@@ -18,6 +18,7 @@ const coreSetConfig = require("./core/setConfig");
18
18
  const { errorHandler } = require("./core/errorHandler");
19
19
  const registerHealth = require("./core/healthCheck");
20
20
  const redirect = require("./core/redirect");
21
+ const { removeMiddlewareByFn } = require("./core/utils");
21
22
 
22
23
  function createApp() {
23
24
  const app = express();
@@ -99,18 +100,7 @@ function createApp() {
99
100
  // middleware utility helpers
100
101
  // ---------------------------
101
102
 
102
- // remove middleware by matching the function reference from the express internal stack
103
- function removeMiddlewareByFn(appInstance, fn) {
104
- if (
105
- !appInstance ||
106
- !appInstance._router ||
107
- !Array.isArray(appInstance._router.stack)
108
- )
109
- return;
110
- appInstance._router.stack = appInstance._router.stack.filter(
111
- (layer) => layer.handle !== fn
112
- );
113
- }
103
+ // removeMiddlewareByFn imported from core/utils.js
114
104
 
115
105
  // ---------------------------
116
106
  // bind existing core helpers to the app
@@ -182,4 +172,4 @@ function createApp() {
182
172
  return app;
183
173
  }
184
174
 
185
- module.exports = createApp;
175
+ module.exports = createApp;
@@ -0,0 +1,43 @@
1
+ import js from "@eslint/js";
2
+ import prettier from "eslint-config-prettier";
3
+
4
+ export default [
5
+ js.configs.recommended,
6
+ prettier,
7
+ {
8
+ languageOptions: {
9
+ ecmaVersion: 2022,
10
+ sourceType: "commonjs",
11
+ globals: {
12
+ console: "readonly",
13
+ process: "readonly",
14
+ require: "readonly",
15
+ module: "readonly",
16
+ exports: "readonly",
17
+ __dirname: "readonly",
18
+ __filename: "readonly",
19
+ Buffer: "readonly",
20
+ setImmediate: "readonly",
21
+ setTimeout: "readonly",
22
+ clearTimeout: "readonly",
23
+ setInterval: "readonly",
24
+ clearInterval: "readonly",
25
+ },
26
+ },
27
+ rules: {
28
+ "no-unused-vars": ["warn", { argsIgnorePattern: "^_|next" }],
29
+ "no-console": "off",
30
+ "prefer-const": "warn",
31
+ },
32
+ },
33
+ {
34
+ ignores: [
35
+ "node_modules/",
36
+ "docs/",
37
+ "coverage/",
38
+ "cli/templates/",
39
+ "*.config.js",
40
+ "*.config.mjs",
41
+ ],
42
+ },
43
+ ];
package/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  const createApp = require("./createApp");
2
- module.exports = createApp;
2
+ module.exports = createApp;
package/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  import createApp from './index.js';
2
- export default createApp;
2
+ export default createApp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaelum",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
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": {
@@ -13,7 +13,15 @@
13
13
  "kaelum": "cli/index.js"
14
14
  },
15
15
  "scripts": {
16
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --verbose"
16
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --verbose",
17
+ "lint": "eslint .",
18
+ "format": "prettier --write .",
19
+ "release": "standard-version",
20
+ "changelog": "standard-version --skip.bump --skip.tag --skip.commit"
21
+ },
22
+ "funding": {
23
+ "type": "ko-fi",
24
+ "url": "https://ko-fi.com/matheusmessias"
17
25
  },
18
26
  "keywords": [
19
27
  "framework",
@@ -28,6 +36,14 @@
28
36
  ],
29
37
  "author": "Matheus Campagnolo",
30
38
  "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/kaelumjs/kaelum.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/kaelumjs/kaelum/issues"
45
+ },
46
+ "homepage": "https://github.com/kaelumjs/kaelum#readme",
31
47
  "dependencies": {
32
48
  "cors": "^2.8.5",
33
49
  "dotenv": "^17.2.3",
@@ -39,7 +55,11 @@
39
55
  "morgan": "^1.10.1"
40
56
  },
41
57
  "devDependencies": {
58
+ "eslint": "^10.0.2",
59
+ "eslint-config-prettier": "^10.1.8",
42
60
  "jest": "^30.2.0",
61
+ "prettier": "^3.8.1",
62
+ "standard-version": "^9.5.0",
43
63
  "supertest": "^7.2.2"
44
64
  }
45
65
  }