kempo-server 1.7.4 → 1.7.6
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/CONFIG.md +501 -0
- package/README.md +13 -442
- package/UTILS.md +127 -0
- package/dist/utils/cli.js +1 -0
- package/dist/utils/fs-utils.js +1 -0
- package/package.json +7 -2
- package/scripts/build.js +57 -43
- package/tests/getFiles.node-test.js +3 -3
- package/tests/index.node-test.js +3 -2
- package/tests/router-middleware.node-test.js +2 -3
- package/tests/router.node-test.js +7 -8
- package/tests/serveFile.node-test.js +5 -8
- package/tests/test-server-root/.config.json +5 -0
- package/tests/test-server-root/README.md +118 -0
- package/tests/test-server-root/a.txt +1 -0
- package/tests/test-server-root/api/GET.js +1 -0
- package/tests/test-server-root/api/no-default.js +1 -0
- package/tests/test-server-root/b/1.txt +1 -0
- package/tests/test-server-root/custom/data.json +1 -0
- package/tests/test-server-root/docs/.config.json +6 -0
- package/tests/test-server-root/docs/api/data.json +1 -0
- package/tests/test-server-root/docs/src/components/Button.js +1 -0
- package/tests/test-server-root/docs/src/nested/file.js +1 -0
- package/tests/test-server-root/docs/src/utils/helpers/format.js +1 -0
- package/tests/test-server-root/hello.html +1 -0
- package/tests/test-server-root/index.html +1 -0
- package/tests/test-server-root/late.html +1 -0
- package/tests/test-server-root/public/src/file.txt +1 -0
- package/tests/test-server-root/src/components/Button.js +1 -0
- package/tests/test-server-root/src/deep/nested/folder/file.js +1 -0
- package/tests/test-server-root/src/file.js +1 -0
- package/tests/test-server-root/src/file.txt +1 -0
- package/tests/test-server-root/src/nested/file.js +1 -0
- package/tests/test-server-root/src/utils/helpers/format.js +1 -0
- package/tests/test-utils.js +50 -1
- package/config-examples/development.config.json +0 -24
- package/config-examples/low-memory.config.json +0 -23
- package/config-examples/no-cache.config.json +0 -13
- package/config-examples/production.config.json +0 -38
- package/example-cache.config.json +0 -45
- package/example.config.json +0 -50
- package/utils/cache-demo.js +0 -145
- package/utils/cache-monitor.js +0 -132
package/README.md
CHANGED
|
@@ -211,435 +211,19 @@ export default async function(request, response) {
|
|
|
211
211
|
|
|
212
212
|
## Configuration
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
Kempo Server can be customized with a simple JSON configuration file to control caching, middleware, security, routing, and more.
|
|
215
215
|
|
|
216
|
-
**
|
|
217
|
-
- When using a relative path for the `--config` flag, the config file must be located within the server root directory
|
|
218
|
-
- When using an absolute path for the `--config` flag, the config file can be located anywhere on the filesystem
|
|
219
|
-
- The server will throw an error if you attempt to use a relative config file path that points outside the root directory
|
|
216
|
+
For detailed configuration options and examples, see **[CONFIG.md](./CONFIG.md)**.
|
|
220
217
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
- [customRoutes](#customroutes)
|
|
226
|
-
- [routeFiles](#routefiles)
|
|
227
|
-
- [noRescanPaths](#norescanpaths)
|
|
228
|
-
- [maxRescanAttempts](#maxrescanattempts)
|
|
229
|
-
- [cache](#cache)
|
|
230
|
-
- [middleware](#middleware)
|
|
231
|
-
|
|
232
|
-
## Cache
|
|
233
|
-
|
|
234
|
-
Kempo Server includes an intelligent module caching system that dramatically improves performance by caching JavaScript route modules in memory. The cache combines multiple strategies:
|
|
235
|
-
|
|
236
|
-
- **LRU (Least Recently Used)** - Evicts oldest modules when cache fills
|
|
237
|
-
- **Time-based expiration** - Modules expire after configurable TTL
|
|
238
|
-
- **Memory monitoring** - Automatically clears cache if memory usage gets too high
|
|
239
|
-
- **File watching** - Instantly invalidates cache when files change (development)
|
|
240
|
-
|
|
241
|
-
### Basic Cache Configuration
|
|
242
|
-
|
|
243
|
-
Enable caching in your `.config.json`:
|
|
244
|
-
|
|
245
|
-
```json
|
|
246
|
-
{
|
|
247
|
-
"cache": {
|
|
248
|
-
"enabled": true,
|
|
249
|
-
"maxSize": 100,
|
|
250
|
-
"maxMemoryMB": 50,
|
|
251
|
-
"ttlMs": 300000,
|
|
252
|
-
"watchFiles": true
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### Cache Options
|
|
258
|
-
|
|
259
|
-
- `enabled` (boolean) - Enable/disable caching (default: `true`)
|
|
260
|
-
- `maxSize` (number) - Maximum cached modules (default: `100`)
|
|
261
|
-
- `maxMemoryMB` (number) - Memory limit in MB (default: `50`)
|
|
262
|
-
- `ttlMs` (number) - Cache lifetime in milliseconds (default: `300000` - 5 minutes)
|
|
263
|
-
- `maxHeapUsagePercent` (number) - Clear cache when heap exceeds % (default: `70`)
|
|
264
|
-
- `memoryCheckInterval` (number) - Memory check frequency in ms (default: `30000`)
|
|
265
|
-
- `watchFiles` (boolean) - Auto-invalidate on file changes (default: `true`)
|
|
266
|
-
- `enableMemoryMonitoring` (boolean) - Enable memory monitoring (default: `true`)
|
|
267
|
-
|
|
268
|
-
### Environment-Specific Configurations
|
|
269
|
-
|
|
270
|
-
Use different config files for different environments:
|
|
271
|
-
|
|
272
|
-
**Development (`dev.config.json`):**
|
|
273
|
-
```json
|
|
274
|
-
{
|
|
275
|
-
"cache": {
|
|
276
|
-
"enabled": true,
|
|
277
|
-
"maxSize": 50,
|
|
278
|
-
"ttlMs": 300000,
|
|
279
|
-
"watchFiles": true
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
**Production (`prod.config.json`):**
|
|
285
|
-
```json
|
|
286
|
-
{
|
|
287
|
-
"cache": {
|
|
288
|
-
"enabled": true,
|
|
289
|
-
"maxSize": 1000,
|
|
290
|
-
"maxMemoryMB": 200,
|
|
291
|
-
"ttlMs": 3600000,
|
|
292
|
-
"watchFiles": false
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Run with specific config: `node src/index.js --config prod.config.json`
|
|
298
|
-
|
|
299
|
-
### Cache Monitoring
|
|
300
|
-
|
|
301
|
-
Monitor cache performance at runtime:
|
|
302
|
-
|
|
303
|
-
- **View stats:** `GET /_admin/cache` - Returns detailed cache statistics
|
|
304
|
-
- **Clear cache:** `DELETE /_admin/cache` - Clears entire cache
|
|
305
|
-
|
|
306
|
-
Example response:
|
|
307
|
-
```json
|
|
308
|
-
{
|
|
309
|
-
"cache": {
|
|
310
|
-
"size": 45,
|
|
311
|
-
"maxSize": 100,
|
|
312
|
-
"memoryUsageMB": 12.5,
|
|
313
|
-
"hitRate": 87
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
## Middleware
|
|
319
|
-
|
|
320
|
-
Kempo Server includes a powerful middleware system that allows you to add functionality like authentication, logging, CORS, compression, and more. Middleware runs before your route handlers and can modify requests, responses, or handle requests entirely.
|
|
321
|
-
|
|
322
|
-
### Built-in Middleware
|
|
323
|
-
|
|
324
|
-
#### CORS
|
|
325
|
-
Enable Cross-Origin Resource Sharing for your API:
|
|
326
|
-
|
|
327
|
-
```json
|
|
328
|
-
{
|
|
329
|
-
"middleware": {
|
|
330
|
-
"cors": {
|
|
331
|
-
"enabled": true,
|
|
332
|
-
"origin": "*",
|
|
333
|
-
"methods": ["GET", "POST", "PUT", "DELETE"],
|
|
334
|
-
"headers": ["Content-Type", "Authorization"]
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
#### Compression
|
|
341
|
-
Automatically compress responses with gzip:
|
|
342
|
-
|
|
343
|
-
```json
|
|
344
|
-
{
|
|
345
|
-
"middleware": {
|
|
346
|
-
"compression": {
|
|
347
|
-
"enabled": true,
|
|
348
|
-
"threshold": 1024
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
#### Rate Limiting
|
|
355
|
-
Limit requests per client to prevent abuse:
|
|
356
|
-
|
|
357
|
-
```json
|
|
358
|
-
{
|
|
359
|
-
"middleware": {
|
|
360
|
-
"rateLimit": {
|
|
361
|
-
"enabled": true,
|
|
362
|
-
"maxRequests": 100,
|
|
363
|
-
"windowMs": 60000,
|
|
364
|
-
"message": "Too many requests"
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
#### Security Headers
|
|
371
|
-
Add security headers to all responses:
|
|
372
|
-
|
|
373
|
-
```json
|
|
374
|
-
{
|
|
375
|
-
"middleware": {
|
|
376
|
-
"security": {
|
|
377
|
-
"enabled": true,
|
|
378
|
-
"headers": {
|
|
379
|
-
"X-Content-Type-Options": "nosniff",
|
|
380
|
-
"X-Frame-Options": "DENY",
|
|
381
|
-
"X-XSS-Protection": "1; mode=block"
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
#### Request Logging
|
|
389
|
-
Log requests with configurable detail:
|
|
390
|
-
|
|
391
|
-
```json
|
|
392
|
-
{
|
|
393
|
-
"middleware": {
|
|
394
|
-
"logging": {
|
|
395
|
-
"enabled": true,
|
|
396
|
-
"includeUserAgent": true,
|
|
397
|
-
"includeResponseTime": true
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Custom Middleware
|
|
404
|
-
|
|
405
|
-
Create your own middleware by writing JavaScript files and referencing them in your config:
|
|
406
|
-
|
|
407
|
-
```json
|
|
408
|
-
{
|
|
409
|
-
"middleware": {
|
|
410
|
-
"custom": ["./middleware/auth.js", "./middleware/analytics.js"]
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
#### Custom Middleware Example
|
|
416
|
-
|
|
417
|
-
```javascript
|
|
418
|
-
// middleware/auth.js
|
|
419
|
-
export default (config) => {
|
|
420
|
-
return async (req, res, next) => {
|
|
421
|
-
const token = req.headers.authorization;
|
|
422
|
-
|
|
423
|
-
if (!token) {
|
|
424
|
-
req.user = null;
|
|
425
|
-
return await next();
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
try {
|
|
429
|
-
// Verify JWT token (example)
|
|
430
|
-
const user = verifyToken(token);
|
|
431
|
-
req.user = user;
|
|
432
|
-
req.permissions = await getUserPermissions(user.id);
|
|
433
|
-
|
|
434
|
-
// Add helper methods
|
|
435
|
-
req.hasPermission = (permission) => req.permissions.includes(permission);
|
|
436
|
-
|
|
437
|
-
} catch (error) {
|
|
438
|
-
req.user = null;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
await next();
|
|
442
|
-
};
|
|
443
|
-
};
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
#### Using Enhanced Requests in Routes
|
|
447
|
-
|
|
448
|
-
Your route files can now access the enhanced request object:
|
|
449
|
-
|
|
450
|
-
```javascript
|
|
451
|
-
// api/user/profile/GET.js
|
|
452
|
-
export default async (req, res, params) => {
|
|
453
|
-
if (!req.user) {
|
|
454
|
-
return res.status(401).json({ error: 'Authentication required' });
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
if (!req.hasPermission('user:read')) {
|
|
458
|
-
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const profile = await getUserProfile(req.user.id);
|
|
462
|
-
res.json(profile);
|
|
463
|
-
};
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
### Middleware Order
|
|
467
|
-
|
|
468
|
-
Middleware executes in this order:
|
|
469
|
-
1. Built-in middleware (cors, compression, rateLimit, security, logging)
|
|
470
|
-
2. Custom middleware (in the order listed in config)
|
|
471
|
-
3. Your route handlers
|
|
472
|
-
|
|
473
|
-
### Route Interception
|
|
474
|
-
|
|
475
|
-
Middleware can intercept and handle routes completely, useful for authentication endpoints:
|
|
476
|
-
|
|
477
|
-
```javascript
|
|
478
|
-
// middleware/auth-routes.js
|
|
479
|
-
export default (config) => {
|
|
480
|
-
return async (req, res, next) => {
|
|
481
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
482
|
-
|
|
483
|
-
// Handle login endpoint
|
|
484
|
-
if (req.method === 'POST' && url.pathname === '/auth/login') {
|
|
485
|
-
const credentials = await req.json();
|
|
486
|
-
const token = await authenticateUser(credentials);
|
|
487
|
-
|
|
488
|
-
if (token) {
|
|
489
|
-
return res.json({ token, success: true });
|
|
490
|
-
} else {
|
|
491
|
-
return res.status(401).json({ error: 'Invalid credentials' });
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
await next();
|
|
496
|
-
};
|
|
497
|
-
};
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
### allowedMimes
|
|
501
|
-
|
|
502
|
-
An object mapping file extensions to their MIME types. Files with extensions not in this list will not be served.
|
|
503
|
-
|
|
504
|
-
```json
|
|
505
|
-
{
|
|
506
|
-
"allowedMimes": {
|
|
507
|
-
"html": "text/html",
|
|
508
|
-
"css": "text/css",
|
|
509
|
-
"js": "application/javascript",
|
|
510
|
-
"json": "application/json",
|
|
511
|
-
"png": "image/png",
|
|
512
|
-
"jpg": "image/jpeg"
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
### disallowedRegex
|
|
518
|
-
|
|
519
|
-
An array of regular expressions that match paths that should never be served. This provides security by preventing access to sensitive files.
|
|
520
|
-
|
|
521
|
-
```json
|
|
522
|
-
{
|
|
523
|
-
"disallowedRegex": [
|
|
524
|
-
"^/\\..*",
|
|
525
|
-
"\\.env$",
|
|
526
|
-
"\\.config$",
|
|
527
|
-
"password"
|
|
528
|
-
]
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
### routeFiles
|
|
533
|
-
|
|
534
|
-
An array of filenames that should be treated as route handlers and executed as JavaScript modules.
|
|
535
|
-
|
|
536
|
-
```json
|
|
537
|
-
{
|
|
538
|
-
"routeFiles": [
|
|
539
|
-
"GET.js",
|
|
540
|
-
"POST.js",
|
|
541
|
-
"PUT.js",
|
|
542
|
-
"DELETE.js",
|
|
543
|
-
"index.js"
|
|
544
|
-
]
|
|
545
|
-
}
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
### noRescanPaths
|
|
549
|
-
|
|
550
|
-
An array of regex patterns for paths that should not trigger a file system rescan. This improves performance for common static assets.
|
|
551
|
-
|
|
552
|
-
```json
|
|
553
|
-
{
|
|
554
|
-
"noRescanPaths": [
|
|
555
|
-
"/favicon\\.ico$",
|
|
556
|
-
"/robots\\.txt$",
|
|
557
|
-
"\\.map$"
|
|
558
|
-
]
|
|
559
|
-
}
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
### customRoutes
|
|
563
|
-
|
|
564
|
-
An object mapping custom route paths to file paths. Useful for aliasing or serving files from outside the document root.
|
|
565
|
-
|
|
566
|
-
**Note:** All file paths in customRoutes are resolved relative to the server root directory (the `--root` path). This allows you to reference files both inside and outside the document root.
|
|
567
|
-
|
|
568
|
-
**Basic Routes:**
|
|
569
|
-
```json
|
|
570
|
-
{
|
|
571
|
-
"customRoutes": {
|
|
572
|
-
"/vendor/bootstrap.css": "../node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
573
|
-
"/api/status": "./status.js"
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
**Wildcard Routes:**
|
|
579
|
-
Wildcard routes allow you to map entire directory structures using the `*` and `**` wildcards:
|
|
580
|
-
|
|
581
|
-
```json
|
|
582
|
-
{
|
|
583
|
-
"customRoutes": {
|
|
584
|
-
"kempo/*": "../node_modules/kempo/dist/*",
|
|
585
|
-
"assets/*": "../static-files/*",
|
|
586
|
-
"docs/*": "../documentation/*",
|
|
587
|
-
"src/**": "../src/**"
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
With wildcard routes:
|
|
593
|
-
- `kempo/styles.css` would serve `../node_modules/kempo/dist/styles.css`
|
|
594
|
-
- `assets/logo.png` would serve `../static-files/logo.png`
|
|
595
|
-
- `docs/readme.md` would serve `../documentation/readme.md`
|
|
596
|
-
- `src/components/Button.js` would serve `../src/components/Button.js`
|
|
597
|
-
|
|
598
|
-
The `*` wildcard matches any single path segment (anything between `/` characters).
|
|
599
|
-
The `**` wildcard matches any number of path segments, allowing you to map entire directory trees.
|
|
600
|
-
Multiple wildcards can be used in a single route pattern.
|
|
601
|
-
|
|
602
|
-
### maxRescanAttempts
|
|
603
|
-
|
|
604
|
-
The maximum number of times to attempt rescanning the file system when a file is not found. Defaults to 3.
|
|
605
|
-
|
|
606
|
-
```json
|
|
607
|
-
{
|
|
608
|
-
"maxRescanAttempts": 3
|
|
609
|
-
}
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
### cache
|
|
613
|
-
|
|
614
|
-
Configure the intelligent module caching system for improved performance:
|
|
218
|
+
Quick start:
|
|
219
|
+
```bash
|
|
220
|
+
# Create a basic config file
|
|
221
|
+
echo '{"cache": {"enabled": true}}' > .config.json
|
|
615
222
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"cache": {
|
|
619
|
-
"enabled": true,
|
|
620
|
-
"maxSize": 100,
|
|
621
|
-
"maxMemoryMB": 50,
|
|
622
|
-
"ttlMs": 300000,
|
|
623
|
-
"maxHeapUsagePercent": 70,
|
|
624
|
-
"memoryCheckInterval": 30000,
|
|
625
|
-
"watchFiles": true,
|
|
626
|
-
"enableMemoryMonitoring": true
|
|
627
|
-
}
|
|
628
|
-
}
|
|
223
|
+
# Use different configs for different environments
|
|
224
|
+
kempo-server --root public --config dev.config.json
|
|
629
225
|
```
|
|
630
226
|
|
|
631
|
-
Cache options:
|
|
632
|
-
- `enabled` - Enable/disable caching (boolean, default: `true`)
|
|
633
|
-
- `maxSize` - Maximum cached modules (number, default: `100`)
|
|
634
|
-
- `maxMemoryMB` - Memory limit in MB (number, default: `50`)
|
|
635
|
-
- `ttlMs` - Cache lifetime in milliseconds (number, default: `300000`)
|
|
636
|
-
- `maxHeapUsagePercent` - Clear cache when heap exceeds % (number, default: `70`)
|
|
637
|
-
- `memoryCheckInterval` - Memory check frequency in ms (number, default: `30000`)
|
|
638
|
-
- `watchFiles` - Auto-invalidate on file changes (boolean, default: `true`)
|
|
639
|
-
- `enableMemoryMonitoring` - Enable memory monitoring (boolean, default: `true`)
|
|
640
|
-
|
|
641
|
-
Use different config files for different environments rather than nested objects.
|
|
642
|
-
|
|
643
227
|
## Features
|
|
644
228
|
|
|
645
229
|
- **Zero Dependencies** - No external dependencies required
|
|
@@ -756,24 +340,6 @@ Kempo Server supports several command line options to customize its behavior:
|
|
|
756
340
|
kempo-server --root public --port 8080 --host 0.0.0.0 --verbose
|
|
757
341
|
```
|
|
758
342
|
|
|
759
|
-
### Configuration File Examples
|
|
760
|
-
|
|
761
|
-
You can specify different configuration files for different environments:
|
|
762
|
-
|
|
763
|
-
```bash
|
|
764
|
-
# Development
|
|
765
|
-
kempo-server --root public --config dev.config.json
|
|
766
|
-
|
|
767
|
-
# Staging
|
|
768
|
-
kempo-server --root public --config staging.config.json
|
|
769
|
-
|
|
770
|
-
# Production with absolute path
|
|
771
|
-
kempo-server --root public --config /etc/kempo/production.config.json
|
|
772
|
-
|
|
773
|
-
# Mix with other options
|
|
774
|
-
kempo-server --root dist --port 8080 --config production.config.json --scan
|
|
775
|
-
```
|
|
776
|
-
|
|
777
343
|
## Testing
|
|
778
344
|
|
|
779
345
|
This project uses the Kempo Testing Framework. Tests live in the `tests/` folder and follow these naming conventions:
|
|
@@ -796,3 +362,8 @@ npm run tests:gui # Start the GUI test runner
|
|
|
796
362
|
For advanced usage (filters, flags, GUI options), see:
|
|
797
363
|
https://github.com/dustinpoissant/kempo-testing-framework
|
|
798
364
|
|
|
365
|
+
## Documentation
|
|
366
|
+
|
|
367
|
+
- **[CONFIG.md](./CONFIG.md)** - Comprehensive server configuration guide
|
|
368
|
+
- **[UTILS.md](./UTILS.md)** - Utility modules for Node.js projects
|
|
369
|
+
|
package/UTILS.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Utility Modules
|
|
2
|
+
|
|
3
|
+
Kempo Server includes some utility modules that can be used in your own Node.js projects. These utilities are built and exported alongside the main server package.
|
|
4
|
+
|
|
5
|
+
> **Note:** These utilities are included here for convenience but may be moved to their own dedicated package in the future as more Node.js utilities are added.
|
|
6
|
+
|
|
7
|
+
## CLI Utilities
|
|
8
|
+
|
|
9
|
+
The CLI utilities provide simple command-line argument parsing functionality.
|
|
10
|
+
|
|
11
|
+
### Usage
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { getArgs } from 'kempo-server/utils/cli';
|
|
15
|
+
|
|
16
|
+
// Basic usage - get all arguments as key-value pairs
|
|
17
|
+
const args = getArgs();
|
|
18
|
+
console.log(args); // { port: '3000', host: 'localhost', verbose: true }
|
|
19
|
+
|
|
20
|
+
// With mapping - map short flags to full names
|
|
21
|
+
const args = getArgs({
|
|
22
|
+
'p': 'port',
|
|
23
|
+
'h': 'host',
|
|
24
|
+
'v': 'verbose'
|
|
25
|
+
});
|
|
26
|
+
console.log(args); // Maps -p to port, -h to host, -v to verbose
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Example
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node myapp.js --port 8080 -h 127.0.0.1 --verbose
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { getArgs } from 'kempo-server/utils/cli';
|
|
37
|
+
|
|
38
|
+
const args = getArgs({
|
|
39
|
+
'h': 'host',
|
|
40
|
+
'p': 'port',
|
|
41
|
+
'v': 'verbose'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Results in:
|
|
45
|
+
// {
|
|
46
|
+
// host: '127.0.0.1',
|
|
47
|
+
// port: '8080',
|
|
48
|
+
// verbose: true
|
|
49
|
+
// }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## File System Utilities
|
|
53
|
+
|
|
54
|
+
The file system utilities provide common file and directory operations with Promise-based APIs.
|
|
55
|
+
|
|
56
|
+
### Usage
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { ensureDir, copyDir } from 'kempo-server/utils/fs-utils';
|
|
60
|
+
|
|
61
|
+
// Ensure a directory exists (creates all parent directories if needed)
|
|
62
|
+
await ensureDir('./my/nested/directory');
|
|
63
|
+
|
|
64
|
+
// Copy an entire directory structure recursively
|
|
65
|
+
await copyDir('./source', './destination');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Functions
|
|
69
|
+
|
|
70
|
+
#### `ensureDir(dirPath)`
|
|
71
|
+
|
|
72
|
+
Ensures that a directory exists, creating it and any necessary parent directories if they don't exist. Similar to `mkdir -p`.
|
|
73
|
+
|
|
74
|
+
- **Parameters:**
|
|
75
|
+
- `dirPath` (string) - The directory path to ensure exists
|
|
76
|
+
- **Returns:** Promise that resolves when the directory is confirmed to exist
|
|
77
|
+
|
|
78
|
+
#### `copyDir(srcPath, destPath)`
|
|
79
|
+
|
|
80
|
+
Recursively copies an entire directory structure from source to destination.
|
|
81
|
+
|
|
82
|
+
- **Parameters:**
|
|
83
|
+
- `srcPath` (string) - The source directory to copy from
|
|
84
|
+
- `destPath` (string) - The destination directory to copy to
|
|
85
|
+
- **Returns:** Promise that resolves when the copy operation is complete
|
|
86
|
+
|
|
87
|
+
### Example Use Cases
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
import { ensureDir, copyDir } from 'kempo-server/utils/fs-utils';
|
|
91
|
+
|
|
92
|
+
// Build script example
|
|
93
|
+
async function buildProject() {
|
|
94
|
+
// Ensure build directories exist
|
|
95
|
+
await ensureDir('./dist/assets');
|
|
96
|
+
await ensureDir('./dist/components');
|
|
97
|
+
|
|
98
|
+
// Copy static assets
|
|
99
|
+
await copyDir('./src/assets', './dist/assets');
|
|
100
|
+
await copyDir('./src/public', './dist');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Backup script example
|
|
104
|
+
async function backupProject() {
|
|
105
|
+
const timestamp = new Date().toISOString().slice(0, 10);
|
|
106
|
+
const backupPath = `./backups/${timestamp}`;
|
|
107
|
+
|
|
108
|
+
await ensureDir(backupPath);
|
|
109
|
+
await copyDir('./src', `${backupPath}/src`);
|
|
110
|
+
await copyDir('./config', `${backupPath}/config`);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Installation and Build
|
|
115
|
+
|
|
116
|
+
These utilities are automatically built when you install kempo-server. They're available through the package's exports:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"exports": {
|
|
121
|
+
"./utils/cli": "./dist/utils/cli.js",
|
|
122
|
+
"./utils/fs-utils": "./dist/utils/fs-utils.js"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The utilities are ES modules and require Node.js environments that support ES module imports.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{spawn}from"child_process";import readline from"readline";export const getArgs=(mapping={})=>{const args={};let name="",values=[];const save=()=>{name&&(0===values.length?args[name]=!0:1===values.length?"false"===values[0]?args[name]=!1:args[name]=values[0]:args[name]=values)};for(let i=2;i<process.argv.length;i++){const arg=process.argv[i];arg.startsWith("-")?(save(),arg.startsWith("--")?name=arg.slice(2):(name=arg.slice(1),mapping[name]&&(name=mapping[name])),values=[]):values.push(arg)}return save(),args};export const runChildProcess=command=>new Promise((resolve,reject)=>{const[cmd,...args]=command.split(" "),child=spawn(cmd,args,{stdio:"inherit",shell:!0});child.on("close",code=>{0===code?resolve(`child process exited with code ${code}`):reject(new Error(`child process exited with code ${code}`))}),child.on("error",reject)});export const runChildNodeProcess=(scriptPath,argsObj={})=>{const command=`node ${scriptPath} ${Object.entries(argsObj).flatMap(([key,value])=>!0===value?[`--${key}`]:[`--${key}`,value]).join(" ")}`;return runChildProcess(command)};export const runChildNodeProcessScript=scriptPath=>{const child=spawn("node",[scriptPath],{stdio:"inherit",shell:!0});return new Promise((resolve,reject)=>{child.on("close",code=>{0===code?resolve():reject(new Error(`Process exited with code ${code}`))}),child.on("error",reject)})};export const promptUser=query=>{const rl=readline.createInterface({input:process.stdin,output:process.stdout});return new Promise(resolve=>{rl.question(`${query}: `,answer=>{rl.close(),resolve(answer)})})};export const promptYN=(query,defaultValue="y")=>promptUser(`${query} (${"y"===defaultValue?"Y/n":"y/N"}): `).then(answer=>{const normalizedAnswer=answer.trim().toLowerCase();return""===normalizedAnswer?"y"===defaultValue:"y"===normalizedAnswer});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import fs from"fs/promises";import path from"path";export const ensureDir=async dirPath=>{try{await fs.mkdir(dirPath,{recursive:!0})}catch(error){if("EEXIST"!==error.code)throw error}};export const copyDir=async(src,dest)=>{await ensureDir(dest);const entries=await fs.readdir(src,{withFileTypes:!0});for(const entry of entries){const srcPath=path.join(src,entry.name),destPath=path.join(dest,entry.name);entry.isDirectory()?await copyDir(srcPath,destPath):await fs.copyFile(srcPath,destPath)}};export const emptyDir=async dirPath=>{try{const entries=await fs.readdir(dirPath);await Promise.all(entries.map(entry=>fs.rm(path.join(dirPath,entry),{recursive:!0,force:!0})))}catch(error){if("ENOENT"!==error.code)throw error}};
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kempo-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.6",
|
|
5
5
|
"description": "A lightweight, zero-dependency, file based routing server.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./utils/cli": "./dist/utils/cli.js",
|
|
10
|
+
"./utils/fs-utils": "./dist/utils/fs-utils.js"
|
|
11
|
+
},
|
|
7
12
|
"bin": {
|
|
8
13
|
"kempo-server": "./dist/index.js"
|
|
9
14
|
},
|
|
10
15
|
"scripts": {
|
|
11
16
|
"build": "node scripts/build.js",
|
|
12
|
-
"
|
|
17
|
+
"docs": "node dist/index.js -r ./docs",
|
|
13
18
|
"tests": "npx kempo-test",
|
|
14
19
|
"tests:gui": "npx kempo-test --gui",
|
|
15
20
|
"tests:browser": "npx kempo-test -b",
|