@je-es/server 0.0.4 → 0.0.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/README.md +295 -75
- package/dist/main.cjs +4 -4
- package/dist/main.cjs.map +1 -1
- package/dist/main.d.cts +90 -9
- package/dist/main.d.ts +90 -9
- package/dist/main.js +4 -4
- package/dist/main.js.map +1 -1
- package/package.json +49 -57
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<div align="center">
|
|
11
|
-
<img src="https://img.shields.io/badge/v-0.0.
|
|
11
|
+
<img src="https://img.shields.io/badge/v-0.0.6-black"/>
|
|
12
12
|
<a href="https://github.com/maysara-elshewehy">
|
|
13
13
|
</a>
|
|
14
14
|
<a href="https://github.com/je-es/server"> <img src="https://img.shields.io/badge/🔥-@je--es/server-black"/> </a>
|
|
@@ -95,39 +95,36 @@
|
|
|
95
95
|
- ### With Database
|
|
96
96
|
|
|
97
97
|
```typescript
|
|
98
|
-
import { server,
|
|
98
|
+
import { server, table, integer, text, primaryKey, notNull } from '@je-es/server';
|
|
99
99
|
|
|
100
|
-
// Define your schema
|
|
101
|
-
const users =
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
// Define your schema using the built-in schema builder
|
|
101
|
+
const users = table('users', [
|
|
102
|
+
primaryKey(integer('id'), true), // auto-increment primary key
|
|
103
|
+
notNull(text('name')),
|
|
104
|
+
notNull(text('email'))
|
|
105
|
+
]);
|
|
106
106
|
|
|
107
107
|
const app = server({
|
|
108
108
|
port : 3000,
|
|
109
109
|
database: {
|
|
110
|
-
connection : './my_app.db',
|
|
110
|
+
connection : './my_app.db', // File-based SQLite database
|
|
111
111
|
schema : { users }
|
|
112
112
|
},
|
|
113
113
|
routes : [
|
|
114
114
|
{
|
|
115
115
|
method : 'GET',
|
|
116
116
|
path : '/users',
|
|
117
|
-
handler :
|
|
118
|
-
const allUsers =
|
|
117
|
+
handler : (c) => {
|
|
118
|
+
const allUsers = c.db.all('users');
|
|
119
119
|
return c.json(allUsers);
|
|
120
120
|
}
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
method : 'POST',
|
|
124
124
|
path : '/users',
|
|
125
|
-
handler :
|
|
126
|
-
const newUser =
|
|
127
|
-
|
|
128
|
-
.values(c.body)
|
|
129
|
-
.returning();
|
|
130
|
-
return c.json(newUser[0]);
|
|
125
|
+
handler : (c) => {
|
|
126
|
+
const newUser = c.db.insert('users', c.body);
|
|
127
|
+
return c.json(newUser);
|
|
131
128
|
}
|
|
132
129
|
}
|
|
133
130
|
]
|
|
@@ -198,8 +195,7 @@
|
|
|
198
195
|
|
|
199
196
|
// Database
|
|
200
197
|
database: {
|
|
201
|
-
|
|
202
|
-
connection : ':memory:',
|
|
198
|
+
connection : ':memory:', // or file path like './app.db'
|
|
203
199
|
schema : {}
|
|
204
200
|
},
|
|
205
201
|
|
|
@@ -436,110 +432,334 @@
|
|
|
436
432
|
{
|
|
437
433
|
method : 'GET',
|
|
438
434
|
path : '/data',
|
|
439
|
-
handler :
|
|
435
|
+
handler : (c) => {
|
|
440
436
|
// Access default database
|
|
441
|
-
const users =
|
|
437
|
+
const users = c.db.all('users');
|
|
442
438
|
|
|
443
439
|
// Access named databases
|
|
444
440
|
const mainDb = app.db.get('default');
|
|
445
441
|
const analyticsDb = app.db.get('analytics');
|
|
446
442
|
|
|
447
|
-
|
|
443
|
+
const mainData = mainDb.all('some_table');
|
|
444
|
+
const analyticsData = analyticsDb.all('analytics_table');
|
|
445
|
+
|
|
446
|
+
return c.json({ users, mainData, analyticsData });
|
|
448
447
|
}
|
|
449
448
|
}
|
|
450
449
|
]
|
|
451
450
|
});
|
|
452
451
|
```
|
|
453
452
|
|
|
454
|
-
- ###
|
|
453
|
+
- ### Schema Definition
|
|
455
454
|
|
|
456
455
|
```typescript
|
|
457
456
|
import {
|
|
458
457
|
server,
|
|
459
|
-
|
|
458
|
+
table,
|
|
460
459
|
integer,
|
|
461
460
|
text,
|
|
462
461
|
real,
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
462
|
+
blob,
|
|
463
|
+
numeric,
|
|
464
|
+
primaryKey,
|
|
465
|
+
notNull,
|
|
466
|
+
unique,
|
|
467
|
+
defaultValue,
|
|
468
|
+
references
|
|
466
469
|
} from '@je-es/server';
|
|
467
470
|
|
|
468
|
-
// Define
|
|
469
|
-
const products =
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
471
|
+
// Define products table
|
|
472
|
+
const products = table('products', [
|
|
473
|
+
primaryKey(integer('id'), true), // Auto-increment primary key
|
|
474
|
+
notNull(text('name')),
|
|
475
|
+
text('description'),
|
|
476
|
+
notNull(real('price')),
|
|
477
|
+
defaultValue(integer('stock'), 0)
|
|
478
|
+
]);
|
|
479
|
+
|
|
480
|
+
// Define orders table with foreign key
|
|
481
|
+
const orders = table('orders', [
|
|
482
|
+
primaryKey(integer('id'), true),
|
|
483
|
+
notNull(integer('product_id')),
|
|
484
|
+
references(integer('product_id'), 'products', 'id'),
|
|
485
|
+
notNull(integer('quantity')),
|
|
486
|
+
defaultValue(text('status'), 'pending')
|
|
487
|
+
]);
|
|
476
488
|
|
|
477
489
|
const app = server({
|
|
478
490
|
database: {
|
|
479
491
|
connection: './store.db',
|
|
480
|
-
schema: { products }
|
|
492
|
+
schema: { products, orders }
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
- ### Database Operations
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
import { server, table, integer, text, primaryKey, notNull } from '@je-es/server';
|
|
501
|
+
|
|
502
|
+
const users = table('users', [
|
|
503
|
+
primaryKey(integer('id'), true),
|
|
504
|
+
notNull(text('name')),
|
|
505
|
+
notNull(text('email')),
|
|
506
|
+
integer('age')
|
|
507
|
+
]);
|
|
508
|
+
|
|
509
|
+
const app = server({
|
|
510
|
+
database: {
|
|
511
|
+
connection: './app.db',
|
|
512
|
+
schema: { users }
|
|
481
513
|
},
|
|
482
514
|
routes : [
|
|
515
|
+
// Get all records
|
|
483
516
|
{
|
|
484
517
|
method : 'GET',
|
|
485
|
-
path : '/
|
|
486
|
-
handler :
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
.where(and(
|
|
492
|
-
eq(products.stock, 0),
|
|
493
|
-
like(products.name, '%laptop%')
|
|
494
|
-
));
|
|
518
|
+
path : '/users',
|
|
519
|
+
handler : (c) => {
|
|
520
|
+
const allUsers = c.db.all('users');
|
|
521
|
+
return c.json(allUsers);
|
|
522
|
+
}
|
|
523
|
+
},
|
|
495
524
|
|
|
496
|
-
|
|
525
|
+
// Find by ID
|
|
526
|
+
{
|
|
527
|
+
method : 'GET',
|
|
528
|
+
path : '/users/:id',
|
|
529
|
+
handler : (c) => {
|
|
530
|
+
const user = c.db.findById('users', parseInt(c.params.id));
|
|
531
|
+
if (!user) return c.status(404).json({ error: 'Not found' });
|
|
532
|
+
return c.json(user);
|
|
497
533
|
}
|
|
498
534
|
},
|
|
535
|
+
|
|
536
|
+
// Find with conditions
|
|
499
537
|
{
|
|
500
|
-
method : '
|
|
501
|
-
path : '/
|
|
502
|
-
handler :
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
538
|
+
method : 'GET',
|
|
539
|
+
path : '/users/search',
|
|
540
|
+
handler : (c) => {
|
|
541
|
+
const users = c.db.find('users', {
|
|
542
|
+
name: c.query.name
|
|
543
|
+
});
|
|
544
|
+
return c.json(users);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
508
547
|
|
|
509
|
-
|
|
548
|
+
// Insert
|
|
549
|
+
{
|
|
550
|
+
method : 'POST',
|
|
551
|
+
path : '/users',
|
|
552
|
+
handler : (c) => {
|
|
553
|
+
const newUser = c.db.insert('users', c.body);
|
|
554
|
+
return c.json(newUser);
|
|
510
555
|
}
|
|
511
556
|
},
|
|
557
|
+
|
|
558
|
+
// Update
|
|
512
559
|
{
|
|
513
560
|
method : 'PUT',
|
|
514
|
-
path : '/
|
|
515
|
-
handler :
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
.
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
return c.json(updated[0]);
|
|
561
|
+
path : '/users/:id',
|
|
562
|
+
handler : (c) => {
|
|
563
|
+
const updated = c.db.update(
|
|
564
|
+
'users',
|
|
565
|
+
parseInt(c.params.id),
|
|
566
|
+
c.body
|
|
567
|
+
);
|
|
568
|
+
if (!updated) return c.status(404).json({ error: 'Not found' });
|
|
569
|
+
return c.json(updated);
|
|
524
570
|
}
|
|
525
571
|
},
|
|
572
|
+
|
|
573
|
+
// Delete
|
|
526
574
|
{
|
|
527
575
|
method : 'DELETE',
|
|
528
|
-
path : '/
|
|
529
|
-
handler :
|
|
530
|
-
|
|
531
|
-
await c.db
|
|
532
|
-
.delete(products)
|
|
533
|
-
.where(eq(products.id, parseInt(c.params.id)));
|
|
534
|
-
|
|
576
|
+
path : '/users/:id',
|
|
577
|
+
handler : (c) => {
|
|
578
|
+
c.db.delete('users', parseInt(c.params.id));
|
|
535
579
|
return c.json({ deleted: true });
|
|
536
580
|
}
|
|
537
581
|
}
|
|
538
582
|
]
|
|
539
583
|
});
|
|
584
|
+
```
|
|
540
585
|
|
|
541
|
-
|
|
542
|
-
|
|
586
|
+
- ### Query Builder
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
const app = server({
|
|
590
|
+
database: {
|
|
591
|
+
connection: './app.db',
|
|
592
|
+
schema: { users }
|
|
593
|
+
},
|
|
594
|
+
routes : [
|
|
595
|
+
{
|
|
596
|
+
method : 'GET',
|
|
597
|
+
path : '/advanced-search',
|
|
598
|
+
handler : (c) => {
|
|
599
|
+
// Complex queries with query builder
|
|
600
|
+
const results = c.db.query()
|
|
601
|
+
.select(['name', 'email', 'age'])
|
|
602
|
+
.from('users')
|
|
603
|
+
.where({
|
|
604
|
+
column: 'age',
|
|
605
|
+
operator: '>=',
|
|
606
|
+
value: 18
|
|
607
|
+
})
|
|
608
|
+
.and({
|
|
609
|
+
column: 'name',
|
|
610
|
+
operator: 'LIKE',
|
|
611
|
+
value: '%John%'
|
|
612
|
+
})
|
|
613
|
+
.orderBy('age', 'DESC')
|
|
614
|
+
.limit(10)
|
|
615
|
+
.offset(0)
|
|
616
|
+
.execute();
|
|
617
|
+
|
|
618
|
+
return c.json(results);
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
|
|
622
|
+
// Multiple where conditions
|
|
623
|
+
{
|
|
624
|
+
method : 'GET',
|
|
625
|
+
path : '/filter',
|
|
626
|
+
handler : (c) => {
|
|
627
|
+
const users = c.db.query()
|
|
628
|
+
.select()
|
|
629
|
+
.from('users')
|
|
630
|
+
.where([
|
|
631
|
+
{ column: 'age', operator: '>', value: 25 },
|
|
632
|
+
{ column: 'age', operator: '<', value: 50 }
|
|
633
|
+
])
|
|
634
|
+
.execute();
|
|
635
|
+
|
|
636
|
+
return c.json(users);
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
|
|
640
|
+
// OR conditions
|
|
641
|
+
{
|
|
642
|
+
method : 'GET',
|
|
643
|
+
path : '/or-search',
|
|
644
|
+
handler : (c) => {
|
|
645
|
+
const users = c.db.query()
|
|
646
|
+
.select()
|
|
647
|
+
.from('users')
|
|
648
|
+
.where({ column: 'name', operator: '=', value: 'John' })
|
|
649
|
+
.or({ column: 'name', operator: '=', value: 'Jane' })
|
|
650
|
+
.execute();
|
|
651
|
+
|
|
652
|
+
return c.json(users);
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
// Get single result
|
|
657
|
+
{
|
|
658
|
+
method : 'GET',
|
|
659
|
+
path : '/first-user',
|
|
660
|
+
handler : (c) => {
|
|
661
|
+
const user = c.db.query()
|
|
662
|
+
.select()
|
|
663
|
+
.from('users')
|
|
664
|
+
.limit(1)
|
|
665
|
+
.executeOne();
|
|
666
|
+
|
|
667
|
+
return c.json(user);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
]
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
- ### Transactions
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
const app = server({
|
|
678
|
+
database: {
|
|
679
|
+
connection: './app.db',
|
|
680
|
+
schema: { users, orders }
|
|
681
|
+
},
|
|
682
|
+
routes : [
|
|
683
|
+
{
|
|
684
|
+
method : 'POST',
|
|
685
|
+
path : '/place-order',
|
|
686
|
+
handler : (c) => {
|
|
687
|
+
try {
|
|
688
|
+
c.db.transaction((db) => {
|
|
689
|
+
// Insert order
|
|
690
|
+
const order = db.insert('orders', {
|
|
691
|
+
product_id: c.body.productId,
|
|
692
|
+
quantity: c.body.quantity
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Update product stock
|
|
696
|
+
const product = db.findById('products', c.body.productId);
|
|
697
|
+
db.update('products', c.body.productId, {
|
|
698
|
+
stock: product.stock - c.body.quantity
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
return c.json({ success: true });
|
|
703
|
+
} catch (error) {
|
|
704
|
+
return c.status(500).json({
|
|
705
|
+
error: 'Transaction failed'
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
]
|
|
711
|
+
});
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
- ### Raw SQL
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
const app = server({
|
|
718
|
+
database: {
|
|
719
|
+
connection: './app.db',
|
|
720
|
+
schema: { users }
|
|
721
|
+
},
|
|
722
|
+
routes : [
|
|
723
|
+
{
|
|
724
|
+
method : 'GET',
|
|
725
|
+
path : '/custom-query',
|
|
726
|
+
handler : (c) => {
|
|
727
|
+
// Execute raw SQL
|
|
728
|
+
const results = c.db.raw(
|
|
729
|
+
'SELECT * FROM users WHERE age > ? AND name LIKE ?',
|
|
730
|
+
[25, '%John%']
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
return c.json(results);
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
|
|
737
|
+
{
|
|
738
|
+
method : 'GET',
|
|
739
|
+
path : '/single-result',
|
|
740
|
+
handler : (c) => {
|
|
741
|
+
// Get single row
|
|
742
|
+
const user = c.db.rawOne(
|
|
743
|
+
'SELECT * FROM users WHERE id = ?',
|
|
744
|
+
[1]
|
|
745
|
+
);
|
|
746
|
+
|
|
747
|
+
return c.json(user);
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
{
|
|
752
|
+
method : 'POST',
|
|
753
|
+
path : '/execute-sql',
|
|
754
|
+
handler : (c) => {
|
|
755
|
+
// Execute without return
|
|
756
|
+
c.db.exec('DELETE FROM users WHERE age < 18');
|
|
757
|
+
|
|
758
|
+
return c.json({ success: true });
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
]
|
|
762
|
+
});
|
|
543
763
|
```
|
|
544
764
|
|
|
545
765
|
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
package/dist/main.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var
|
|
2
|
-
${JSON.stringify(
|
|
1
|
+
'use strict';Object.defineProperty(exports,'__esModule',{value:true});var bun_sqlite=require('bun:sqlite'),ce=require('crypto');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ce__default=/*#__PURE__*/_interopDefault(ce);var q=class{constructor(e=":memory:"){this.schemas=new Map;this.currentQuery="";this.currentParams=[];this.db=new bun_sqlite.Database(e),this.db.exec("PRAGMA foreign_keys = ON");}close(){this.db.close();}defineSchema(e){this.schemas.set(e.name,e);let r=this.generateCreateTableSQL(e);if(this.db.exec(r),e.indexes)for(let t of e.indexes){let a=`CREATE ${t.unique?"UNIQUE":""} INDEX IF NOT EXISTS ${t.name} ON ${e.name} (${t.columns.join(", ")})`;this.db.exec(a);}}getSchema(e){return this.schemas.get(e)}listTables(){return this.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all().map(r=>r.name)}dropTable(e){this.db.exec(`DROP TABLE IF EXISTS ${e}`),this.schemas.delete(e);}query(){return this.reset(),this.createQueryBuilder()}find(e,r){let t=Object.entries(r).map(([n,a])=>({column:n,operator:"=",value:a}));return this.query().select().from(e).where(t).execute()}findOne(e,r){return this.query().select().from(e).where(Object.entries(r).map(([t,n])=>({column:t,operator:"=",value:n}))).limit(1).executeOne()}findById(e,r){return this.findOne(e,{id:r})}all(e){return this.query().select().from(e).execute()}insert(e,r){this.query().insert(e,r).execute();let t=this.db.query("SELECT last_insert_rowid() as id").get();return this.findById(e,t.id)}update(e,r,t){return this.query().update(e,t).where({column:"id",operator:"=",value:r}).execute(),this.findById(e,r)}delete(e,r){this.query().delete(e).where({column:"id",operator:"=",value:r}).execute();return true}transaction(e){this.db.exec("BEGIN TRANSACTION");try{e(this),this.db.exec("COMMIT");}catch(r){throw this.db.exec("ROLLBACK"),r}}exec(e){this.db.exec(e);}raw(e,r=[]){return this.db.query(e).all(...r)}rawOne(e,r=[]){return this.db.query(e).get(...r)}reset(){this.currentQuery="",this.currentParams=[];}createQueryBuilder(){let e={_select:["*"],_from:"",_where:[],_orderBy:"",_limit:null,_offset:null,_isInsert:false,_isUpdate:false,_isDelete:false,_insertData:null,_updateData:null},r=this;return e.select=function(t){return this._select=t||["*"],this},e.from=function(t){return this._from=t,this},e.where=function(t){let a=(Array.isArray(t)?t:[t]).map(u=>{if(u.operator==="IS NULL"||u.operator==="IS NOT NULL")return `${u.column} ${u.operator}`;if(u.operator==="IN"&&Array.isArray(u.value)){let i=u.value.map(()=>"?").join(", ");return u.value.forEach(p=>{r.currentParams.push(p);}),`${u.column} IN (${i})`}else return r.currentParams.push(u.value),`${u.column} ${u.operator} ?`});return this._where.push(...a),this},e.and=function(t){return this.where(t)},e.or=function(t){if(t.operator==="IS NULL"||t.operator==="IS NOT NULL")this._where.push(`OR ${t.column} ${t.operator}`);else if(t.operator==="IN"&&Array.isArray(t.value)){let n=t.value.map(()=>"?").join(", ");t.value.forEach(a=>{r.currentParams.push(a);}),this._where.push(`OR ${t.column} IN (${n})`);}else r.currentParams.push(t.value),this._where.push(`OR ${t.column} ${t.operator} ?`);return this},e.orderBy=function(t,n="ASC"){return this._orderBy=`ORDER BY ${t} ${n}`,this},e.limit=function(t){return this._limit=t,this},e.offset=function(t){return this._offset=t,this},e.insert=function(t,n){return this._isInsert=true,this._from=t,this._insertData=n,this},e.update=function(t,n){return this._isUpdate=true,this._from=t,this._updateData=n,this},e.delete=function(t){return this._isDelete=true,this._from=t,this},e.raw=function(t,n=[]){return r.currentQuery=t,r.currentParams=n,this},e.execute=function(){let t="";if(this._isInsert&&this._insertData){let u=Object.keys(this._insertData),i=u.map(()=>"?").join(", ");t=`INSERT INTO ${this._from} (${u.join(", ")}) VALUES (${i})`,r.currentParams=Object.values(this._insertData);}else if(this._isUpdate&&this._updateData){let u=Object.keys(this._updateData).map(p=>`${p} = ?`),i=Object.values(this._updateData);r.currentParams=[...i,...r.currentParams],t=`UPDATE ${this._from} SET ${u.join(", ")}`,this._where.length>0&&(t+=` WHERE ${this._where.join(" AND ")}`);}else this._isDelete?(t=`DELETE FROM ${this._from}`,this._where.length>0&&(t+=` WHERE ${this._where.join(" AND ")}`)):(t=`SELECT ${this._select.join(", ")} FROM ${this._from}`,this._where.length>0&&(t+=` WHERE ${this._where.join(" AND ")}`),this._orderBy&&(t+=` ${this._orderBy}`),this._limit!==null&&(t+=` LIMIT ${this._limit}`),this._offset!==null&&(t+=` OFFSET ${this._offset}`));!t&&r.currentQuery&&(t=r.currentQuery);let a=r.db.query(t).all(...r.currentParams);return r.reset(),a},e.executeOne=function(){let t=this.execute();return t.length>0?t[0]:null},e.executeRaw=function(t,n=[]){return r.db.query(t).all(...n)},e}generateCreateTableSQL(e){let r=e.columns.map(t=>{let n=`${t.name} ${t.type}`;return t.primaryKey&&(n+=" PRIMARY KEY",t.autoIncrement&&(n+=" AUTOINCREMENT")),t.notNull&&!t.primaryKey&&(n+=" NOT NULL"),t.unique&&(n+=" UNIQUE"),t.default!==void 0&&(typeof t.default=="string"?n+=` DEFAULT '${t.default}'`:t.default===null?n+=" DEFAULT NULL":n+=` DEFAULT ${t.default}`),t.references&&(n+=` REFERENCES ${t.references.table}(${t.references.column})`),n});return `CREATE TABLE IF NOT EXISTS ${e.name} (${r.join(", ")})`}};function Y(s,e){return {name:s,columns:e}}function Z(s,e){return {name:s,type:e}}function ee(s){return {name:s,type:"INTEGER"}}function te(s){return {name:s,type:"TEXT"}}function re(s){return {name:s,type:"REAL"}}function ne(s){return {name:s,type:"BLOB"}}function se(s){return {name:s,type:"NUMERIC"}}function oe(s,e=false){return {...s,primaryKey:true,autoIncrement:e}}function ie(s){return {...s,notNull:true}}function ae(s){return {...s,unique:true}}function ue(s,e){return {...s,default:e}}function le(s,e,r){return {...s,references:{table:e,column:r}}}var _=class{constructor(){this.routes=new Map;this.regexRoutes=[];}match(e,r){let t=`${e}:${r}`;if(this.routes.has(t))return {handler:this.routes.get(t),params:{}};for(let n of this.regexRoutes)if(n.method===e){let a=r.match(n.pattern);if(a?.groups)return {handler:n.handler,params:a.groups}}return null}getAll(){let e=Array.from(this.routes.entries()).map(([t,n])=>{let a=t.indexOf(":"),u=t.substring(0,a),i=t.substring(a+1);return {method:u,path:i,handler:n}}),r=this.regexRoutes.map(t=>{let n=t.key.indexOf(":");return {method:t.method,path:t.key.substring(n+1),handler:t.handler}});return [...e,...r]}clear(){this.routes.clear(),this.regexRoutes=[];}remove(e,r){let t=`${e}:${r}`;if(this.routes.has(t))return this.routes.delete(t),true;let n=this.regexRoutes.findIndex(a=>a.key===t);return n>=0?(this.regexRoutes.splice(n,1),true):false}register(e,r,t,n={}){let a=`${e}:${r}`;if(r.includes(":")){let u=this.pathToRegex(r),i=this.regexRoutes.findIndex(b=>b.key===a),p={pattern:u,method:e,handler:t,key:a};i>=0?this.regexRoutes[i]=p:this.regexRoutes.push(p);}else this.routes.set(a,t);}pathToRegex(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/:(\w+)/g,"(?<$1>[^/]+)");return new RegExp(`^${t}$`)}};var N=class{constructor(){this.rateLimitStore=new Map;this.csrfTokens=new Map;this.requestLog=new Map;this.MAX_REQUEST_LOG_SIZE=1e3;}checkRateLimit(e,r,t){let n=Date.now(),a=this.rateLimitStore.get(e);return a?n<a.reset?a.count>=r?false:(a.count++,true):(this.rateLimitStore.set(e,{count:1,reset:n+t}),true):(this.rateLimitStore.set(e,{count:1,reset:n+t}),true)}cleanupRateLimit(){let e=Date.now();for(let[r,t]of this.rateLimitStore.entries())e>t.reset&&this.rateLimitStore.delete(r);}generateCsrfToken(e,r=36e5){let t=ce__default.default.randomBytes(32).toString("hex");return this.csrfTokens.set(t,{sessionId:e,expires:Date.now()+r}),t}validateCsrfToken(e,r){let t=this.csrfTokens.get(e);return t?Date.now()>t.expires?(this.csrfTokens.delete(e),false):t.sessionId===r?(this.csrfTokens.delete(e),true):false:false}cleanupCsrfTokens(){let e=Date.now();for(let[r,t]of this.csrfTokens.entries())e>t.expires&&this.csrfTokens.delete(r);}sanitizeHtml(e){return e?e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/"):""}sanitizeSql(e){return e?e.replace(/\\/g,"\\\\").replace(/;/g,"").replace(/'/g,"''").replace(/"/g,'\\"').replace(/\x00/g,""):""}logRequest(e,r,t,n,a,u){if(this.requestLog.set(e,{timestamp:new Date().toISOString(),method:r,path:t,ip:n,status:a,duration:u}),this.requestLog.size>this.MAX_REQUEST_LOG_SIZE){let{value:i}=this.requestLog.keys().next()||{value:null};i&&this.requestLog.delete(i);}}getRequestLog(e){return this.requestLog.get(e)}getAllRequestLogs(){return Array.from(this.requestLog.values())}clearAll(){this.rateLimitStore.clear(),this.csrfTokens.clear(),this.requestLog.clear();}getStats(){return {rateLimitEntries:this.rateLimitStore.size,csrfTokens:this.csrfTokens.size,requestLogs:this.requestLog.size}}};var $=class{constructor(e="info",r=false){this.level=1;this.pretty=false;this.levels={debug:0,info:1,warn:2,error:3,fatal:4};this.level=this.levels[e]??1,this.pretty=r;}debug(e,r){this.log("debug",this.levels.debug,e,r);}info(e,r){this.log("info",this.levels.info,e,r);}warn(e,r){this.log("warn",this.levels.warn,e,r);}error(e,r){this.log("error",this.levels.error,e,r);}fatal(e,r){this.log("fatal",this.levels.fatal,e,r),process.env.NODE_ENV;}log(e,r,t,n){if(r<this.level)return;let a=new Date().toISOString(),u=t??{},i={timestamp:a,level:e.toUpperCase(),message:n||"No message",...u},p=this.pretty?`[${a}] ${e.toUpperCase()} ${n||"No message"}
|
|
2
|
+
${JSON.stringify(u,null,2)}`:JSON.stringify(i);e==="error"||e==="fatal"?console.error(p):e==="warn"?console.warn(p):console.log(p);}};var w=class extends Error{constructor(r,t=500,n){super(r);this.message=r;this.statusCode=t;this.code=n;this.name="AppError";}},E=class extends w{constructor(r,t){super(r,400,"VALIDATION_ERROR");this.issues=t;this.name="ValidationError";}},W=class extends w{constructor(e){super(e,500,"DATABASE_ERROR"),this.name="DatabaseError";}},k=class extends w{constructor(e="Request timeout"){super(e,408,"TIMEOUT_ERROR"),this.name="TimeoutError";}},G=class extends w{constructor(e="Too many requests"){super(e,429,"RATE_LIMIT_ERROR"),this.name="RateLimitError";}};var P=new N,L=new _;function de(s={}){let e=Number(s.port)||3e3,r=s.hostname||"localhost",t=s.maxRequestSize||10*1024*1024,n=s.requestTimeout||3e4,a=s.gracefulShutdownTimeout||1e4,u=typeof s.logging=="object"?s.logging:{},i=s.logging?new $(u.level||"info",u.pretty):null,p=new Map,b=[],x=new Set,T=setInterval(()=>{P.cleanupRateLimit(),P.cleanupCsrfTokens();},120*1e3);async function c(o){let m=Date.now(),l=crypto.randomUUID(),R=new URL(o.url).pathname,A=o.method.toUpperCase(),f=he(o);x.add(l);try{let y=o.headers.get("content-length");if(y&&parseInt(y)>t)return i?.warn({requestId:l,size:y,ip:f},"Request too large"),new Response(JSON.stringify({error:"Payload too large"}),{status:413,headers:{"Content-Type":"application/json"}});let I=fe(o,s);if(A==="OPTIONS")return new Response(null,{status:204,headers:I});if(s.security&&typeof s.security=="object"&&s.security.rateLimit){let C=typeof s.security.rateLimit=="object"?s.security.rateLimit:{},v=C.max||100,j=C.windowMs||6e4,F=C.keyGenerator?C.keyGenerator({request:o,ip:f}):f;if(!P.checkRateLimit(F,v,j))return i?.warn({requestId:l,ip:f,key:F},"Rate limit exceeded"),new Response(JSON.stringify({error:C.message||"Too many requests"}),{status:429,headers:{"Content-Type":"application/json"}})}let M=null;["POST","PUT","PATCH"].includes(A)&&(M=await ge(o,i,t));let H=p.get("default"),B=L.match(A,R);if(!B){let C=X(o,{},H,i,l);return i?.warn({requestId:l,method:A,path:R,ip:f},"Route not found"),C.json({error:"Not Found",path:R},404)}let U=X(o,B.params||{},H,i,l);U.body=M,U.request=o;let Q=new AbortController,K=new Promise((C,v)=>{let j=setTimeout(()=>{Q.abort(),v(new k("Request timeout"));},n);Q.signal.addEventListener("abort",()=>clearTimeout(j));}),D=await Promise.race([B.handler(U),K]),S=new Headers(D.headers);I.forEach((C,v)=>{S.has(v)||S.set(v,C);}),S.set("X-Request-ID",l),S.set("X-Content-Type-Options","nosniff"),S.set("X-Frame-Options","DENY"),S.set("X-XSS-Protection","1; mode=block"),S.set("Referrer-Policy","strict-origin-when-cross-origin");let z=Date.now()-m;return P.logRequest(l,A,R,f,D.status,z),i?.info({requestId:l,method:A,path:R,status:D.status,duration:z,ip:f},"Request completed"),new Response(D.body,{status:D.status,headers:S})}catch(y){if(y instanceof w)return i?.warn({error:y.message,requestId:l,ip:f},`App error: ${y.message}`),new Response(JSON.stringify({error:y.message,code:y.code,requestId:l}),{status:y.statusCode,headers:{"Content-Type":"application/json"}});i?.error({error:String(y),requestId:l,ip:f},"Unhandled error");let I=process.env.NODE_ENV==="production"?"Internal Server Error":y.message;return new Response(JSON.stringify({error:I,requestId:l}),{status:500,headers:{"Content-Type":"application/json"}})}finally{x.delete(l);}}let d={method:"GET",path:"/health",handler:o=>o.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime(),activeRequests:x.size})},g={method:"GET",path:"/readiness",handler:o=>{let m=p.size>0,l=m||p.size===0;return o.json({ready:l,checks:{database:m?"connected":"not configured",activeRequests:x.size},timestamp:new Date().toISOString()},l?200:503)}};s.routes&&s.routes.forEach(o=>{b.push(o),(Array.isArray(o.method)?o.method:[o.method]).forEach(l=>{L.register(l,o.path,o.handler,o);});}),b.push(d,g),L.register("GET","/health",d.handler,d),L.register("GET","/readiness",g.handler,g);let h=null,V={app:null,logger:i,db:p,bunServer:null,async start(){if(s.database){let m=Array.isArray(s.database)?s.database:[s.database];for(let l of m){let O=l.name||"default";try{if(typeof l.connection=="string"){let R=new q(l.connection);if(l.schema&&typeof l.schema=="object")for(let[A,f]of Object.entries(l.schema))f&&typeof f=="object"&&R.defineSchema(f);p.set(O,R),i?.info({name:O,connection:l.connection},"\u2705 Database connected");}else throw new Error(`Database connection must be a string path (got ${typeof l.connection})`)}catch(R){throw i?.error({error:String(R),name:O},"Failed to connect to database"),R}}}h=Bun.serve({port:e,hostname:r,fetch:c}),V.bunServer=h;let o=`http://${r}:${e}`;console.log(`\u2192 URL: ${o}
|
|
3
3
|
\u2192 Environment: ${process.env.NODE_ENV||"development"}
|
|
4
4
|
\u2192 Routes: ${b.length.toString()}
|
|
5
|
-
\u2192 Database: ${
|
|
5
|
+
\u2192 Database: ${p.size>0?"\u2705 Connected":"\u274C None"}
|
|
6
6
|
\u2192 Security: ${s.security?"\u2705 ENABLED":"\u274C Disabled"}
|
|
7
7
|
|
|
8
8
|
\u{1F50D} Health: ${o}/health
|
|
9
9
|
\u{1F50D} Ready: ${o}/readiness
|
|
10
|
-
`),
|
|
10
|
+
`),i?.info({url:o},"Server started");},async stop(){if(i?.info("Stopping server..."),x.size>0){i?.info({count:x.size},"Waiting for active requests...");let o=Date.now()+a;for(;x.size>0&&Date.now()<o;)await new Promise(m=>setTimeout(m,100));x.size>0&&i?.warn({count:x.size},"Force closing with active requests");}if(clearInterval(T),s.onShutdown)try{await s.onShutdown();}catch(o){i?.error({error:String(o)},"Error in shutdown handler");}for(let[o,m]of p.entries())try{m&&typeof m.close=="function"&&m.close(),i?.info({name:o},"Database closed");}catch(l){i?.error({error:String(l),name:o},"Error closing database");}h&&(h.stop(),i?.info("Bun server stopped")),i?.info("Server stopped successfully");},addRoute(o){b.push(o),(Array.isArray(o.method)?o.method:[o.method]).forEach(l=>{L.register(l,o.path,o.handler,o);}),i?.info({method:o.method,path:o.path},"Route added");},getRoutes(){return b}};return V}async function ge(s,e,r){let t=s.headers.get("content-type")||"";try{if(t.includes("application/json")){let n=await s.text();if(n.length>r)throw new E("Payload too large");if(!n.trim())return {};try{return JSON.parse(n)}catch(a){throw e?.warn({error:String(a),bodyPreview:n.substring(0,100)},"Invalid JSON in request body"),new E("Invalid JSON in request body")}}if(t.includes("application/x-www-form-urlencoded")){let n=await s.text();if(n.length>r)throw new E("Payload too large");return Object.fromEntries(new URLSearchParams(n))}if(t.includes("multipart/form-data"))return await s.formData()}catch(n){throw n instanceof E?n:(e?.error({error:String(n)},"Error parsing request body"),new E("Failed to parse request body"))}return {}}function me(s){let e=new Map;if(!s)return e;let r=s.split(";");for(let t of r){let[n,...a]=t.trim().split("=");if(n){let u=a.join("=");e.set(n,u?decodeURIComponent(u):"");}}return e}function X(s,e,r,t,n){let a=new URL(s.url),u=Object.fromEntries(a.searchParams),i=s.headers,p=200,b=new Map,x=me(i.get("cookie")||""),T={request:s,params:e,query:u,headers:i,db:r,logger:t,requestId:n,get statusCode(){return p},set statusCode(c){p=c;},body:null,json(c,d){return new Response(JSON.stringify(c),{status:d??p,headers:{"Content-Type":"application/json",...this._setCookieHeaders()}})},text(c,d){return new Response(c,{status:d??p,headers:{"Content-Type":"text/plain",...this._setCookieHeaders()}})},html(c,d){return new Response(c,{status:d??p,headers:{"Content-Type":"text/html; charset=utf-8",...this._setCookieHeaders()}})},redirect(c,d=302){return new Response(null,{status:d,headers:{Location:c,...this._setCookieHeaders()}})},file(c,d="application/octet-stream"){let g=Bun.file(c);return new Response(g,{headers:{"Content-Type":d,...this._setCookieHeaders()}})},setCookie(c,d,g={}){let h=`${c}=${encodeURIComponent(d)}`;return g.maxAge!==void 0&&(h+=`; Max-Age=${g.maxAge}`),g.expires&&(h+=`; Expires=${g.expires.toUTCString()}`),g.path&&(h+=`; Path=${g.path}`),g.domain&&(h+=`; Domain=${g.domain}`),g.secure&&(h+="; Secure"),g.httpOnly&&(h+="; HttpOnly"),g.sameSite&&(h+=`; SameSite=${g.sameSite}`),b.set(c,h),T},getCookie(c){return x.get(c)},deleteCookie(c,d={}){return T.setCookie(c,"",{...d,maxAge:0,path:d.path||"/"})},setHeader(c,d){return i.set(c,d),T},getHeader(c){return i.get(c)||void 0},status(c){return p=c,T},_setCookieHeaders(){let c={};return b.size>0&&(c["Set-Cookie"]=Array.from(b.values())),c}};return T}function he(s){let e=s.headers.get("x-forwarded-for");if(e)return e.split(",").map(n=>n.trim())[0]||"unknown";let r=s.headers.get("x-real-ip");return r||"unknown"}function fe(s,e){let r=new Headers;if(!e.security||typeof e.security!="object"||!e.security.cors)return r;let t=typeof e.security.cors=="object"?e.security.cors:{},n=s.headers.get("Origin");if(n){typeof t.origin=="function"?t.origin(n)&&r.set("Access-Control-Allow-Origin",n):Array.isArray(t.origin)?t.origin.includes(n)&&r.set("Access-Control-Allow-Origin",n):typeof t.origin=="string"?r.set("Access-Control-Allow-Origin",t.origin):r.set("Access-Control-Allow-Origin",n);let a=t.methods||["GET","POST","PUT","DELETE","PATCH","OPTIONS"];r.set("Access-Control-Allow-Methods",a.join(", "));let u=t.allowedHeaders||["Content-Type","Authorization","X-Requested-With"];r.set("Access-Control-Allow-Headers",u.join(", ")),t.credentials&&r.set("Access-Control-Allow-Credentials","true"),t.maxAge&&r.set("Access-Control-Max-Age",t.maxAge.toString());}return r}var ve=de;exports.AppError=w;exports.DB=q;exports.DatabaseError=W;exports.Logger=$;exports.RateLimitError=G;exports.Router=_;exports.SecurityManager=N;exports.TimeoutError=k;exports.ValidationError=E;exports.blob=ne;exports.column=Z;exports.default=ve;exports.defaultValue=ue;exports.integer=ee;exports.notNull=ie;exports.numeric=se;exports.primaryKey=oe;exports.real=re;exports.references=le;exports.server=de;exports.table=Y;exports.text=te;exports.unique=ae;//# sourceMappingURL=main.cjs.map
|
|
11
11
|
//# sourceMappingURL=main.cjs.map
|