kempo-server 2.2.0 → 3.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.
Files changed (62) hide show
  1. package/CONFIG.md +295 -187
  2. package/README.md +5 -4
  3. package/SPA.md +14 -14
  4. package/dist/defaultConfig.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/render.js +2 -0
  7. package/dist/router.js +1 -1
  8. package/dist/serveFile.js +1 -1
  9. package/dist/templating/index.js +1 -0
  10. package/dist/templating/parse.js +1 -0
  11. package/docs/caching.html +103 -17
  12. package/docs/cli-utils.html +102 -16
  13. package/docs/configuration.html +104 -17
  14. package/docs/examples.html +104 -17
  15. package/docs/fs-utils.html +102 -16
  16. package/docs/getting-started.html +104 -17
  17. package/docs/index.html +176 -81
  18. package/docs/middleware.html +104 -17
  19. package/docs/request-response.html +104 -17
  20. package/docs/routing.html +104 -17
  21. package/docs/templating.html +292 -0
  22. package/docs-src/.config.js +11 -0
  23. package/docs-src/caching.page.html +220 -0
  24. package/docs-src/cli-utils.page.html +71 -0
  25. package/docs-src/configuration.page.html +310 -0
  26. package/docs-src/default.template.html +35 -0
  27. package/docs-src/examples.page.html +192 -0
  28. package/docs-src/fs-utils.page.html +102 -0
  29. package/docs-src/getting-started.page.html +63 -0
  30. package/docs-src/index.page.html +79 -0
  31. package/docs-src/middleware.page.html +133 -0
  32. package/docs-src/nav.fragment.html +73 -0
  33. package/docs-src/request-response.page.html +96 -0
  34. package/docs-src/routing.page.html +73 -0
  35. package/docs-src/templating.page.html +188 -0
  36. package/llms.txt +97 -31
  37. package/package.json +5 -2
  38. package/scripts/build.js +22 -1
  39. package/scripts/render.js +58 -0
  40. package/src/defaultConfig.js +14 -2
  41. package/src/index.js +1 -1
  42. package/src/router.js +69 -10
  43. package/src/serveFile.js +27 -0
  44. package/src/templating/index.js +132 -0
  45. package/src/templating/parse.js +285 -0
  46. package/tests/cacheConfig.node-test.js +2 -2
  47. package/tests/config-flag.node-test.js +61 -25
  48. package/tests/customRoute-outside-root.node-test.js +1 -1
  49. package/tests/router-wildcard.node-test.js +47 -2
  50. package/tests/templating-parse.node-test.js +243 -0
  51. package/tests/templating-render.node-test.js +188 -0
  52. package/tests/utils/test-scenario.js +4 -4
  53. package/docs/.config.json.example +0 -29
  54. package/docs/api/_admin/cache/DELETE.js +0 -28
  55. package/docs/api/_admin/cache/GET.js +0 -53
  56. package/docs/api/user/[id]/GET.js +0 -15
  57. package/docs/api/user/[id]/[info]/DELETE.js +0 -12
  58. package/docs/api/user/[id]/[info]/GET.js +0 -17
  59. package/docs/api/user/[id]/[info]/POST.js +0 -18
  60. package/docs/api/user/[id]/[info]/PUT.js +0 -19
  61. package/docs/init.js +0 -2
  62. package/docs/nav.inc.html +0 -70
package/CONFIG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Configuration
2
2
 
3
- To configure the server, create a configuration file (by default `.config.json`) within the root directory of your server (`public` in the start example). You can specify a different configuration file using the `--config` flag.
3
+ To configure the server, create a configuration file (by default `.config.js`) within the root directory of your server (`public` in the start example). The server also supports `.config.json` as a fallback. You can specify a different configuration file using the `--config` flag.
4
4
 
5
5
  **Important:**
6
6
  - When using a relative path for the `--config` flag, the config file must be located within the server root directory
@@ -13,21 +13,31 @@ You can specify different configuration files for different environments using t
13
13
 
