lieko-express 0.0.20 → 1.0.1
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/LICENSE +21 -0
- package/README.md +387 -1
- package/lib/cors.js +0 -1
- package/lib/schema.js +4 -8
- package/lieko-express.js +48 -21
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 eiwSrvt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1 +1,387 @@
|
|
|
1
|
-
|
|
1
|
+
# Lieko Express
|
|
2
|
+
|
|
3
|
+
A modern, minimal, Express-like framework for Node.js with built-in body parsing, CORS, validation, and more. Lieko-express is designed to be a drop-in replacement for Express.js with additional features and better performance.
|
|
4
|
+
|
|
5
|
+
Online documentation
|
|
6
|
+
[Lieko Express Documentation](https://express.lieko.app/)
|
|
7
|
+
|
|
8
|
+
## Key Features
|
|
9
|
+
|
|
10
|
+
- **Express-compatible API**: Familiar routing, middleware, and request/response handling.
|
|
11
|
+
- **Built-in Body Parsing**: JSON, URL-encoded, and multipart form-data support.
|
|
12
|
+
- **CORS Support**: Configurable cross-origin resource sharing with flexible options.
|
|
13
|
+
- **Schema Validation**: Built-in validation system with comprehensive validators.
|
|
14
|
+
- **Static File Serving**: Efficient static file middleware with caching and ETags.
|
|
15
|
+
- **Template Engine**: Simple HTML templating with support for custom engines.
|
|
16
|
+
- **Route Groups**: Organize routes with nested groups and shared middleware.
|
|
17
|
+
- **Debug Mode**: Detailed request logging with timing and payload information.
|
|
18
|
+
|
|
19
|
+
> **Note**: Lieko-express requires Node.js ≥14.0.0.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### NPM
|
|
24
|
+
```bash
|
|
25
|
+
npm install lieko-express
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Yarn
|
|
29
|
+
```bash
|
|
30
|
+
yarn add lieko-express
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
Create your first Lieko-express application:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const Lieko = require('lieko-express');
|
|
39
|
+
const app = Lieko();
|
|
40
|
+
|
|
41
|
+
app.get('/', (req, res) => {
|
|
42
|
+
res.json({ message: 'Hello World!' });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
app.listen(3000, () => {
|
|
46
|
+
console.log('Server running on http://localhost:3000');
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Basic REST API Example
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const Lieko = require('lieko-express');
|
|
54
|
+
const app = Lieko();
|
|
55
|
+
|
|
56
|
+
// Enable debug mode
|
|
57
|
+
app.debug(true);
|
|
58
|
+
|
|
59
|
+
// Simple in-memory database
|
|
60
|
+
const users = [];
|
|
61
|
+
let idCounter = 1;
|
|
62
|
+
|
|
63
|
+
// Get all users
|
|
64
|
+
app.get('/api/users', (req, res) => {
|
|
65
|
+
res.json(users);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Get user by ID
|
|
69
|
+
app.get('/api/users/:id', (req, res) => {
|
|
70
|
+
const user = users.find(u => u.id === req.params.id);
|
|
71
|
+
|
|
72
|
+
if (!user) {
|
|
73
|
+
return res.status(404).json({
|
|
74
|
+
error: 'User not found'
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
res.json(user);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Create user
|
|
82
|
+
app.post('/api/users', (req, res) => {
|
|
83
|
+
const user = {
|
|
84
|
+
id: String(idCounter++),
|
|
85
|
+
name: req.body.name,
|
|
86
|
+
email: req.body.email,
|
|
87
|
+
createdAt: new Date().toISOString()
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
users.push(user);
|
|
91
|
+
res.status(201).json(user);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Update user
|
|
95
|
+
app.patch('/api/users/:id', (req, res) => {
|
|
96
|
+
const user = users.find(u => u.id === req.params.id);
|
|
97
|
+
|
|
98
|
+
if (!user) {
|
|
99
|
+
return res.status(404).json({
|
|
100
|
+
error: 'User not found'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Object.assign(user, req.body);
|
|
105
|
+
res.json(user);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Delete user
|
|
109
|
+
app.delete('/api/users/:id', (req, res) => {
|
|
110
|
+
const index = users.findIndex(u => u.id === req.params.id);
|
|
111
|
+
|
|
112
|
+
if (index === -1) {
|
|
113
|
+
return res.status(404).json({
|
|
114
|
+
error: 'User not found'
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
users.splice(index, 1);
|
|
119
|
+
res.status(204).end();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
app.listen(3000, () => {
|
|
123
|
+
console.log('API running on http://localhost:3000');
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Configuration
|
|
128
|
+
|
|
129
|
+
Customize Lieko-express with settings:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
const app = Lieko();
|
|
133
|
+
|
|
134
|
+
// Enable/disable features
|
|
135
|
+
app.set('x-powered-by', 'MyApp');
|
|
136
|
+
app.set('trust proxy', true);
|
|
137
|
+
app.set('views', './templates');
|
|
138
|
+
app.set('view engine', 'html');
|
|
139
|
+
|
|
140
|
+
// Enable debug mode
|
|
141
|
+
app.debug(true);
|
|
142
|
+
|
|
143
|
+
// Disable strict trailing slash
|
|
144
|
+
app.set('strictTrailingSlash', false);
|
|
145
|
+
app.set('allowTrailingSlash', true);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Configuration Options
|
|
149
|
+
|
|
150
|
+
| Setting | Type | Default | Description |
|
|
151
|
+
|----------------------|---------------|---------------|---------------------------------|
|
|
152
|
+
| `debug` | boolean | false | Enable detailed request logging |
|
|
153
|
+
| `x-powered-by` | string\|boolean | 'lieko-express' | X-Powered-By header value |
|
|
154
|
+
| `trust proxy` | boolean | false | Trust X-Forwarded-* headers |
|
|
155
|
+
| `strictTrailingSlash` | boolean | true | Strict trailing slash matching |
|
|
156
|
+
| `allowTrailingSlash` | boolean | true | Allow optional trailing slash |
|
|
157
|
+
| `views` | string | './views' | Template directory path |
|
|
158
|
+
| `view engine` | string | 'html' | Default template engine |
|
|
159
|
+
|
|
160
|
+
## Routing
|
|
161
|
+
|
|
162
|
+
Define routes with flexible patterns:
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
// GET request
|
|
166
|
+
app.get('/users', (req, res) => {
|
|
167
|
+
res.json({ users: [] });
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// POST request
|
|
171
|
+
app.post('/users', (req, res) => {
|
|
172
|
+
res.status(201).json({ message: 'User created' });
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Route parameters
|
|
176
|
+
app.get('/users/:id', (req, res) => {
|
|
177
|
+
const userId = req.params.id;
|
|
178
|
+
res.json({ userId });
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Multiple handlers
|
|
182
|
+
app.get('/protected', authMiddleware, (req, res) => {
|
|
183
|
+
res.json({ message: 'Protected route' });
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Middleware
|
|
188
|
+
|
|
189
|
+
Middleware for request processing:
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
// Application-level
|
|
193
|
+
app.use((req, res, next) => {
|
|
194
|
+
console.log(`${req.method} ${req.url}`);
|
|
195
|
+
next();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Error handling
|
|
199
|
+
app.errorHandler((err, req, res, next) => {
|
|
200
|
+
console.error('Error:', err.message);
|
|
201
|
+
res.status(err.status || 500).json({
|
|
202
|
+
error: {
|
|
203
|
+
message: err.message,
|
|
204
|
+
code: err.code || 'SERVER_ERROR'
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Request Object
|
|
211
|
+
|
|
212
|
+
Properties and methods:
|
|
213
|
+
|
|
214
|
+
| Property | Type | Description |
|
|
215
|
+
|-------------------|---------|--------------------------------------|
|
|
216
|
+
| `req.body` | object | Parsed request body |
|
|
217
|
+
| `req.params` | object | Route parameters |
|
|
218
|
+
| `req.query` | object | Query string parameters |
|
|
219
|
+
| `req.files` | object | Uploaded files |
|
|
220
|
+
| `req.headers` | object | HTTP headers |
|
|
221
|
+
| `req.method` | string | HTTP method |
|
|
222
|
+
|
|
223
|
+
Methods like `req.get('Content-Type')`, `req.accepts(['json', 'html'])`.
|
|
224
|
+
|
|
225
|
+
## Response Object
|
|
226
|
+
|
|
227
|
+
Methods for sending responses:
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
// Send JSON
|
|
231
|
+
res.json({ message: 'Hello' });
|
|
232
|
+
|
|
233
|
+
// Status and helpers
|
|
234
|
+
res.status(201).json({ message: 'Created' });
|
|
235
|
+
res.ok({ data: users });
|
|
236
|
+
res.created({ user });
|
|
237
|
+
res.noContent();
|
|
238
|
+
res.badRequest('Invalid input');
|
|
239
|
+
res.redirect('/new-url');
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Body Parsing
|
|
243
|
+
|
|
244
|
+
Automatic parsing with limits:
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
app.bodyParser({
|
|
248
|
+
limit: '50mb',
|
|
249
|
+
extended: true,
|
|
250
|
+
strict: true
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## CORS
|
|
255
|
+
|
|
256
|
+
Configure CORS:
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
app.cors({
|
|
260
|
+
origin: '*',
|
|
261
|
+
methods: ['GET', 'POST'],
|
|
262
|
+
credentials: true
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Static Files
|
|
267
|
+
|
|
268
|
+
Serve static files:
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
app.use(app.static('public'));
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Template Engine
|
|
275
|
+
|
|
276
|
+
Render templates:
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
res.render('index', {
|
|
280
|
+
title: 'My Page',
|
|
281
|
+
user: { name: 'Alice' }
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Schema Validation
|
|
286
|
+
|
|
287
|
+
Validate requests:
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
const { Schema, validators: v, validate } = require('lieko-express');
|
|
291
|
+
|
|
292
|
+
const schema = new Schema({
|
|
293
|
+
name: [v.required(), v.string(), v.minLength(3)],
|
|
294
|
+
age: [v.optional(), v.number(), v.min(18)]
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
app.post('/users', validate(schema), (req, res) => {
|
|
298
|
+
res.created(req.body);
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Route Groups
|
|
303
|
+
|
|
304
|
+
Organize routes:
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
app.group('/api', (api) => {
|
|
308
|
+
api.get('/users', handler);
|
|
309
|
+
api.post('/users', handler);
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Error Handling
|
|
314
|
+
|
|
315
|
+
Custom handlers:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
app.notFound((req, res) => {
|
|
319
|
+
res.notFound('Page not found');
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Cookies
|
|
324
|
+
|
|
325
|
+
Set and clear cookies:
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
res.cookie('session', 'abc123', {
|
|
329
|
+
maxAge: 86400000,
|
|
330
|
+
httpOnly: true,
|
|
331
|
+
secure: true
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
res.clearCookie('session');
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## File Uploads
|
|
338
|
+
|
|
339
|
+
Handle uploads:
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
app.post('/upload', (req, res) => {
|
|
343
|
+
const file = req.files.avatar;
|
|
344
|
+
// Process file
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## API Methods Reference
|
|
349
|
+
|
|
350
|
+
See the full documentation for complete lists of application and response methods.
|
|
351
|
+
|
|
352
|
+
## Validators Reference
|
|
353
|
+
|
|
354
|
+
Built-in validators like `v.required()`, `v.email()`, `v.min(10)`.
|
|
355
|
+
|
|
356
|
+
## Best Practices
|
|
357
|
+
|
|
358
|
+
- Use modular routes and controllers.
|
|
359
|
+
- Handle environment variables with `dotenv`.
|
|
360
|
+
- Implement security headers.
|
|
361
|
+
- Add rate limiting for APIs.
|
|
362
|
+
|
|
363
|
+
## Examples
|
|
364
|
+
|
|
365
|
+
### Basic REST API
|
|
366
|
+
|
|
367
|
+
(See code in Quick Start)
|
|
368
|
+
|
|
369
|
+
### Authentication
|
|
370
|
+
|
|
371
|
+
JWT-based auth example (see full code in documentation).
|
|
372
|
+
|
|
373
|
+
### File Upload
|
|
374
|
+
|
|
375
|
+
Upload service example (see full code in documentation).
|
|
376
|
+
|
|
377
|
+
### Real-world App
|
|
378
|
+
|
|
379
|
+
Blog API with auth and posts (see full code in documentation).
|
|
380
|
+
|
|
381
|
+
## Contributing
|
|
382
|
+
|
|
383
|
+
Contributions welcome! Please submit issues or pull requests on GitHub.
|
|
384
|
+
|
|
385
|
+
## License
|
|
386
|
+
|
|
387
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
package/lib/cors.js
CHANGED
package/lib/schema.js
CHANGED
|
@@ -371,15 +371,11 @@ function validate(schema) {
|
|
|
371
371
|
try {
|
|
372
372
|
schema.validate(req.body);
|
|
373
373
|
next();
|
|
374
|
-
} catch (
|
|
375
|
-
if (
|
|
376
|
-
return res.status(400).json({
|
|
377
|
-
success: false,
|
|
378
|
-
message: 'Validation failed',
|
|
379
|
-
errors: error.errors
|
|
380
|
-
});
|
|
374
|
+
} catch (err) {
|
|
375
|
+
if (err instanceof ValidationError) {
|
|
376
|
+
return res.status(400).json({ error: { status: 400, type: "VALIDATION_ERROR", message: 'Validation failed', details: err.errors } });
|
|
381
377
|
}
|
|
382
|
-
throw
|
|
378
|
+
throw err;
|
|
383
379
|
}
|
|
384
380
|
};
|
|
385
381
|
}
|
package/lieko-express.js
CHANGED
|
@@ -781,7 +781,8 @@ ${cyan} (req, res, next) => {
|
|
|
781
781
|
return res.status(500).json({
|
|
782
782
|
error: {
|
|
783
783
|
message: "Internal Server Error",
|
|
784
|
-
|
|
784
|
+
status: 500,
|
|
785
|
+
type: "InternalServerError"
|
|
785
786
|
}
|
|
786
787
|
});
|
|
787
788
|
}
|
|
@@ -812,7 +813,7 @@ ${cyan} (req, res, next) => {
|
|
|
812
813
|
res.status(500).json({
|
|
813
814
|
error: {
|
|
814
815
|
message: "Internal Server Error",
|
|
815
|
-
|
|
816
|
+
status: 500
|
|
816
817
|
}
|
|
817
818
|
});
|
|
818
819
|
}
|
|
@@ -827,13 +828,12 @@ ${cyan} (req, res, next) => {
|
|
|
827
828
|
return res.status(500).json({
|
|
828
829
|
error: {
|
|
829
830
|
message: "Invalid error format passed to res.error()",
|
|
830
|
-
|
|
831
|
+
status: 500
|
|
831
832
|
}
|
|
832
833
|
});
|
|
833
834
|
}
|
|
834
835
|
|
|
835
836
|
const HTTP_STATUS = {
|
|
836
|
-
// 4xx – CLIENT ERRORS
|
|
837
837
|
INVALID_REQUEST: 400,
|
|
838
838
|
VALIDATION_FAILED: 400,
|
|
839
839
|
NO_TOKEN_PROVIDED: 401,
|
|
@@ -844,18 +844,21 @@ ${cyan} (req, res, next) => {
|
|
|
844
844
|
CONFLICT: 409,
|
|
845
845
|
RECORD_EXISTS: 409,
|
|
846
846
|
TOO_MANY_REQUESTS: 429,
|
|
847
|
-
|
|
848
|
-
// 5xx – SERVER ERRORS
|
|
849
847
|
SERVER_ERROR: 500,
|
|
850
848
|
SERVICE_UNAVAILABLE: 503
|
|
851
849
|
};
|
|
852
850
|
|
|
853
|
-
|
|
851
|
+
let currentStatus = res.statusCode || 200;
|
|
852
|
+
let desiredStatus = errorObj.status || HTTP_STATUS[errorObj.status];
|
|
853
|
+
|
|
854
|
+
const finalStatus = (currentStatus >= 400 && currentStatus < 600)
|
|
855
|
+
? currentStatus
|
|
856
|
+
: (desiredStatus || 500);
|
|
854
857
|
|
|
855
|
-
return res.status(
|
|
858
|
+
return res.status(finalStatus).json({
|
|
856
859
|
error: {
|
|
857
860
|
message: errorObj.message || 'An error occurred',
|
|
858
|
-
|
|
861
|
+
status: errorObj.status || finalStatus,
|
|
859
862
|
...errorObj
|
|
860
863
|
}
|
|
861
864
|
});
|
|
@@ -982,7 +985,7 @@ ${cyan} (req, res, next) => {
|
|
|
982
985
|
return res.status(413).json({
|
|
983
986
|
error: {
|
|
984
987
|
message: 'Payload Too Large',
|
|
985
|
-
|
|
988
|
+
status: 413
|
|
986
989
|
}
|
|
987
990
|
});
|
|
988
991
|
}
|
|
@@ -1032,7 +1035,7 @@ ${cyan} (req, res, next) => {
|
|
|
1032
1035
|
|
|
1033
1036
|
if (!route) {
|
|
1034
1037
|
if (this.notFoundHandler) return this.notFoundHandler(req, res);
|
|
1035
|
-
return res.status(404).
|
|
1038
|
+
return res.status(404).error('Not Found');
|
|
1036
1039
|
}
|
|
1037
1040
|
|
|
1038
1041
|
req.params = route.params;
|
|
@@ -1058,7 +1061,11 @@ ${cyan} (req, res, next) => {
|
|
|
1058
1061
|
|
|
1059
1062
|
if (res.headersSent) return;
|
|
1060
1063
|
|
|
1061
|
-
await route.handler(req, res)
|
|
1064
|
+
await route.handler(req, res, (err) => {
|
|
1065
|
+
if (err) {
|
|
1066
|
+
return this._runErrorHandlers(err, req, res);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1062
1069
|
|
|
1063
1070
|
} catch (error) {
|
|
1064
1071
|
if (!res.headersSent) {
|
|
@@ -1138,16 +1145,21 @@ ${cyan} (req, res, next) => {
|
|
|
1138
1145
|
.map(item => item.type);
|
|
1139
1146
|
};
|
|
1140
1147
|
|
|
1141
|
-
const
|
|
1148
|
+
const acceptedTypes = parseAccept(req.headers['accept']);
|
|
1149
|
+
|
|
1150
|
+
req.accepts = function (types) {
|
|
1151
|
+
if (arguments.length === 0) {
|
|
1152
|
+
return acceptedTypes;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1142
1155
|
if (!Array.isArray(types)) types = [types];
|
|
1143
|
-
const accepted = parseAccept(req.headers['accept']);
|
|
1144
1156
|
|
|
1145
1157
|
for (const type of types) {
|
|
1146
1158
|
const t = type.toLowerCase();
|
|
1147
1159
|
|
|
1148
|
-
if (
|
|
1160
|
+
if (acceptedTypes.includes(t)) return type;
|
|
1149
1161
|
|
|
1150
|
-
if (
|
|
1162
|
+
if (acceptedTypes.some(a => {
|
|
1151
1163
|
if (a === '*/*') return true;
|
|
1152
1164
|
if (a.endsWith('/*')) {
|
|
1153
1165
|
const prefix = a.slice(0, -1);
|
|
@@ -1162,8 +1174,24 @@ ${cyan} (req, res, next) => {
|
|
|
1162
1174
|
return false;
|
|
1163
1175
|
};
|
|
1164
1176
|
|
|
1165
|
-
req.
|
|
1166
|
-
|
|
1177
|
+
req.responseType = function () {
|
|
1178
|
+
const accepted = this.accepts();
|
|
1179
|
+
|
|
1180
|
+
if (accepted.length > 0) {
|
|
1181
|
+
for (const type of accepted) {
|
|
1182
|
+
if (type === 'text/html') return 'html';
|
|
1183
|
+
if (type === 'application/json') return 'json';
|
|
1184
|
+
if (type === '*/*') break;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
const ua = (this.headers['user-agent'] || '').toLowerCase();
|
|
1189
|
+
const isApi = ua.includes('curl') ||
|
|
1190
|
+
ua.includes('postman') ||
|
|
1191
|
+
this.xhr ||
|
|
1192
|
+
this.headers['content-type']?.includes('application/json');
|
|
1193
|
+
|
|
1194
|
+
return isApi ? 'json' : 'html';
|
|
1167
1195
|
};
|
|
1168
1196
|
|
|
1169
1197
|
req.acceptsLanguages = function (langs) {
|
|
@@ -1538,6 +1566,7 @@ ${cyan} (req, res, next) => {
|
|
|
1538
1566
|
status = 404;
|
|
1539
1567
|
message = 'File Not Found';
|
|
1540
1568
|
details = `The file "${filePath}" does not exist.\nFull path tried: ${file}`;
|
|
1569
|
+
console.error(details, err);
|
|
1541
1570
|
} else if (err.code === 'FORBIDDEN') {
|
|
1542
1571
|
status = 403;
|
|
1543
1572
|
message = 'Forbidden';
|
|
@@ -1576,11 +1605,9 @@ ${cyan} (req, res, next) => {
|
|
|
1576
1605
|
if (message !== undefined) payload.message = message;
|
|
1577
1606
|
return res.json(payload);
|
|
1578
1607
|
};
|
|
1579
|
-
//res.success = res.ok;
|
|
1580
1608
|
|
|
1581
1609
|
res.created = (data, message = 'Resource created successfully') => {
|
|
1582
|
-
|
|
1583
|
-
return res.status(201).json(payload);
|
|
1610
|
+
return res.status(201).json({ data, message });
|
|
1584
1611
|
};
|
|
1585
1612
|
|
|
1586
1613
|
res.noContent = () => {
|