kaelum 1.4.4 → 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.
- package/.prettierignore +5 -0
- package/.prettierrc +7 -0
- package/CODE_OF_CONDUCT.md +57 -0
- package/CONTRIBUTING.md +79 -0
- package/README.md +166 -187
- package/SECURITY.md +42 -0
- package/core/addRoute.js +0 -1
- package/core/errorHandler.js +14 -6
- package/core/setConfig.js +2 -9
- package/core/utils.js +23 -0
- package/createApp.js +2 -12
- package/eslint.config.mjs +43 -0
- package/package.json +10 -1
package/.prettierignore
ADDED
package/.prettierrc
ADDED
|
@@ -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).
|
package/CONTRIBUTING.md
ADDED
|
@@ -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
|
-
|
|
6
|
-
[](https://github.com/kaelumjs/kaelum/actions)
|
|
7
|
-
[](LICENSE)
|
|
8
|
-
[](https://matheuscampagnolo.github.io/kaelum/)
|
|
7
|
+
<p><strong>Fast, minimalist Node.js framework for web apps & REST APIs</strong></p>
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/kaelum)
|
|
10
|
+
[](https://www.npmjs.com/package/kaelum)
|
|
11
|
+
[](https://github.com/kaelumjs/kaelum/actions)
|
|
12
|
+
[](LICENSE)
|
|
12
13
|
|
|
13
|
-
|
|
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
|
-
|
|
16
|
+
</div>
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
---
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
## Why Kaelum?
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
<table>
|
|
23
|
+
<tr>
|
|
24
|
+
<td width="50%">
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
**Without Kaelum (raw Express)**
|
|
24
27
|
|
|
25
|
-
```
|
|
26
|
-
|
|
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
|
-
|
|
51
|
+
</td>
|
|
52
|
+
<td width="50%">
|
|
30
53
|
|
|
31
|
-
|
|
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
|
-
|
|
56
|
+
```js
|
|
57
|
+
const kaelum = require("kaelum");
|
|
58
|
+
const app = kaelum();
|
|
38
59
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
>
|
|
76
|
+
</td>
|
|
77
|
+
</tr>
|
|
78
|
+
</table>
|
|
79
|
+
|
|
80
|
+
> **Less boilerplate. Same Express power. Better DX.**
|
|
46
81
|
|
|
47
82
|
---
|
|
48
83
|
|
|
49
|
-
##
|
|
84
|
+
## ⚡ Quick Start
|
|
50
85
|
|
|
51
|
-
|
|
52
|
-
|
|
86
|
+
```bash
|
|
87
|
+
# Scaffold a new project
|
|
88
|
+
npx kaelum create my-app --template web
|
|
53
89
|
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
93
|
+
# Run it
|
|
94
|
+
cd my-app && npm install && npm start
|
|
95
|
+
```
|
|
61
96
|
|
|
62
|
-
|
|
97
|
+
> No global install needed — `npx` handles everything.
|
|
63
98
|
|
|
64
99
|
---
|
|
65
100
|
|
|
66
|
-
##
|
|
101
|
+
## ✨ Features
|
|
67
102
|
|
|
68
|
-
|
|
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
|
-
|
|
117
|
+
## 📦 Installation
|
|
86
118
|
|
|
119
|
+
```bash
|
|
120
|
+
npm install kaelum
|
|
87
121
|
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
## 🧩
|
|
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,
|
|
121
|
-
helmet: true,
|
|
122
|
-
static: "public",
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
port: 3000,
|
|
126
|
-
views: { 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
|
-
|
|
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.
|
|
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.
|
|
151
|
-
get:
|
|
152
|
-
post:
|
|
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:
|
|
161
|
-
put:
|
|
162
|
-
delete:
|
|
163
|
-
"/
|
|
164
|
-
get:
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
### `app.setMiddleware(...)`
|
|
175
|
-
|
|
176
|
-
Flexible helper to register middleware(s):
|
|
182
|
+
### Other Helpers
|
|
177
183
|
|
|
178
184
|
```js
|
|
179
|
-
//
|
|
180
|
-
app.setMiddleware(
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
app.
|
|
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
|
-
|
|
194
|
+
## 📁 Project Templates
|
|
192
195
|
|
|
193
|
-
|
|
196
|
+
### Web Template
|
|
194
197
|
|
|
195
|
-
```
|
|
196
|
-
app
|
|
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
|
-
|
|
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
|
-
## 🧪
|
|
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
|
-
##
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
git clone https://github.com/kaelumjs/kaelum.git
|
|
235
|
-
cd kaelum
|
|
236
|
-
npm install
|
|
237
|
-
npm link
|
|
238
|
-
```
|
|
232
|
+
## 🤝 Contributing
|
|
239
233
|
|
|
240
|
-
|
|
234
|
+
We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a PR.
|
|
241
235
|
|
|
242
|
-
|
|
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
|
-
##
|
|
240
|
+
## 🌐 Ecosystem
|
|
249
241
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
252
|
+
If Kaelum helps you, consider supporting its development:
|
|
265
253
|
|
|
266
|
-
-
|
|
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
|
-
##
|
|
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/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);
|
package/core/errorHandler.js
CHANGED
|
@@ -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, "&")
|
|
118
|
+
.replace(/</g, "<")
|
|
119
|
+
.replace(/>/g, ">")
|
|
120
|
+
.replace(/"/g, """);
|
|
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>${
|
|
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);
|
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)
|
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
|
-
//
|
|
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
|
|
@@ -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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaelum",
|
|
3
|
-
"version": "1.4.
|
|
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": {
|
|
@@ -14,9 +14,15 @@
|
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --verbose",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"format": "prettier --write .",
|
|
17
19
|
"release": "standard-version",
|
|
18
20
|
"changelog": "standard-version --skip.bump --skip.tag --skip.commit"
|
|
19
21
|
},
|
|
22
|
+
"funding": {
|
|
23
|
+
"type": "ko-fi",
|
|
24
|
+
"url": "https://ko-fi.com/matheusmessias"
|
|
25
|
+
},
|
|
20
26
|
"keywords": [
|
|
21
27
|
"framework",
|
|
22
28
|
"nodejs",
|
|
@@ -49,7 +55,10 @@
|
|
|
49
55
|
"morgan": "^1.10.1"
|
|
50
56
|
},
|
|
51
57
|
"devDependencies": {
|
|
58
|
+
"eslint": "^10.0.2",
|
|
59
|
+
"eslint-config-prettier": "^10.1.8",
|
|
52
60
|
"jest": "^30.2.0",
|
|
61
|
+
"prettier": "^3.8.1",
|
|
53
62
|
"standard-version": "^9.5.0",
|
|
54
63
|
"supertest": "^7.2.2"
|
|
55
64
|
}
|