lieko-express 0.0.3 → 0.0.5
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 +458 -18
- package/lieko-express.d.ts +264 -0
- package/lieko-express.js +488 -126
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -311,7 +311,7 @@ app.use((req, res, next) => {
|
|
|
311
311
|
next();
|
|
312
312
|
});
|
|
313
313
|
|
|
314
|
-
// CORS middleware
|
|
314
|
+
// CORS middleware (native, but you can use app.cors())
|
|
315
315
|
app.use((req, res, next) => {
|
|
316
316
|
res.set('Access-Control-Allow-Origin', '*');
|
|
317
317
|
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
|
|
@@ -382,6 +382,380 @@ app.use(async (req, res, next) => {
|
|
|
382
382
|
});
|
|
383
383
|
```
|
|
384
384
|
|
|
385
|
+
# **CORS**
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
Lieko-Express includes a **fully built-in, high-performance CORS engine**, with:
|
|
389
|
+
|
|
390
|
+
* Global CORS (`app.cors()`)
|
|
391
|
+
* Route-level CORS (`app.get("/test", { cors: {...} }, handler)`—coming soon if you want it)
|
|
392
|
+
* Wildcard origins (`https://*.example.com`)
|
|
393
|
+
* Multiple allowed origins
|
|
394
|
+
* Strict mode (reject unknown origins)
|
|
395
|
+
* Credential support
|
|
396
|
+
* Private Network Access (Chrome PNA)
|
|
397
|
+
* Debug logging
|
|
398
|
+
* Full OPTIONS preflight support
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
# **Enable CORS Globally**
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
app.cors();
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
This enables default permissive CORS:
|
|
409
|
+
|
|
410
|
+
| Option | Default |
|
|
411
|
+
| --------------------- | ----------------------------- |
|
|
412
|
+
| `origin` | `"*"` |
|
|
413
|
+
| `methods` | all standard methods |
|
|
414
|
+
| `headers` | `Content-Type, Authorization` |
|
|
415
|
+
| `credentials` | false |
|
|
416
|
+
| `maxAge` | 86400 (24h) |
|
|
417
|
+
| `exposedHeaders` | none |
|
|
418
|
+
| `strictOrigin` | false |
|
|
419
|
+
| `allowPrivateNetwork` | false |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
# **Custom Global CORS Options**
|
|
424
|
+
|
|
425
|
+
```js
|
|
426
|
+
app.cors({
|
|
427
|
+
origin: ["https://example.com", "https://api.example.com"],
|
|
428
|
+
methods: ["GET", "POST"],
|
|
429
|
+
headers: ["Content-Type", "Authorization", "X-Custom"],
|
|
430
|
+
credentials: true,
|
|
431
|
+
maxAge: 3600,
|
|
432
|
+
exposedHeaders: ["X-RateLimit-Remaining"],
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
# **Allow All Origins (Standard Mode)**
|
|
439
|
+
|
|
440
|
+
```js
|
|
441
|
+
app.cors({
|
|
442
|
+
origin: "*"
|
|
443
|
+
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
⚠️ If you also set `credentials: true`, browsers will **reject** `*`.
|
|
447
|
+
Lieko will still output `*` because that's the correct spec behavior.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
# **Strict Origin Mode**
|
|
452
|
+
|
|
453
|
+
Strict mode ensures the incoming `Origin` header **must match exactly** one of your allowed origins.
|
|
454
|
+
|
|
455
|
+
```js
|
|
456
|
+
app.cors({
|
|
457
|
+
origin: ["https://myapp.com"],
|
|
458
|
+
strictOrigin: true
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
If the request comes from an unauthorized origin:
|
|
463
|
+
|
|
464
|
+
```json
|
|
465
|
+
HTTP 403
|
|
466
|
+
{
|
|
467
|
+
"success": false,
|
|
468
|
+
"error": "Origin Forbidden",
|
|
469
|
+
"message": "Origin \"https://evil.com\" is not allowed"
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
# **Wildcard Origins**
|
|
476
|
+
|
|
477
|
+
Lieko-Express supports Express-style wildcard patterns:
|
|
478
|
+
|
|
479
|
+
### Allow any subdomain
|
|
480
|
+
|
|
481
|
+
```js
|
|
482
|
+
app.cors({
|
|
483
|
+
origin: "https://*.example.com"
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Matches:
|
|
488
|
+
|
|
489
|
+
* `https://api.example.com`
|
|
490
|
+
* `https://dashboard.example.com`
|
|
491
|
+
|
|
492
|
+
Does not match:
|
|
493
|
+
|
|
494
|
+
* `http://example.com`
|
|
495
|
+
* `https://example.net`
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
# **Allow Private Network Access (Chrome PNA)**
|
|
500
|
+
|
|
501
|
+
```js
|
|
502
|
+
app.cors({
|
|
503
|
+
allowPrivateNetwork: true
|
|
504
|
+
});
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
When Chrome sends:
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
Access-Control-Request-Private-Network: true
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Lieko automatically responds:
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
Access-Control-Allow-Private-Network: true
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
# Route-Level CORS
|
|
520
|
+
|
|
521
|
+
Lieko-Express allows each route to override or extend the global CORS settings using a `cors` property in the route options.
|
|
522
|
+
This gives you fine-grained control over cross-origin behavior on a per-endpoint basis.
|
|
523
|
+
|
|
524
|
+
Route-level CORS:
|
|
525
|
+
|
|
526
|
+
* Overrides global CORS
|
|
527
|
+
* Supports wildcards (`https://*.example.com`)
|
|
528
|
+
* Supports strict mode
|
|
529
|
+
* Sends its own preflight response
|
|
530
|
+
* Automatically merges with the global configuration
|
|
531
|
+
* Does **not** affect other routes
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Basic Example
|
|
536
|
+
|
|
537
|
+
```js
|
|
538
|
+
app.get("/public", {
|
|
539
|
+
cors: { origin: "*" }
|
|
540
|
+
}, (req, res) => {
|
|
541
|
+
res.ok("Public endpoint with open CORS");
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
This route allows requests from **any origin**, even if global CORS is configured differently.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## 🔒 Restrict a Sensitive Route
|
|
550
|
+
|
|
551
|
+
```js
|
|
552
|
+
app.post("/admin/login", {
|
|
553
|
+
cors: {
|
|
554
|
+
origin: "https://dashboard.myapp.com",
|
|
555
|
+
credentials: true,
|
|
556
|
+
strictOrigin: true
|
|
557
|
+
}
|
|
558
|
+
}, (req, res) => {
|
|
559
|
+
res.ok("Login OK");
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Result:
|
|
564
|
+
|
|
565
|
+
* Only `https://dashboard.myapp.com` is allowed
|
|
566
|
+
* Cookies / sessions allowed
|
|
567
|
+
* Any other origin receives:
|
|
568
|
+
|
|
569
|
+
```json
|
|
570
|
+
{
|
|
571
|
+
"success": false,
|
|
572
|
+
"error": "Origin Forbidden",
|
|
573
|
+
"message": "Origin \"https://evil.com\" is not allowed"
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Status: **403 Forbidden**
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## ✨ Wildcard Origins on a Route
|
|
582
|
+
|
|
583
|
+
```js
|
|
584
|
+
app.get("/api/data", {
|
|
585
|
+
cors: {
|
|
586
|
+
origin: "https://*.example.com"
|
|
587
|
+
}
|
|
588
|
+
}, (req, res) => {
|
|
589
|
+
res.ok({ data: 123 });
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
Matches:
|
|
594
|
+
|
|
595
|
+
* `https://api.example.com`
|
|
596
|
+
* `https://dashboard.example.com`
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## ⚙️ Full Route-Level CORS Example
|
|
601
|
+
|
|
602
|
+
```js
|
|
603
|
+
app.get("/user/profile", {
|
|
604
|
+
cors: {
|
|
605
|
+
origin: [
|
|
606
|
+
"https://app.example.com",
|
|
607
|
+
"https://*.trusted.dev"
|
|
608
|
+
],
|
|
609
|
+
methods: ["GET", "PATCH"],
|
|
610
|
+
headers: ["Content-Type", "Authorization"],
|
|
611
|
+
exposedHeaders: ["X-User-Id"],
|
|
612
|
+
credentials: true,
|
|
613
|
+
maxAge: 600,
|
|
614
|
+
strictOrigin: true,
|
|
615
|
+
allowPrivateNetwork: true,
|
|
616
|
+
debug: true
|
|
617
|
+
}
|
|
618
|
+
}, (req, res) => {
|
|
619
|
+
res.ok({ profile: "OK" });
|
|
620
|
+
});
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
## 📌 How Route-Level CORS Works Internally
|
|
626
|
+
|
|
627
|
+
When a request hits a route:
|
|
628
|
+
|
|
629
|
+
1. If global CORS is enabled → apply it.
|
|
630
|
+
2. If the route defines `cors` → merge with global config.
|
|
631
|
+
3. Route CORS **overrides** global CORS.
|
|
632
|
+
4. If request is `OPTIONS` (preflight) → return automatic CORS response.
|
|
633
|
+
5. Otherwise → run route handler.
|
|
634
|
+
|
|
635
|
+
This ensures predictable behavior.
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## 📘 Route-Level CORS Options
|
|
640
|
+
|
|
641
|
+
| Option | Type | Description | |
|
|
642
|
+
| --------------------- | ---------- | ---------------------------------------- | ---------------------------------------- |
|
|
643
|
+
| `origin` | `string | string[]` | Allowed origins (`*`, domain, wildcard). |
|
|
644
|
+
| `methods` | `string[]` | Allowed HTTP methods. | |
|
|
645
|
+
| `headers` | `string[]` | Allowed request headers. | |
|
|
646
|
+
| `exposedHeaders` | `string[]` | Response headers exposed to the browser. | |
|
|
647
|
+
| `credentials` | `boolean` | Allow cookies/sessions. | |
|
|
648
|
+
| `maxAge` | `number` | Preflight cache lifetime (seconds). | |
|
|
649
|
+
| `strictOrigin` | `boolean` | Reject non-matching origins with 403. | |
|
|
650
|
+
| `allowPrivateNetwork` | `boolean` | Enables Chrome Private Network Access. | |
|
|
651
|
+
| `debug` | `boolean` | Logs detailed CORS decisions. | |
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## 🧩 Interaction with Global CORS
|
|
656
|
+
|
|
657
|
+
| Feature | Global | Route |
|
|
658
|
+
| ------------------ | ------ | ------------- |
|
|
659
|
+
| Origin | ✔ | ✔ (overrides) |
|
|
660
|
+
| Wildcards | ✔ | ✔ |
|
|
661
|
+
| Credentials | ✔ | ✔ |
|
|
662
|
+
| Strict Origin | ✔ | ✔ |
|
|
663
|
+
| Private Network | ✔ | ✔ |
|
|
664
|
+
| Debug Logging | ✔ | ✔ |
|
|
665
|
+
| Preflight Handling | ✔ | ✔ |
|
|
666
|
+
| Overrides Global | ❌ | ✔ |
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
# **Enable CORS Debug Logging**
|
|
672
|
+
|
|
673
|
+
```js
|
|
674
|
+
app.cors({
|
|
675
|
+
debug: true
|
|
676
|
+
});
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Console output example:
|
|
680
|
+
|
|
681
|
+
```
|
|
682
|
+
[CORS DEBUG]
|
|
683
|
+
Request: GET /users
|
|
684
|
+
Origin: https://app.example.com
|
|
685
|
+
Applied CORS Policy:
|
|
686
|
+
- Access-Control-Allow-Origin: https://app.example.com
|
|
687
|
+
- Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
|
|
688
|
+
- Access-Control-Allow-Headers: Content-Type, Authorization
|
|
689
|
+
- Max-Age: 86400
|
|
690
|
+
Simple request handled normally
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
# **Preflight Handling (OPTIONS)**
|
|
696
|
+
|
|
697
|
+
Lieko-Express automatically handles it:
|
|
698
|
+
|
|
699
|
+
### Request:
|
|
700
|
+
|
|
701
|
+
```
|
|
702
|
+
OPTIONS /login
|
|
703
|
+
Access-Control-Request-Method: POST
|
|
704
|
+
Access-Control-Request-Headers: Content-Type
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Lieko Response:
|
|
708
|
+
|
|
709
|
+
```
|
|
710
|
+
204 No Content
|
|
711
|
+
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
|
|
712
|
+
Access-Control-Allow-Headers: Content-Type, Authorization
|
|
713
|
+
Access-Control-Max-Age: 86400
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
# **Credentials Support**
|
|
719
|
+
|
|
720
|
+
```js
|
|
721
|
+
app.cors({
|
|
722
|
+
credentials: true,
|
|
723
|
+
origin: "https://myapp.com"
|
|
724
|
+
});
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Response contains:
|
|
728
|
+
|
|
729
|
+
```
|
|
730
|
+
Access-Control-Allow-Credentials: true
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
# **Disable CORS**
|
|
737
|
+
|
|
738
|
+
Just don’t call `app.cors()`.
|
|
739
|
+
CORS stays fully disabled.
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
# **Default CORS Configuration**
|
|
744
|
+
|
|
745
|
+
```js
|
|
746
|
+
this.corsOptions = {
|
|
747
|
+
enabled: false,
|
|
748
|
+
origin: "*",
|
|
749
|
+
strictOrigin: false,
|
|
750
|
+
allowPrivateNetwork: false,
|
|
751
|
+
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
752
|
+
headers: ["Content-Type", "Authorization"],
|
|
753
|
+
credentials: false,
|
|
754
|
+
maxAge: 86400,
|
|
755
|
+
exposedHeaders: [],
|
|
756
|
+
debug: false
|
|
757
|
+
};
|
|
758
|
+
```
|
|
385
759
|
|
|
386
760
|
# 🔍 Request Object
|
|
387
761
|
|
|
@@ -514,15 +888,83 @@ res.paginated(items, page, limit, total);
|
|
|
514
888
|
* Error code → HTTP mapping
|
|
515
889
|
* String errors also supported (`res.error("Invalid user")`)
|
|
516
890
|
|
|
517
|
-
|
|
891
|
+
---
|
|
892
|
+
# Body Parsing (JSON, URL-encoded, Multipart) — 100% Native, Zero Dependencies
|
|
893
|
+
|
|
894
|
+
Lieko Express ships with a **fast, secure, and fully native body parser** — no external packages, not even `body-parser`.
|
|
895
|
+
|
|
896
|
+
As soon as you create your app, body parsing is **automatically enabled**:
|
|
897
|
+
|
|
898
|
+
```js
|
|
899
|
+
const app = Lieko(); // Ready to handle JSON, form-data, files, etc.
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
### Default Limits
|
|
903
|
+
|
|
904
|
+
| Content-Type | Default Limit | Bytes |
|
|
905
|
+
|---------------------------------------|---------------|-------------------|
|
|
906
|
+
| `application/json` | **1mb** | ~1,048,576 bytes |
|
|
907
|
+
| `application/x-www-form-urlencoded` | **1mb** | ~1,048,576 bytes |
|
|
908
|
+
| `multipart/form-data` (file uploads) | **10mb** | ~10,485,760 bytes |
|
|
909
|
+
|
|
910
|
+
That’s already **10× more generous** than Express’s default 100kb!
|
|
911
|
+
|
|
912
|
+
### Change Limits — Three Super-Simple Ways
|
|
913
|
+
|
|
914
|
+
#### 1. Per content-type (most common)
|
|
915
|
+
|
|
916
|
+
```js
|
|
917
|
+
app.json({ limit: '100mb' }); // JSON payloads only
|
|
918
|
+
app.urlencoded({ limit: '50mb' }); // Classic HTML forms
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
#### 2. Global limit (JSON + urlencoded at once)
|
|
922
|
+
|
|
923
|
+
```js
|
|
924
|
+
app.bodyParser({ limit: '50mb' });
|
|
925
|
+
// Applies 50mb to both JSON and urlencoded bodies
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
#### 3. File upload limit (multipart/form-data)
|
|
929
|
+
|
|
930
|
+
```js
|
|
931
|
+
app.multipart({ limit: '500mb' }); // For very large file uploads
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
You can freely combine them:
|
|
935
|
+
|
|
936
|
+
```js
|
|
937
|
+
const app = Lieko();
|
|
938
|
+
|
|
939
|
+
app.json({ limit: '10mb' }); // Small, fast JSON APIs
|
|
940
|
+
app.urlencoded({ limit: '5mb' });
|
|
941
|
+
app.multipart({ limit: '1gb' }); // Allow huge file uploads
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
### Real-world Example
|
|
945
|
+
|
|
946
|
+
```js
|
|
947
|
+
const Lieko = require('lieko-express');
|
|
948
|
+
const app = Lieko();
|
|
949
|
+
|
|
950
|
+
// Accept reasonably large JSON payloads
|
|
951
|
+
app.json({ limit: '25mb' });
|
|
952
|
+
|
|
953
|
+
// Accept classic forms
|
|
954
|
+
app.urlencoded({ limit: '10mb' });
|
|
518
955
|
|
|
519
|
-
|
|
956
|
+
// Allow big file uploads (photos, videos, etc.)
|
|
957
|
+
app.multipart({ limit: '500mb' });
|
|
520
958
|
|
|
521
|
-
|
|
959
|
+
app.post('/upload', (req, res) => {
|
|
960
|
+
console.log('JSON body size :', Buffer.byteLength(JSON.stringify(req.body)), 'bytes');
|
|
961
|
+
console.log('Uploaded files :', Object.keys(req.files || {}));
|
|
522
962
|
|
|
523
|
-
|
|
963
|
+
res.ok({ received: true, files: req.files });
|
|
964
|
+
});
|
|
524
965
|
|
|
525
|
-
|
|
966
|
+
app.listen(3000);
|
|
967
|
+
```
|
|
526
968
|
|
|
527
969
|
Uploads end up in:
|
|
528
970
|
|
|
@@ -546,6 +988,12 @@ Query & body fields are **auto converted**:
|
|
|
546
988
|
"null" → null
|
|
547
989
|
```
|
|
548
990
|
|
|
991
|
+
|
|
992
|
+
**No `app.use(express.json())`, no `app.use(express.urlencoded())`, no extra dependencies** — everything works out of the box, blazing fast, and fully configurable in one line.
|
|
993
|
+
|
|
994
|
+
That’s the Lieko philosophy: **less boilerplate, more power**.
|
|
995
|
+
|
|
996
|
+
|
|
549
997
|
### Response Methods
|
|
550
998
|
|
|
551
999
|
```javascript
|
|
@@ -1577,6 +2025,7 @@ DEBUG REQUEST
|
|
|
1577
2025
|
→ Params: {"id":"42"}
|
|
1578
2026
|
→ Query: {"page":2,"active":true}
|
|
1579
2027
|
→ Body: {}
|
|
2028
|
+
→ Body Size: 0 bytes
|
|
1580
2029
|
→ Files:
|
|
1581
2030
|
---------------------------------------------
|
|
1582
2031
|
```
|
|
@@ -1649,9 +2098,9 @@ You can configure:
|
|
|
1649
2098
|
```js
|
|
1650
2099
|
app.set('trust proxy', value);
|
|
1651
2100
|
app.set('debug', boolean);
|
|
1652
|
-
app.set('x-powered-by',
|
|
1653
|
-
app.set('strictTrailingSlash',
|
|
1654
|
-
app.set('allowTrailingSlash',
|
|
2101
|
+
app.set('x-powered-by', boolean);
|
|
2102
|
+
app.set('strictTrailingSlash', boolean);
|
|
2103
|
+
app.set('allowTrailingSlash', boolean);
|
|
1655
2104
|
```
|
|
1656
2105
|
|
|
1657
2106
|
# 🌐 Trust Proxy & IP Parsing
|
|
@@ -1761,15 +2210,6 @@ function myPlugin(app) {
|
|
|
1761
2210
|
|
|
1762
2211
|
myPlugin(app);
|
|
1763
2212
|
```
|
|
1764
|
-
|
|
1765
|
-
## 🚀 Deploying Lieko Express
|
|
1766
|
-
|
|
1767
|
-
### Node.js (PM2)
|
|
1768
|
-
|
|
1769
|
-
```bash
|
|
1770
|
-
pm2 start app.js
|
|
1771
|
-
```
|
|
1772
|
-
|
|
1773
2213
|
## 📦 API Reference
|
|
1774
2214
|
|
|
1775
2215
|
### `Lieko()`
|