14
14
  ```bash
15
15
  # Development
16
- kempo-server --root public --config dev.config.json
16
+ kempo-server --root public --config dev.config.js
17
17
 
18
18
  # Staging
19
- kempo-server --root public --config staging.config.json
19
+ kempo-server --root public --config staging.config.js
20
20
 
21
21
  # Production with absolute path
22
- kempo-server --root public --config /etc/kempo/production.config.json
22
+ kempo-server --root public --config /etc/kempo/production.config.js
23
23
 
24
24
  # Mix with other options
25
- kempo-server --root dist --port 8080 --config production.config.json
25
+ kempo-server --root dist --port 8080 --config production.config.js
26
+
27
+ # JSON config files are also supported
28
+ kempo-server --root public --config legacy.config.json
26
29
  ```
27
30
 
28
31
  ## Configuration File Structure
29
32
 
30
- This json file can have any of the following properties, any property not defined will use the "Default Config".
33
+ The config file exports a default object with any of the following properties. Any property not defined will use the "Default Config".
34
+
35
+ ```javascript
36
+ // .config.js
37
+ export default {
38
+ // your config here
39
+ };
40
+ ```
31
41
 
32
42
  - [allowedMimes](#allowedmimes)
33
43
  - [disallowedRegex](#disallowedregex)
@@ -38,6 +48,7 @@ This json file can have any of the following properties, any property not define
38
48
  - [maxBodySize](#maxbodysize)
39
49
  - [cache](#cache)
40
50
  - [middleware](#middleware)
51
+ - [templating](#templating)
41
52
 
42
53
  ## Cache
43
54
 
@@ -50,18 +61,18 @@ Kempo Server includes an intelligent module caching system that dramatically imp
50
61
 
51
62
  ### Basic Cache Configuration
52
63
 
53
- Enable caching in your `.config.json`:
64
+ Enable caching in your `.config.js`:
54
65
 
55
- ```json
56
- {
57
- "cache": {
58
- "enabled": true,
59
- "maxSize": 100,
60
- "maxMemoryMB": 50,
61
- "ttlMs": 300000,
62
- "watchFiles": true
66
+ ```javascript
67
+ export default {
68
+ cache: {
69
+ enabled: true,
70
+ maxSize: 100,
71
+ maxMemoryMB: 50,
72
+ ttlMs: 300000,
73
+ watchFiles: true
63
74
  }
64
- }
75
+ };
65
76
  ```
66
77
 
67
78
  ### Cache Options
@@ -75,7 +86,7 @@ Enable caching in your `.config.json`:
75
86
  - `watchFiles` (boolean) - Auto-invalidate on file changes (default: `true`)
76
87
  - `enableMemoryMonitoring` (boolean) - Enable memory monitoring (default: `true`)
77
88
 
78
- Run with specific config: `kempo-server --config prod.config.json`
89
+ Run with specific config: `kempo-server --config prod.config.js`
79
90
 
80
91
  ### Cache Monitoring
81
92
 
@@ -105,92 +116,92 @@ Kempo Server includes a powerful middleware system that allows you to add functi
105
116
  #### CORS
106
117
  Enable Cross-Origin Resource Sharing for your API:
107
118
 
108
- ```json
109
- {
110
- "middleware": {
111
- "cors": {
112
- "enabled": true,
113
- "origin": "*",
114
- "methods": ["GET", "POST", "PUT", "DELETE"],
115
- "headers": ["Content-Type", "Authorization"]
119
+ ```javascript
120
+ export default {
121
+ middleware: {
122
+ cors: {
123
+ enabled: true,
124
+ origin: '*',
125
+ methods: ['GET', 'POST', 'PUT', 'DELETE'],
126
+ headers: ['Content-Type', 'Authorization']
116
127
  }
117
128
  }
118
- }
129
+ };
119
130
  ```
120
131
 
121
132
  #### Compression
122
133
  Automatically compress responses with gzip:
123
134
 
124
- ```json
125
- {
126
- "middleware": {
127
- "compression": {
128
- "enabled": true,
129
- "threshold": 1024
135
+ ```javascript
136
+ export default {
137
+ middleware: {
138
+ compression: {
139
+ enabled: true,
140
+ threshold: 1024
130
141
  }
131
142
  }
132
- }
143
+ };
133
144
  ```
134
145
 
135
146
  #### Rate Limiting
136
147
  Limit requests per client to prevent abuse:
137
148
 
138
- ```json
139
- {
140
- "middleware": {
141
- "rateLimit": {
142
- "enabled": true,
143
- "maxRequests": 100,
144
- "windowMs": 60000,
145
- "message": "Too many requests"
149
+ ```javascript
150
+ export default {
151
+ middleware: {
152
+ rateLimit: {
153
+ enabled: true,
154
+ maxRequests: 100,
155
+ windowMs: 60000,
156
+ message: 'Too many requests'
146
157
  }
147
158
  }
148
- }
159
+ };
149
160
  ```
150
161
 
151
162
  #### Security Headers
152
163
  Add security headers to all responses:
153
164
 
154
- ```json
155
- {
156
- "middleware": {
157
- "security": {
158
- "enabled": true,
159
- "headers": {
160
- "X-Content-Type-Options": "nosniff",
161
- "X-Frame-Options": "DENY",
162
- "X-XSS-Protection": "1; mode=block"
165
+ ```javascript
166
+ export default {
167
+ middleware: {
168
+ security: {
169
+ enabled: true,
170
+ headers: {
171
+ 'X-Content-Type-Options': 'nosniff',
172
+ 'X-Frame-Options': 'DENY',
173
+ 'X-XSS-Protection': '1; mode=block'
163
174
  }
164
175
  }
165
176
  }
166
- }
177
+ };
167
178
  ```
168
179
 
169
180
  #### Request Logging
170
181
  Log requests with configurable detail:
171
182
 
172
- ```json
173
- {
174
- "middleware": {
175
- "logging": {
176
- "enabled": true,
177
- "includeUserAgent": true,
178
- "includeResponseTime": true
183
+ ```javascript
184
+ export default {
185
+ middleware: {
186
+ logging: {
187
+ enabled: true,
188
+ includeUserAgent: true,
189
+ includeResponseTime: true
179
190
  }
180
191
  }
181
- }
192
+ };
182
193
  ```
183
194
 
184
195
  ### Custom Middleware
185
196
 
186
197
  Create your own middleware by writing JavaScript files and referencing them in your config:
187
198
 
188
- ```json
189
- {
190
- "middleware": {
191
- "custom": ["./middleware/auth.js", "./middleware/analytics.js"]
199
+ ```javascript
200
+ export default {
201
+ middleware: {
202
+ custom: ['./middleware/auth.js', './middleware/analytics.js']
192
203
  }
193
- }
204
+ };
194
205
  ```
195
206
 
196
207
  #### Custom Middleware Example
@@ -284,62 +295,62 @@ export default (config) => {
284
295
 
285
296
  An object mapping file extensions to their MIME types. Files with extensions not in this list will not be served.
286
297
 
287
- ```json
288
- {
289
- "allowedMimes": {
290
- "html": "text/html",
291
- "css": "text/css",
292
- "js": "application/javascript",
293
- "json": "application/json",
294
- "png": "image/png",
295
- "jpg": "image/jpeg"
298
+ ```javascript
299
+ export default {
300
+ allowedMimes: {
301
+ html: 'text/html',
302
+ css: 'text/css',
303
+ js: 'application/javascript',
304
+ json: 'application/json',
305
+ png: 'image/png',
306
+ jpg: 'image/jpeg'
296
307
  }
297
- }
308
+ };
298
309
  ```
299
310
 
300
311
  ### disallowedRegex
301
312
 
302
313
  An array of regular expressions that match paths that should never be served. This provides security by preventing access to sensitive files.
303
314
 
304
- ```json
305
- {
306
- "disallowedRegex": [
307
- "^/\\..*",
308
- "\\.env$",
309
- "\\.config$",
310
- "password"
315
+ ```javascript
316
+ export default {
317
+ disallowedRegex: [
318
+ '^/\\..*',
319
+ '\\.env$',
320
+ '\\.config$',
321
+ 'password'
311
322
  ]
312
- }
323
+ };
313
324
  ```
314
325
 
315
326
  ### routeFiles
316
327
 
317
328
  An array of filenames that should be treated as route handlers and executed as JavaScript modules.
318
329
 
319
- ```json
320
- {
321
- "routeFiles": [
322
- "GET.js",
323
- "POST.js",
324
- "PUT.js",
325
- "DELETE.js",
326
- "index.js"
330
+ ```javascript
331
+ export default {
332
+ routeFiles: [
333
+ 'GET.js',
334
+ 'POST.js',
335
+ 'PUT.js',
336
+ 'DELETE.js',
337
+ 'index.js'
327
338
  ]
328
- }
339
+ };
329
340
  ```
330
341
 
331
342
  ### noRescanPaths
332
343
 
333
344
  An array of regex patterns for paths that should not trigger a file system rescan. This improves performance for common static assets.
334
345
 
335
- ```json
336
- {
337
- "noRescanPaths": [
338
- "/favicon\\.ico$",
339
- "/robots\\.txt$",
340
- "\\.map$"
346
+ ```javascript
347
+ export default {
348
+ noRescanPaths: [
349
+ '/favicon\\.ico$',
350
+ '/robots\\.txt$',
351
+ '\\.map$'
341
352
  ]
342
- }
353
+ };
343
354
  ```
344
355
 
345
356
  ### customRoutes
@@ -349,27 +360,27 @@ An object mapping custom route paths to file paths. Useful for aliasing or servi
349
360
  **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.
350
361
 
351
362
  **Basic Routes:**
352
- ```json
353
- {
354
- "customRoutes": {
355
- "/vendor/bootstrap.css": "../node_modules/bootstrap/dist/css/bootstrap.min.css",
356
- "/api/status": "./status.js"
363
+ ```javascript
364
+ export default {
365
+ customRoutes: {
366
+ '/vendor/bootstrap.css': '../node_modules/bootstrap/dist/css/bootstrap.min.css',
367
+ '/api/status': './status.js'
357
368
  }
358
- }
369
+ };
359
370
  ```
360
371
 
361
372
  **Wildcard Routes:**
362
373
  Wildcard routes allow you to map entire directory structures using the `*` and `**` wildcards:
363
374
 
364
- ```json
365
- {
366
- "customRoutes": {
367
- "kempo/*": "../node_modules/kempo/dist/*",
368
- "assets/*": "../static-files/*",
369
- "docs/*": "../documentation/*",
370
- "src/**": "../src/**"
375
+ ```javascript
376
+ export default {
377
+ customRoutes: {
378
+ 'kempo/*': '../node_modules/kempo/dist/*',
379
+ 'assets/*': '../static-files/*',
380
+ 'docs/*': '../documentation/*',
381
+ 'src/**': '../src/**'
371
382
  }
372
- }
383
+ };
373
384
  ```
374
385
 
375
386
  With wildcard routes:
@@ -398,123 +409,220 @@ If the resolved path is a file whose name matches `routeFiles` (e.g. `GET.js`),
398
409
 
399
410
  The maximum number of times to attempt rescanning the file system when a file is not found. Defaults to 3.
400
411
 
401
- ```json
402
- {
403
- "maxRescanAttempts": 3
404
- }
412
+ ```javascript
413
+ export default {
414
+ maxRescanAttempts: 3
415
+ };
405
416
  ```
406
417
 
407
418
  ### maxBodySize
408
419
 
409
420
  Maximum allowed request body size in bytes. If a request body exceeds this limit, the server responds with `413 Payload Too Large` before the route handler runs. Defaults to `1048576` (1 MB).
410
421
 
411
- ```json
412
- {
413
- "maxBodySize": 1048576
414
- }
422
+ ```javascript
423
+ export default {
424
+ maxBodySize: 1048576
425
+ };
415
426
  ```
416
427
 
428
+ ### templating
429
+
430
+ The templating system lets you build HTML pages from reusable templates, fragments, and content blocks using valid XML syntax. Files use the conventions `*.template.html`, `*.page.html`, and `*.fragment.html`.
431
+
432
+ ```javascript
433
+ export default {
434
+ templating: {
435
+ preRender: false,
436
+ ssr: false,
437
+ globals: {},
438
+ state: {},
439
+ maxFragmentDepth: 10
440
+ }
441
+ };
442
+ ```
443
+
444
+ - `preRender` (boolean) - Render all `.page.html` files to `.html` on server start (default: `false`)
445
+ - `ssr` (boolean) - Render `.page.html` files on-the-fly when the corresponding `.html` file is not found (default: `false`)
446
+ - `globals` (object) - Variables available in all templates. Values can be functions (called with no args at render time).
447
+ - `state` (object) - Additional variables, typically CMS data. Merged after globals so state overrides globals.
448
+ - `maxFragmentDepth` (number) - Maximum nesting depth for fragment includes (default: `10`)
449
+
450
+ #### Pre-Render Mode
451
+
452
+ With `preRender: true`, the server renders all page files when it starts or rescans. This is ideal for static sites.
453
+
454
+ ```javascript
455
+ export default {
456
+ templating: {
457
+ preRender: true,
458
+ globals: {
459
+ siteName: 'My Site',
460
+ year: () => String(new Date().getFullYear())
461
+ }
462
+ }
463
+ };
464
+ ```
465
+
466
+ #### SSR Mode
467
+
468
+ With `ssr: true`, when a request comes in for `/about` and `about.html` does not exist but `about.page.html` does, the server renders it on-the-fly.
469
+
470
+ ```javascript
471
+ export default {
472
+ templating: {
473
+ ssr: true,
474
+ globals: {
475
+ siteName: 'My Site'
476
+ },
477
+ state: {
478
+ currentUser: 'Guest'
479
+ }
480
+ }
481
+ };
482
+ ```
483
+
484
+ #### CLI Rendering
485
+
486
+ You can also render pages without starting the server using the CLI script:
487
+
488
+ ```bash
489
+ kempo-render <inputDir> [outputDir] [stateFile]
490
+ ```
491
+
492
+ The script loads `.config.js` (or `.config.json`) from the input directory for `templating.globals`, `templating.state`, and `templating.maxFragmentDepth`. An optional state file (`.js` or `.json`) merges additional state variables.
493
+
494
+ #### Templating File Conventions
495
+
496
+ - **Templates** (`*.template.html`): Layout files with `<location>` placeholders
497
+ - **Pages** (`*.page.html`): Content files wrapped in `<page template="...">` with `<content location="...">` blocks
498
+ - **Fragments** (`*.fragment.html`): Reusable HTML snippets included via `<fragment name="..." />`
499
+
500
+ #### Built-in Variables
501
+
502
+ These variables are available in all templates:
503
+ - `{{pathToRoot}}` - Relative path to the root directory (e.g. `../../`)
504
+ - `{{year}}` - Current four-digit year
505
+ - `{{date}}` - Current date in ISO format (YYYY-MM-DD)
506
+ - `{{datetime}}` - Full ISO datetime string
507
+ - `{{timestamp}}` - Unix timestamp
508
+ - `{{version}}` - Version from `package.json`
509
+ - `{{env}}` - Value of `NODE_ENV`
510
+
511
+ #### Conditionals and Loops
512
+
513
+ ```html
514
+ <if condition="env === 'development'">
515
+ <p>Debug mode</p>
516
+ </if>
517
+
518
+ <foreach in="items" as="item">
519
+ <li>{{item.name}}</li>
520
+ </foreach>
521
+ ```
522
+
523
+ Conditions support `===`, `!==`, `>`, `<`, `>=`, `<=`, `&&`, `||`, `!`, parentheses, string/number/boolean literals, and dot-path variable references.
524
+
417
525
  ## Configuration Examples
418
526
 
419
527
  ### Development Environment
420
528
 
421
529
  **Focus: Fast iteration and debugging**
422
- ```json
423
- {
424
- "cache": {
425
- "enabled": true,
426
- "maxSize": 50,
427
- "ttlMs": 300000,
428
- "watchFiles": true
530
+ ```javascript
531
+ export default {
532
+ cache: {
533
+ enabled: true,
534
+ maxSize: 50,
535
+ ttlMs: 300000,
536
+ watchFiles: true
429
537
  },
430
- "middleware": {
431
- "cors": {
432
- "enabled": true,
433
- "origin": "*"
538
+ middleware: {
539
+ cors: {
540
+ enabled: true,
541
+ origin: '*'
434
542
  },
435
- "logging": {
436
- "enabled": true,
437
- "includeUserAgent": true,
438
- "includeResponseTime": true
543
+ logging: {
544
+ enabled: true,
545
+ includeUserAgent: true,
546
+ includeResponseTime: true
439
547
  }
440
548
  }
441
- }
549
+ };
442
550
  ```
443
551
 
444
552
  ### Production Environment
445
553
 
446
554
  **Focus: Performance, security, and stability**
447
- ```json
448
- {
449
- "cache": {
450
- "enabled": true,
451
- "maxSize": 1000,
452
- "maxMemoryMB": 200,
453
- "ttlMs": 3600000,
454
- "maxHeapUsagePercent": 85,
455
- "memoryCheckInterval": 60000,
456
- "watchFiles": false
555
+ ```javascript
556
+ export default {
557
+ cache: {
558
+ enabled: true,
559
+ maxSize: 1000,
560
+ maxMemoryMB: 200,
561
+ ttlMs: 3600000,
562
+ maxHeapUsagePercent: 85,
563
+ memoryCheckInterval: 60000,
564
+ watchFiles: false
457
565
  },
458
- "middleware": {
459
- "cors": {
460
- "enabled": true,
461
- "origin": ["https://myapp.com", "https://www.myapp.com"],
462
- "credentials": true
566
+ middleware: {
567
+ cors: {
568
+ enabled: true,
569
+ origin: ['https://myapp.com', 'https://www.myapp.com'],
570
+ credentials: true
463
571
  },
464
- "compression": {
465
- "enabled": true,
466
- "threshold": 1024
572
+ compression: {
573
+ enabled: true,
574
+ threshold: 1024
467
575
  },
468
- "security": {
469
- "enabled": true,
470
- "headers": {
471
- "X-Content-Type-Options": "nosniff",
472
- "X-Frame-Options": "DENY",
473
- "X-XSS-Protection": "1; mode=block",
474
- "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
576
+ security: {
577
+ enabled: true,
578
+ headers: {
579
+ 'X-Content-Type-Options': 'nosniff',
580
+ 'X-Frame-Options': 'DENY',
581
+ 'X-XSS-Protection': '1; mode=block',
582
+ 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
475
583
  }
476
584
  },
477
- "logging": {
478
- "enabled": true,
479
- "includeUserAgent": false,
480
- "includeResponseTime": true
585
+ logging: {
586
+ enabled: true,
587
+ includeUserAgent: false,
588
+ includeResponseTime: true
481
589
  }
482
590
  }
483
- }
591
+ };
484
592
  ```
485
593
 
486
594
  ### Low-Memory Environment
487
595
 
488
596
  **Focus: Minimal resource usage**
489
- ```json
490
- {
491
- "cache": {
492
- "enabled": true,
493
- "maxSize": 20,
494
- "maxMemoryMB": 5,
495
- "ttlMs": 120000,
496
- "maxHeapUsagePercent": 60,
497
- "memoryCheckInterval": 10000
597
+ ```javascript
598
+ export default {
599
+ cache: {
600
+ enabled: true,
601
+ maxSize: 20,
602
+ maxMemoryMB: 5,
603
+ ttlMs: 120000,
604
+ maxHeapUsagePercent: 60,
605
+ memoryCheckInterval: 10000
498
606
  }
499
- }
607
+ };
500
608
  ```
501
609
 
502
610
  ### Debugging Environment
503
611
 
504
612
  **Focus: Cache disabled for troubleshooting**
505
- ```json
506
- {
507
- "cache": {
508
- "enabled": false
613
+ ```javascript
614
+ export default {
615
+ cache: {
616
+ enabled: false
509
617
  },
510
- "middleware": {
511
- "logging": {
512
- "enabled": true,
513
- "includeUserAgent": true,
514
- "includeResponseTime": true
618
+ middleware: {
619
+ logging: {
620
+ enabled: true,
621
+ includeUserAgent: true,
622
+ includeResponseTime: true
515
623
  }
516
624
  }
517
- }
625
+ };
518
626
  ```
519
627
 
520
628
  ## Additional Resources