mikroserve 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +233 -0
- package/lib/MikroServe.d.mts +9 -0
- package/lib/MikroServe.d.ts +9 -0
- package/lib/MikroServe.js +302 -37
- package/lib/MikroServe.mjs +6 -5
- package/lib/RateLimiter.js +2 -1
- package/lib/RateLimiter.mjs +1 -1
- package/lib/Router.js +1 -1
- package/lib/Router.mjs +1 -1
- package/lib/{chunk-YKRH6T5M.mjs → chunk-7LU765PG.mjs} +2 -2
- package/lib/{chunk-N5ZQZGGT.mjs → chunk-C4IW4XUH.mjs} +176 -40
- package/lib/{chunk-JJX5XRNB.mjs → chunk-DMNHVQTU.mjs} +6 -0
- package/lib/{chunk-ZFBBESGU.mjs → chunk-OF5DEOIU.mjs} +2 -1
- package/lib/chunk-VLQ7ZZIU.mjs +105 -0
- package/lib/{chunk-YOHL3T54.mjs → chunk-ZT2UGCN5.mjs} +29 -4
- package/lib/config.js +32 -3
- package/lib/config.mjs +2 -2
- package/lib/index.d.mts +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +302 -37
- package/lib/index.mjs +6 -5
- package/lib/interfaces/index.d.mts +10 -0
- package/lib/interfaces/index.d.ts +10 -0
- package/lib/utils/configDefaults.d.mts +2 -0
- package/lib/utils/configDefaults.d.ts +2 -0
- package/lib/utils/configDefaults.js +6 -0
- package/lib/utils/configDefaults.mjs +1 -1
- package/lib/utils/multipartParser.d.mts +19 -0
- package/lib/utils/multipartParser.d.ts +19 -0
- package/lib/utils/multipartParser.js +129 -0
- package/lib/utils/multipartParser.mjs +6 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -14,10 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
- Native Node.js [http](https://nodejs.org/api/http.html)/[https](https://nodejs.org/api/https.html)/[http2](https://nodejs.org/api/http2.html) implementation, meaning maximum performance
|
|
16
16
|
- [Hono](https://hono.dev)-style API semantics for GET, POST, PATCH, PUT, DELETE operations
|
|
17
|
+
- Binary file upload/download support (images, PDFs, videos, etc.)
|
|
18
|
+
- Multipart form-data parsing for HTML file uploads
|
|
17
19
|
- Supports being exposed over HTTP, HTTPS, and HTTP2
|
|
18
20
|
- Supports custom middlewares
|
|
19
21
|
- Out-of-the-box CORS support
|
|
20
22
|
- Built-in customizable rate limiter
|
|
23
|
+
- Configurable request timeout protection against slow clients
|
|
24
|
+
- Configurable body size limits
|
|
21
25
|
- Tiny (~5kb gzipped)
|
|
22
26
|
- Only a single dependency: [MikroConf](https://github.com/mikaelvesavuori/mikroconf)
|
|
23
27
|
|
|
@@ -189,6 +193,150 @@ api.get('/error', () => {
|
|
|
189
193
|
api.start();
|
|
190
194
|
```
|
|
191
195
|
|
|
196
|
+
### Binary File Uploads
|
|
197
|
+
|
|
198
|
+
MikroServe automatically handles binary file uploads by preserving the raw Buffer for binary content types.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { MikroServe, type Context } from 'mikroserve';
|
|
202
|
+
import { writeFile } from 'node:fs/promises';
|
|
203
|
+
|
|
204
|
+
const api = new MikroServe();
|
|
205
|
+
|
|
206
|
+
// Handle binary file upload (e.g., image, PDF, video)
|
|
207
|
+
api.post('/upload', async (c: Context) => {
|
|
208
|
+
const buffer = c.body as Buffer;
|
|
209
|
+
|
|
210
|
+
// Save to disk
|
|
211
|
+
await writeFile('/uploads/file.bin', buffer);
|
|
212
|
+
|
|
213
|
+
return c.json({
|
|
214
|
+
success: true,
|
|
215
|
+
size: buffer.length,
|
|
216
|
+
message: 'File uploaded successfully'
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Handle image upload with binary response
|
|
221
|
+
api.post('/process-image', async (c: Context) => {
|
|
222
|
+
const imageBuffer = c.body as Buffer;
|
|
223
|
+
|
|
224
|
+
// Process the image (resize, compress, etc.)
|
|
225
|
+
const processedImage = await processImage(imageBuffer);
|
|
226
|
+
|
|
227
|
+
// Return binary image
|
|
228
|
+
return c.binary(processedImage, 'image/jpeg');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
api.start();
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Supported binary content types:**
|
|
235
|
+
|
|
236
|
+
- Images: `image/*` (PNG, JPEG, GIF, WebP, etc.)
|
|
237
|
+
- Videos: `video/*` (MP4, WebM, etc.)
|
|
238
|
+
- Audio: `audio/*` (MP3, WAV, etc.)
|
|
239
|
+
- Documents: `application/pdf`, Office documents, etc.
|
|
240
|
+
- Archives: `application/zip`, `application/gzip`, etc.
|
|
241
|
+
- Generic: `application/octet-stream`
|
|
242
|
+
|
|
243
|
+
### Multipart Form-Data (File Uploads from HTML Forms)
|
|
244
|
+
|
|
245
|
+
Handle file uploads from HTML forms with automatic multipart parsing.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { MikroServe, type Context, type MultipartFormData } from 'mikroserve';
|
|
249
|
+
|
|
250
|
+
const api = new MikroServe();
|
|
251
|
+
|
|
252
|
+
// Handle HTML form with file upload
|
|
253
|
+
api.post('/submit-form', async (c: Context) => {
|
|
254
|
+
const { fields, files } = c.body as MultipartFormData;
|
|
255
|
+
|
|
256
|
+
// Access form fields
|
|
257
|
+
console.log(fields.username); // "john_doe"
|
|
258
|
+
console.log(fields.email); // "john@example.com"
|
|
259
|
+
|
|
260
|
+
// Access uploaded file
|
|
261
|
+
const uploadedFile = files.avatar;
|
|
262
|
+
console.log(uploadedFile.filename); // "profile.jpg"
|
|
263
|
+
console.log(uploadedFile.contentType); // "image/jpeg"
|
|
264
|
+
console.log(uploadedFile.size); // 45234
|
|
265
|
+
|
|
266
|
+
// uploadedFile.data is a Buffer
|
|
267
|
+
await saveFile(`/uploads/${uploadedFile.filename}`, uploadedFile.data);
|
|
268
|
+
|
|
269
|
+
return c.json({
|
|
270
|
+
success: true,
|
|
271
|
+
user: fields.username,
|
|
272
|
+
file: uploadedFile.filename
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Handle multiple file uploads
|
|
277
|
+
api.post('/upload-multiple', async (c: Context) => {
|
|
278
|
+
const { fields, files } = c.body as MultipartFormData;
|
|
279
|
+
|
|
280
|
+
// Multiple files with same field name become an array
|
|
281
|
+
const uploadedFiles = files.documents as Array<MultipartFile>;
|
|
282
|
+
|
|
283
|
+
for (const file of uploadedFiles) {
|
|
284
|
+
await saveFile(`/uploads/${file.filename}`, file.data);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return c.json({
|
|
288
|
+
success: true,
|
|
289
|
+
count: uploadedFiles.length
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
api.start();
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Example HTML form:**
|
|
297
|
+
|
|
298
|
+
```html
|
|
299
|
+
<form action="http://localhost:3000/submit-form" method="POST" enctype="multipart/form-data">
|
|
300
|
+
<input type="text" name="username" value="john_doe">
|
|
301
|
+
<input type="email" name="email" value="john@example.com">
|
|
302
|
+
<input type="file" name="avatar">
|
|
303
|
+
<button type="submit">Upload</button>
|
|
304
|
+
</form>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Custom Configuration
|
|
308
|
+
|
|
309
|
+
Configure body size limits, request timeouts, and more.
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { MikroServe } from 'mikroserve';
|
|
313
|
+
|
|
314
|
+
const api = new MikroServe({
|
|
315
|
+
port: 3000,
|
|
316
|
+
host: '0.0.0.0',
|
|
317
|
+
|
|
318
|
+
// Set maximum request body size (default: 1MB)
|
|
319
|
+
maxBodySize: 50 * 1024 * 1024, // 50MB for large file uploads
|
|
320
|
+
|
|
321
|
+
// Set request timeout to prevent slow clients (default: 30 seconds)
|
|
322
|
+
requestTimeout: 60000, // 60 seconds, set to 0 to disable
|
|
323
|
+
|
|
324
|
+
// Rate limiting
|
|
325
|
+
rateLimit: {
|
|
326
|
+
enabled: true,
|
|
327
|
+
requestsPerMinute: 100
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
// CORS configuration
|
|
331
|
+
allowedDomains: ['https://yourdomain.com', 'https://app.yourdomain.com'],
|
|
332
|
+
|
|
333
|
+
// Enable debug logging
|
|
334
|
+
debug: false
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
api.start();
|
|
338
|
+
```
|
|
339
|
+
|
|
192
340
|
## Configuration
|
|
193
341
|
|
|
194
342
|
All of the settings already presented in the above examples can be provided in multiple ways.
|
|
@@ -203,6 +351,24 @@ All of the settings already presented in the above examples can be provided in m
|
|
|
203
351
|
|
|
204
352
|
### Options
|
|
205
353
|
|
|
354
|
+
| Option | Type | Default | Description |
|
|
355
|
+
|------------------------|-----------|--------------|-------------------------------------------------------|
|
|
356
|
+
| `port` | `number` | `3000` | Port to listen on |
|
|
357
|
+
| `host` | `string` | `'0.0.0.0'` | Host address to bind to |
|
|
358
|
+
| `useHttps` | `boolean` | `false` | Enable HTTPS |
|
|
359
|
+
| `useHttp2` | `boolean` | `false` | Enable HTTP/2 |
|
|
360
|
+
| `sslCert` | `string` | `''` | Path to SSL certificate file |
|
|
361
|
+
| `sslKey` | `string` | `''` | Path to SSL key file |
|
|
362
|
+
| `sslCa` | `string` | `''` | Path to SSL CA file |
|
|
363
|
+
| `debug` | `boolean` | `false` | Enable debug logging |
|
|
364
|
+
| `maxBodySize` | `number` | `1048576` | Maximum request body size in bytes (1MB default) |
|
|
365
|
+
| `requestTimeout` | `number` | `30000` | Request timeout in milliseconds (30s default, 0 = disabled) |
|
|
366
|
+
| `rateLimit.enabled` | `boolean` | `true` | Enable rate limiting |
|
|
367
|
+
| `rateLimit.requestsPerMinute` | `number` | `100` | Maximum requests per minute per IP |
|
|
368
|
+
| `allowedDomains` | `string[]`| `['*']` | CORS allowed domains (wildcard `*` allows all) |
|
|
369
|
+
|
|
370
|
+
### CLI Arguments
|
|
371
|
+
|
|
206
372
|
| CLI argument | CLI value | JSON (config file) value | Environment variable |
|
|
207
373
|
|--------------|-----------------------------|-----------------------------|----------------------|
|
|
208
374
|
| --port | `<number>` | port | PORT |
|
|
@@ -236,6 +402,73 @@ openssl req -x509 -newkey rsa:2048 -keyout local-key.pem -out local-cert.pem -da
|
|
|
236
402
|
|
|
237
403
|
Feel free to change the key and cert names as you wish.
|
|
238
404
|
|
|
405
|
+
## Response Helpers
|
|
406
|
+
|
|
407
|
+
MikroServe provides convenient response helpers on the context object:
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// Text response
|
|
411
|
+
c.text('Plain text content', 200);
|
|
412
|
+
|
|
413
|
+
// JSON response
|
|
414
|
+
c.json({ message: 'Success' }, 200);
|
|
415
|
+
|
|
416
|
+
// HTML response
|
|
417
|
+
c.html('<h1>Hello World</h1>', 200);
|
|
418
|
+
|
|
419
|
+
// Binary response (for files, images, etc.)
|
|
420
|
+
c.binary(buffer, 'image/png', 200);
|
|
421
|
+
|
|
422
|
+
// Form-urlencoded response
|
|
423
|
+
c.form({ key: 'value' }, 200);
|
|
424
|
+
|
|
425
|
+
// Redirect
|
|
426
|
+
c.redirect('/new-location', 302);
|
|
427
|
+
|
|
428
|
+
// Custom status code
|
|
429
|
+
c.status(404).json({ error: 'Not Found' });
|
|
430
|
+
|
|
431
|
+
// Access raw response object
|
|
432
|
+
const res = c.raw();
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## TypeScript Support
|
|
436
|
+
|
|
437
|
+
MikroServe is written in TypeScript and exports all necessary types:
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import {
|
|
441
|
+
MikroServe,
|
|
442
|
+
type Context,
|
|
443
|
+
type MultipartFile,
|
|
444
|
+
type MultipartFormData
|
|
445
|
+
} from 'mikroserve';
|
|
446
|
+
|
|
447
|
+
// Context provides full type information for request/response
|
|
448
|
+
api.post('/upload', async (c: Context) => {
|
|
449
|
+
// c.body, c.params, c.query, c.headers are all typed
|
|
450
|
+
const data = c.body as MultipartFormData;
|
|
451
|
+
// ...
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Performance Tips
|
|
456
|
+
|
|
457
|
+
1. **Adjust body size limits** based on your use case:
|
|
458
|
+
- For JSON APIs: Keep default 1MB or lower
|
|
459
|
+
- For file uploads: Increase to 50-100MB or as needed
|
|
460
|
+
|
|
461
|
+
2. **Enable request timeouts** to prevent resource exhaustion:
|
|
462
|
+
- Default 30 seconds is good for most APIs
|
|
463
|
+
- Increase for large file uploads
|
|
464
|
+
- Set to 0 only if you have other timeout mechanisms
|
|
465
|
+
|
|
466
|
+
3. **Use rate limiting** to protect against abuse:
|
|
467
|
+
- Default 100 requests/minute per IP
|
|
468
|
+
- Adjust based on your traffic patterns
|
|
469
|
+
|
|
470
|
+
4. **Binary responses**: Use `c.binary()` for files to avoid JSON serialization overhead
|
|
471
|
+
|
|
239
472
|
## License
|
|
240
473
|
|
|
241
474
|
MIT. See the `LICENSE` file.
|
package/lib/MikroServe.d.mts
CHANGED
|
@@ -10,6 +10,7 @@ declare class MikroServe {
|
|
|
10
10
|
private config;
|
|
11
11
|
private rateLimiter;
|
|
12
12
|
private router;
|
|
13
|
+
private shutdownHandlers;
|
|
13
14
|
/**
|
|
14
15
|
* @description Creates a new MikroServe instance.
|
|
15
16
|
*/
|
|
@@ -70,6 +71,10 @@ declare class MikroServe {
|
|
|
70
71
|
* @description Parses the request body based on content type.
|
|
71
72
|
*/
|
|
72
73
|
private parseBody;
|
|
74
|
+
/**
|
|
75
|
+
* @description Checks if a content type is binary.
|
|
76
|
+
*/
|
|
77
|
+
private isBinaryContentType;
|
|
73
78
|
/**
|
|
74
79
|
* @description CORS middleware.
|
|
75
80
|
*/
|
|
@@ -86,6 +91,10 @@ declare class MikroServe {
|
|
|
86
91
|
* @description Sets up graceful shutdown handlers for a server.
|
|
87
92
|
*/
|
|
88
93
|
setupGracefulShutdown(server: ServerType): void;
|
|
94
|
+
/**
|
|
95
|
+
* @description Cleans up shutdown event listeners to prevent memory leaks.
|
|
96
|
+
*/
|
|
97
|
+
private cleanupShutdownHandlers;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
export { MikroServe };
|
package/lib/MikroServe.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ declare class MikroServe {
|
|
|
10
10
|
private config;
|
|
11
11
|
private rateLimiter;
|
|
12
12
|
private router;
|
|
13
|
+
private shutdownHandlers;
|
|
13
14
|
/**
|
|
14
15
|
* @description Creates a new MikroServe instance.
|
|
15
16
|
*/
|
|
@@ -70,6 +71,10 @@ declare class MikroServe {
|
|
|
70
71
|
* @description Parses the request body based on content type.
|
|
71
72
|
*/
|
|
72
73
|
private parseBody;
|
|
74
|
+
/**
|
|
75
|
+
* @description Checks if a content type is binary.
|
|
76
|
+
*/
|
|
77
|
+
private isBinaryContentType;
|
|
73
78
|
/**
|
|
74
79
|
* @description CORS middleware.
|
|
75
80
|
*/
|
|
@@ -86,6 +91,10 @@ declare class MikroServe {
|
|
|
86
91
|
* @description Sets up graceful shutdown handlers for a server.
|
|
87
92
|
*/
|
|
88
93
|
setupGracefulShutdown(server: ServerType): void;
|
|
94
|
+
/**
|
|
95
|
+
* @description Cleans up shutdown event listeners to prevent memory leaks.
|
|
96
|
+
*/
|
|
97
|
+
private cleanupShutdownHandlers;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
export { MikroServe };
|