skyguard-js 1.2.0 → 1.2.2
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 +9 -462
- package/dist/app.d.ts +34 -10
- package/dist/app.js +59 -27
- package/dist/crypto/hasher.js +2 -1
- package/dist/crypto/jwt.js +2 -1
- package/dist/http/context.d.ts +115 -0
- package/dist/http/context.js +147 -0
- package/dist/http/httpAdapter.d.ts +4 -4
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +3 -1
- package/dist/http/logger.d.ts +10 -1
- package/dist/http/logger.js +44 -8
- package/dist/http/nodeNativeHttp.d.ts +6 -5
- package/dist/http/nodeNativeHttp.js +13 -6
- package/dist/http/request.d.ts +4 -0
- package/dist/http/request.js +12 -4
- package/dist/http/response.d.ts +21 -2
- package/dist/http/response.js +30 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -2
- package/dist/middlewares/cors.d.ts +10 -4
- package/dist/middlewares/cors.js +35 -18
- package/dist/middlewares/csrf.js +33 -33
- package/dist/middlewares/index.d.ts +1 -1
- package/dist/middlewares/rateLimiter.d.ts +58 -6
- package/dist/middlewares/rateLimiter.js +149 -40
- package/dist/middlewares/session.js +4 -4
- package/dist/routing/routeResolveFunc.d.ts +10 -0
- package/dist/routing/routeResolveFunc.js +21 -0
- package/dist/routing/router.d.ts +16 -10
- package/dist/routing/router.js +32 -25
- package/dist/routing/routerGroup.d.ts +10 -5
- package/dist/routing/routerGroup.js +11 -10
- package/dist/sessions/databaseSessionStorage.d.ts +52 -0
- package/dist/sessions/databaseSessionStorage.js +166 -0
- package/dist/sessions/fileSessionStorage.js +1 -1
- package/dist/sessions/index.d.ts +1 -0
- package/dist/sessions/index.js +3 -1
- package/dist/sessions/memorySessionStorage.js +1 -1
- package/dist/storage/storage.d.ts +3 -3
- package/dist/storage/storage.js +7 -7
- package/dist/storage/types.d.ts +5 -5
- package/dist/storage/uploader.d.ts +9 -9
- package/dist/storage/uploader.js +62 -62
- package/dist/types/index.d.ts +11 -10
- package/dist/validators/rules/bigIntRule.d.ts +0 -6
- package/dist/validators/rules/bigIntRule.js +0 -24
- package/dist/validators/validationRule.js +1 -1
- package/dist/validators/validationSchema.js +8 -8
- package/package.json +2 -2
- package/dist/helpers/http.d.ts +0 -95
- package/dist/helpers/http.js +0 -112
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Skyguard.js currently delivers a solid core that includes **routing**, **type-sa
|
|
|
31
31
|
- HTTP routing by method (GET, POST, PUT, PATCH, DELETE)
|
|
32
32
|
- Route groups with prefixes
|
|
33
33
|
- Global, group, and route-level middlewares
|
|
34
|
-
-
|
|
34
|
+
- Unified `Context` abstraction (`ctx.req` + response helpers)
|
|
35
35
|
- Declarative data validation
|
|
36
36
|
- Support for template motors (handlebars, pugs, ejs, etc.)
|
|
37
37
|
- Built-in HTTP exceptions
|
|
@@ -73,479 +73,22 @@ npm install skyguard-js
|
|
|
73
73
|
## 🏁 Quick Start
|
|
74
74
|
|
|
75
75
|
```ts
|
|
76
|
-
import { createApp
|
|
76
|
+
import { createApp } from "skyguard-js";
|
|
77
77
|
|
|
78
78
|
const app = createApp();
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
app.get("/", ctx => ctx.json({ status: "ok" }));
|
|
81
81
|
|
|
82
|
-
app.
|
|
83
|
-
return Response.json({ status: "ok" });
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
app.run(PORT, () => {
|
|
87
|
-
console.log(`Server running in port: http://localhost:${PORT}`);
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 🛣️ Routing
|
|
94
|
-
|
|
95
|
-
Routes are registered using HTTP methods on the `app` instance.
|
|
96
|
-
|
|
97
|
-
```ts
|
|
98
|
-
app.get("/posts/{id}", (request: Request) => {
|
|
99
|
-
return Response.json(request.params);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
app.post("/posts", (request: Request) => {
|
|
103
|
-
return Response.json(request.data);
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Internally, the framework maps HTTP methods to route layers using an optimized routing table.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## 🧩 Route Groups
|
|
112
|
-
|
|
113
|
-
Route groups allow you to organize endpoints under a shared prefix.
|
|
114
|
-
|
|
115
|
-
```ts
|
|
116
|
-
app.group("/api", api => {
|
|
117
|
-
api.get("/users", () => res.json({ message: "Users" }));
|
|
118
|
-
api.get("/products", () => res.json({ message: "Products" }));
|
|
119
|
-
});
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## 🛠️ Middlewares
|
|
125
|
-
|
|
126
|
-
Middlewares can be registered **globally**, **per group**, or **per route**.
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
import { Request, Response, json, RouteHandler } from "skyguard-js";
|
|
130
|
-
|
|
131
|
-
const authMiddleware = async (
|
|
132
|
-
request: Request,
|
|
133
|
-
next: RouteHandler,
|
|
134
|
-
): Promise<Response> => {
|
|
135
|
-
if (request.headers["authorization"] !== "secret") {
|
|
136
|
-
return json({ message: "Unauthorized" }).setStatus(401);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return next(request);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
// Global middleware
|
|
143
|
-
app.middlewares(authMiddleware);
|
|
144
|
-
|
|
145
|
-
// Group middleware
|
|
146
|
-
app.group("/admin", admin => {
|
|
147
|
-
admin.middlewares(authMiddleware);
|
|
148
|
-
admin.get("/dashboard", () => json({ ok: true }));
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Route-level middleware
|
|
152
|
-
app.get("/secure", () => json({ secure: true }), [authMiddleware]);
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 🌐 CORS Middleware
|
|
158
|
-
|
|
159
|
-
To enable CORS, use the built-in `cors` middleware.
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
import { cors, HttpMethods } from "skyguard-js";
|
|
163
|
-
|
|
164
|
-
app.middlewares(
|
|
165
|
-
cors({
|
|
166
|
-
origin: ["http://localhost:3000", "https://myapp.com"],
|
|
167
|
-
methods: [HttpMethods.get, HttpMethods.post],
|
|
168
|
-
allowedHeaders: ["Content-Type", "Authorization"],
|
|
169
|
-
credentials: true,
|
|
170
|
-
}),
|
|
171
|
-
);
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## 🛡️ CSRF Middleware
|
|
177
|
-
|
|
178
|
-
Use the built-in `csrf` middleware to protect endpoints against CSRF attacks.
|
|
179
|
-
|
|
180
|
-
```ts
|
|
181
|
-
import { csrf, json } from "skyguard-js";
|
|
182
|
-
|
|
183
|
-
app.middlewares(
|
|
184
|
-
csrf({
|
|
185
|
-
cookieName: "XSRF-TOKEN",
|
|
186
|
-
headerNames: ["x-csrf-token"],
|
|
187
|
-
}),
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
app.post("/transfer", () => {
|
|
191
|
-
return json({ ok: true });
|
|
192
|
-
});
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
The middleware follows a hardened **double-submit cookie** strategy:
|
|
196
|
-
|
|
197
|
-
- It issues a CSRF cookie when missing (including first GET/HEAD/OPTIONS and failed protected requests).
|
|
198
|
-
- For state-changing requests (POST/PUT/PATCH/DELETE), it validates the token from header/body against the cookie value.
|
|
199
|
-
- It validates `Origin`/`Referer` for protected requests (and requires `Referer` on HTTPS when `Origin` is missing).
|
|
200
|
-
- It rejects duplicated CSRF header values to avoid ambiguous token parsing.
|
|
201
|
-
|
|
202
|
-
### Example: CSRF token in HTML templates (Express Handlebars)
|
|
203
|
-
|
|
204
|
-
When you render server-side HTML, you can pass the CSRF token to your template and include it as a hidden field in forms.
|
|
205
|
-
|
|
206
|
-
```ts
|
|
207
|
-
import { createApp, csrf, render, json } from "skyguard-js";
|
|
208
|
-
import { engine } from "express-handlebars";
|
|
209
|
-
import { join } from "node:path";
|
|
210
|
-
|
|
211
|
-
const app = createApp();
|
|
212
|
-
|
|
213
|
-
app.views(__dirname, "views");
|
|
214
|
-
app.engineTemplates(
|
|
215
|
-
"hbs",
|
|
216
|
-
engine({
|
|
217
|
-
extname: "hbs",
|
|
218
|
-
layoutsDir: join(__dirname, "views"),
|
|
219
|
-
defaultLayout: "main",
|
|
220
|
-
}),
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
app.middlewares(
|
|
224
|
-
csrf({
|
|
225
|
-
cookieName: "XSRF-TOKEN",
|
|
226
|
-
headerNames: ["x-csrf-token"],
|
|
227
|
-
}),
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
app.get("/transfer", request => {
|
|
231
|
-
return render("transfer", {
|
|
232
|
-
csrfToken: request.cookies["XSRF-TOKEN"],
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
app.post("/transfer", request => {
|
|
237
|
-
// If middleware passes, token is valid
|
|
238
|
-
return json({ ok: true, amount: request.body.amount });
|
|
239
|
-
});
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
`views/transfer.hbs`:
|
|
243
|
-
|
|
244
|
-
```hbs
|
|
245
|
-
<form action="/transfer" method="POST">
|
|
246
|
-
<input type="hidden" name="csrf" value="{{csrfToken}}" />
|
|
247
|
-
<input type="number" name="amount" />
|
|
248
|
-
<button type="submit">Send</button>
|
|
249
|
-
</form>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
For `fetch`/AJAX requests, send the same token in headers:
|
|
253
|
-
|
|
254
|
-
```html
|
|
255
|
-
<script>
|
|
256
|
-
const csrfToken = "{{csrfToken}}";
|
|
257
|
-
|
|
258
|
-
async function sendTransfer() {
|
|
259
|
-
await fetch("/transfer", {
|
|
260
|
-
method: "POST",
|
|
261
|
-
headers: {
|
|
262
|
-
"Content-Type": "application/json",
|
|
263
|
-
"x-csrf-token": csrfToken,
|
|
264
|
-
},
|
|
265
|
-
body: JSON.stringify({ amount: 150 }),
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
</script>
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
## 🚦 Rate Limit Middleware
|
|
274
|
-
|
|
275
|
-
You can limit requests with the built-in `rateLimit` middleware.
|
|
276
|
-
|
|
277
|
-
```ts
|
|
278
|
-
import { rateLimit, Response } from "skyguard-js";
|
|
279
|
-
|
|
280
|
-
const apiRateLimit = rateLimit({
|
|
281
|
-
windowMs: 60_000, // 1 minute
|
|
282
|
-
max: 100,
|
|
283
|
-
message: "Too many requests from this IP",
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
app.get(
|
|
287
|
-
"/api/users",
|
|
288
|
-
() => {
|
|
289
|
-
return Response.json([{ id: 1 }]);
|
|
290
|
-
},
|
|
291
|
-
[apiRateLimit],
|
|
292
|
-
);
|
|
82
|
+
app.run();
|
|
293
83
|
```
|
|
294
84
|
|
|
295
85
|
---
|
|
296
86
|
|
|
297
|
-
## 📌 Static Files
|
|
298
|
-
|
|
299
|
-
To serve static files, use the application's `staticFiles` method with the directory path. The name of the folder will determine the initial route prefix.
|
|
300
|
-
|
|
301
|
-
```ts
|
|
302
|
-
import { join } from "node:path";
|
|
303
|
-
|
|
304
|
-
app.staticFiles(join(__dirname, "..", "static"));
|
|
305
|
-
|
|
306
|
-
// Route http://localhost:3000/static/style.css will serve the file located at ./static/style.css
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
---
|
|
310
|
-
|
|
311
|
-
## ⛔ Data Validation
|
|
312
|
-
|
|
313
|
-
To validate the data in the body of client requests, the framework provides the creation of validation schemes and a middleware function to validate the body of HTTP requests, used as follows:
|
|
314
|
-
|
|
315
|
-
```ts
|
|
316
|
-
import { v, schema, validateRequest, json } from "skyguard-js";
|
|
317
|
-
|
|
318
|
-
// Created Schema
|
|
319
|
-
const userSchema = schema({
|
|
320
|
-
body: {
|
|
321
|
-
name: v.string({ maxLength: 60 }),
|
|
322
|
-
email: v.email(),
|
|
323
|
-
age: v.number({ min: 18 }),
|
|
324
|
-
active: v.boolean().default(false),
|
|
325
|
-
birthdate: v.date({ max: new Date() }),
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
app.post(
|
|
330
|
-
"/test",
|
|
331
|
-
(request: Request) => {
|
|
332
|
-
const data = request.body;
|
|
333
|
-
return json(data).setStatusCode(201);
|
|
334
|
-
},
|
|
335
|
-
[validateRequest(userSchema)],
|
|
336
|
-
);
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
To type the request body, an interface is used and the .getData() method is used, which allows returning the typed bodym. By default each property you define in the schema is required, to define it optional you use the `.optional()` or `.default(value)` function
|
|
340
|
-
|
|
341
|
-
Validation is:
|
|
342
|
-
|
|
343
|
-
- Fail-fast per field
|
|
344
|
-
- Fully typed
|
|
345
|
-
- Reusable
|
|
346
|
-
- Decoupled from transport layer
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
## 🚨 Exceptions & Error Handling
|
|
351
|
-
|
|
352
|
-
The framework provides a set of built-in HTTP exceptions that can be thrown from route handlers or middleware. When an exception is thrown, the framework detects it and sends an appropriate HTTP response with the status code and message you specified in the class.
|
|
353
|
-
|
|
354
|
-
```ts
|
|
355
|
-
import { NotFoundError, InternalServerError, json } from "skyguard-js";
|
|
356
|
-
|
|
357
|
-
const listResources = ["1", "2", "3"];
|
|
358
|
-
|
|
359
|
-
app.get("/resource/{id}", (request: Request) => {
|
|
360
|
-
const resource = request.params["id"];
|
|
361
|
-
|
|
362
|
-
if (!listResources.includes(resource)) {
|
|
363
|
-
throw new NotFoundError("Resource not found");
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return json(resource);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
app.get("/divide", (request: Request) => {
|
|
370
|
-
try {
|
|
371
|
-
const { a, b } = request.query;
|
|
372
|
-
const result = Number(a) / Number(b);
|
|
373
|
-
|
|
374
|
-
return json({ result });
|
|
375
|
-
} catch (error) {
|
|
376
|
-
throw new InternalServerError(
|
|
377
|
-
"An error occurred while processing your request",
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
---
|
|
384
|
-
|
|
385
|
-
## 🧱 Sessions
|
|
386
|
-
|
|
387
|
-
To handle sessions, you must use the framework’s built-in middleware. Depending on where you want to store them (in memory, in files, or in a database), you need to use the corresponding storage class.
|
|
388
|
-
|
|
389
|
-
```ts
|
|
390
|
-
import { sessions, FileSessionStorage, json } from "skyguard-js";
|
|
391
|
-
|
|
392
|
-
app.middlewares(
|
|
393
|
-
sessions(FileSessionStorage, {
|
|
394
|
-
name: "connect.sid",
|
|
395
|
-
rolling: true,
|
|
396
|
-
saveUninitialized: false,
|
|
397
|
-
cookie: {
|
|
398
|
-
maxAge: 60 * 60 * 24,
|
|
399
|
-
httpOnly: true,
|
|
400
|
-
sameSite: "Lax",
|
|
401
|
-
secure: false,
|
|
402
|
-
path: "/",
|
|
403
|
-
},
|
|
404
|
-
}),
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
app.post("/login", (request: Request) => {
|
|
408
|
-
const { username, password } = request.data;
|
|
409
|
-
|
|
410
|
-
if (username === "admin" && password === "secret") {
|
|
411
|
-
request.session.set("user", {
|
|
412
|
-
id: 1,
|
|
413
|
-
username: "admin",
|
|
414
|
-
role: "admin",
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
return json({ message: "Logged in" });
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
throw new UnauthorizedError("Invalid credentials");
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
app.get("/me", (request: Request) => {
|
|
424
|
-
const user = request.session.get("user");
|
|
425
|
-
|
|
426
|
-
if (!user) throw new UnauthorizedError("Not authenticated");
|
|
427
|
-
return json({ user });
|
|
428
|
-
});
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
## 🛡️ Security
|
|
434
|
-
|
|
435
|
-
The framework includes some password hashing and JWT token generation functions, and also includes JWT authentication middleware.
|
|
436
|
-
|
|
437
|
-
```ts
|
|
438
|
-
import { Hasher, JWT, json } from "skyguard-js";
|
|
439
|
-
|
|
440
|
-
app.post("/register", async (request: Request) => {
|
|
441
|
-
const { username, password } = request.data;
|
|
442
|
-
const hashedPassword = await Hasher.hash(password);
|
|
443
|
-
|
|
444
|
-
// Save username and hashedPassword to database
|
|
445
|
-
// ...
|
|
446
|
-
|
|
447
|
-
return json({ message: "User registered" });
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
app.post("/login", async (request: Request) => {
|
|
451
|
-
const { username, password } = request.data;
|
|
452
|
-
|
|
453
|
-
// Retrieve user from database by username
|
|
454
|
-
// ...
|
|
455
|
-
|
|
456
|
-
const isValid = await Hasher.verify(password, user.hashedPassword);
|
|
457
|
-
|
|
458
|
-
if (!isValid) {
|
|
459
|
-
throw new UnauthorizedError("Invalid credentials");
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
const token = JWT.create({ sub: "123" }, "secret-key", {
|
|
463
|
-
algorithm: "HS256",
|
|
464
|
-
expiresIn: "1h",
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
return json({ token });
|
|
468
|
-
});
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
---
|
|
472
|
-
|
|
473
|
-
## 📂 File Uploads
|
|
474
|
-
|
|
475
|
-
To handle file uploads, use the built-in `createUploader` function to create an uploader middleware with the desired storage configuration.
|
|
476
|
-
|
|
477
|
-
```ts
|
|
478
|
-
import { createUploader, StorageType, json } from "skyguard-js";
|
|
479
|
-
|
|
480
|
-
const uploader = createUploader({
|
|
481
|
-
storageType: StorageType.DISK,
|
|
482
|
-
storageOptions: {
|
|
483
|
-
disk: {
|
|
484
|
-
destination: "./uploads",
|
|
485
|
-
},
|
|
486
|
-
},
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
app.post(
|
|
490
|
-
"/upload",
|
|
491
|
-
(request: Request) => {
|
|
492
|
-
return json({
|
|
493
|
-
message: "File uploaded successfully",
|
|
494
|
-
file: request.file,
|
|
495
|
-
});
|
|
496
|
-
},
|
|
497
|
-
[uploader.single("file")],
|
|
498
|
-
);
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
Depending on the `Storage Type` you have selected, the storage options will contain two properties: `disk` and `memory`
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## 📄 Views & Template Engine
|
|
506
|
-
|
|
507
|
-
To render views, you must first set up the template engine using the `engineTemplates` method of the `app`, set the view path with the `views` method of the `app`, and then you can use the `render` method within your handlers to render the views with the data you want to pass.
|
|
508
|
-
|
|
509
|
-
```ts
|
|
510
|
-
import { engine } from "express-handlebars";
|
|
511
|
-
import ejs from "ejs";
|
|
512
|
-
import { join } from "node:path";
|
|
513
|
-
import { render } from "skyguard-js";
|
|
514
|
-
|
|
515
|
-
app.views(__dirname, "views");
|
|
516
|
-
|
|
517
|
-
// Config for Express Handlebars
|
|
518
|
-
app.engineTemplates(
|
|
519
|
-
"hbs",
|
|
520
|
-
engine({
|
|
521
|
-
extname: "hbs",
|
|
522
|
-
layoutsDir: join(__dirname, "views"),
|
|
523
|
-
defaultLayout: "main",
|
|
524
|
-
}),
|
|
525
|
-
);
|
|
526
|
-
|
|
527
|
-
// Config for EJS
|
|
528
|
-
app.engineTemplates("ejs", (templatePath, data) => {
|
|
529
|
-
return ejs.renderFile(templatePath, data);
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
app.get("/home", () => {
|
|
533
|
-
return render("index", {
|
|
534
|
-
title: "Home Page",
|
|
535
|
-
message: "Welcome to the home page!",
|
|
536
|
-
});
|
|
537
|
-
});
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
Currently, it works with third-party template engines such as **Express Handlebars**, **Pug**, and **EJS**, but the idea is to implement its own template engine in the future.
|
|
541
|
-
|
|
542
|
-
---
|
|
543
|
-
|
|
544
87
|
## 🔮 Roadmap (Tentative)
|
|
545
88
|
|
|
546
89
|
- Middleware system (✅)
|
|
547
90
|
- Template engines supported (✅)
|
|
548
|
-
-
|
|
91
|
+
- Context abstraction (✅)
|
|
549
92
|
- Data validation (✅)
|
|
550
93
|
- Error handling improvements (✅)
|
|
551
94
|
- Sessions & cookies (✅)
|
|
@@ -554,3 +97,7 @@ Currently, it works with third-party template engines such as **Express Handleba
|
|
|
554
97
|
- Database & ORM integration
|
|
555
98
|
- Authentication & authorization
|
|
556
99
|
- WebSockets
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|
package/dist/app.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RouterGroup } from "./routing";
|
|
2
|
+
import { type LogFormat } from "./http";
|
|
2
3
|
import type { Middleware, RouteHandler } from "./types";
|
|
3
4
|
import { type TemplateEngineFunction } from "./views/engineTemplate";
|
|
4
5
|
/**
|
|
@@ -19,13 +20,15 @@ import { type TemplateEngineFunction } from "./views/engineTemplate";
|
|
|
19
20
|
* from the runtime platform (Node, Bun, Deno, etc.)
|
|
20
21
|
* through {@link HttpAdapter} and {@link Server}.
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
+
declare class App {
|
|
23
24
|
/** Main routing system */
|
|
24
25
|
private router;
|
|
25
26
|
/** Static file handler (optional) */
|
|
26
27
|
private staticFileHandler;
|
|
27
28
|
/** View engine for rendering templates (optional) */
|
|
28
29
|
private viewEngine;
|
|
30
|
+
/** Logger configuration */
|
|
31
|
+
private loggerOptions;
|
|
29
32
|
/**
|
|
30
33
|
* Bootstraps and configures the application.
|
|
31
34
|
*
|
|
@@ -106,7 +109,22 @@ export declare class App {
|
|
|
106
109
|
*
|
|
107
110
|
* @param port - TCP port to listen on
|
|
108
111
|
*/
|
|
109
|
-
run(port
|
|
112
|
+
run(port?: number, callback?: VoidFunction, hostname?: string): void;
|
|
113
|
+
/**
|
|
114
|
+
* Configures HTTP request logger output format and optional file output.
|
|
115
|
+
*
|
|
116
|
+
* Supported formats are inspired by morgan:
|
|
117
|
+
* - "combined"
|
|
118
|
+
* - "common"
|
|
119
|
+
* - "dev"
|
|
120
|
+
* - "short"
|
|
121
|
+
* - "tiny"
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* app.logger("common");
|
|
125
|
+
* app.logger("combined", "./logs/http.log");
|
|
126
|
+
*/
|
|
127
|
+
logger(format?: LogFormat, filePath?: string): void;
|
|
110
128
|
/**
|
|
111
129
|
* Sets a global prefix for all routes.
|
|
112
130
|
*
|
|
@@ -118,24 +136,29 @@ export declare class App {
|
|
|
118
136
|
*/
|
|
119
137
|
setPrefix(prefix: string): void;
|
|
120
138
|
/** Registers a GET route */
|
|
121
|
-
get(path: string, action: RouteHandler
|
|
139
|
+
get(path: string, action: RouteHandler): void;
|
|
140
|
+
get(path: string, middlewares: Middleware[], action: RouteHandler): void;
|
|
122
141
|
/** Registers a POST route */
|
|
123
|
-
post(path: string, action: RouteHandler
|
|
142
|
+
post(path: string, action: RouteHandler): void;
|
|
143
|
+
post(path: string, middlewares: Middleware[], action: RouteHandler): void;
|
|
124
144
|
/** Registers a PUT route */
|
|
125
|
-
put(path: string, action: RouteHandler
|
|
145
|
+
put(path: string, action: RouteHandler): void;
|
|
146
|
+
put(path: string, middlewares: Middleware[], action: RouteHandler): void;
|
|
126
147
|
/** Registers a PATCH route */
|
|
127
|
-
patch(path: string, action: RouteHandler
|
|
148
|
+
patch(path: string, action: RouteHandler): void;
|
|
149
|
+
patch(path: string, middlewares: Middleware[], action: RouteHandler): void;
|
|
128
150
|
/** Registers a DELETE route */
|
|
129
|
-
delete(path: string, action: RouteHandler
|
|
151
|
+
delete(path: string, action: RouteHandler): void;
|
|
152
|
+
delete(path: string, middlewares: Middleware[], action: RouteHandler): void;
|
|
130
153
|
/**
|
|
131
154
|
* Registers global middlewares.
|
|
132
155
|
*
|
|
133
156
|
* These are executed for every route.
|
|
134
157
|
*
|
|
135
158
|
* @example
|
|
136
|
-
* const auth = async (
|
|
137
|
-
* console.log(
|
|
138
|
-
* return await next(
|
|
159
|
+
* const auth = async (context, next) => {
|
|
160
|
+
* console.log(context.headers);
|
|
161
|
+
* return await next(context);
|
|
139
162
|
* }
|
|
140
163
|
*
|
|
141
164
|
* app.middlewares(auth);
|
|
@@ -159,3 +182,4 @@ export declare class App {
|
|
|
159
182
|
private handleError;
|
|
160
183
|
}
|
|
161
184
|
export declare const createApp: () => App;
|
|
185
|
+
export {};
|