@shohaghinfo/aerojs 0.4.0 → 0.4.2
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/AGENTS.md +17 -16
- package/README.md +117 -44
- package/dist/audit/audit-trail.d.ts +5 -6
- package/dist/audit/audit-trail.d.ts.map +1 -1
- package/dist/audit/audit-trail.js +5 -6
- package/dist/audit/audit-trail.js.map +1 -1
- package/dist/auth/auth-manager.d.ts +5 -5
- package/dist/auth/auth-manager.js +5 -5
- package/dist/auth/bouncer.d.ts +8 -15
- package/dist/auth/bouncer.d.ts.map +1 -1
- package/dist/auth/bouncer.js +10 -17
- package/dist/auth/bouncer.js.map +1 -1
- package/dist/auth/guards/api-token-guard.d.ts +2 -4
- package/dist/auth/guards/api-token-guard.d.ts.map +1 -1
- package/dist/auth/guards/api-token-guard.js +2 -4
- package/dist/auth/guards/api-token-guard.js.map +1 -1
- package/dist/auth/guards/jwt-guard.d.ts +3 -4
- package/dist/auth/guards/jwt-guard.d.ts.map +1 -1
- package/dist/auth/guards/jwt-guard.js +2 -3
- package/dist/auth/guards/jwt-guard.js.map +1 -1
- package/dist/auth/guards/session-guard.d.ts +2 -4
- package/dist/auth/guards/session-guard.d.ts.map +1 -1
- package/dist/auth/guards/session-guard.js +2 -4
- package/dist/auth/guards/session-guard.js.map +1 -1
- package/dist/auth/policy.js +1 -1
- package/dist/auth/policy.js.map +1 -1
- package/dist/cli/commands/make.js +5 -5
- package/dist/cli/runner.js +1 -1
- package/dist/core/application.d.ts +4 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/application.js +29 -3
- package/dist/core/application.js.map +1 -1
- package/dist/core/context.d.ts +25 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +43 -0
- package/dist/core/context.js.map +1 -1
- package/dist/database/drizzle.d.ts +4 -1
- package/dist/database/drizzle.d.ts.map +1 -1
- package/dist/database/drizzle.js +1 -1
- package/dist/database/drizzle.js.map +1 -1
- package/dist/database/index.d.ts +1 -0
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +1 -0
- package/dist/database/index.js.map +1 -1
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +1 -0
- package/dist/database/knex.js.map +1 -1
- package/dist/database/model-hooks.d.ts +5 -5
- package/dist/database/model-hooks.js +11 -11
- package/dist/database/model.d.ts +43 -59
- package/dist/database/model.d.ts.map +1 -1
- package/dist/database/model.js +62 -68
- package/dist/database/model.js.map +1 -1
- package/dist/database/prisma.d.ts +1 -1
- package/dist/database/prisma.d.ts.map +1 -1
- package/dist/database/prisma.js +3 -2
- package/dist/database/prisma.js.map +1 -1
- package/dist/database/query-builder.d.ts +11 -7
- package/dist/database/query-builder.d.ts.map +1 -1
- package/dist/database/query-builder.js +50 -21
- package/dist/database/query-builder.js.map +1 -1
- package/dist/database/sqlite.d.ts +26 -0
- package/dist/database/sqlite.d.ts.map +1 -0
- package/dist/database/sqlite.js +96 -0
- package/dist/database/sqlite.js.map +1 -0
- package/dist/events/event-bus.d.ts +47 -75
- package/dist/events/event-bus.d.ts.map +1 -1
- package/dist/events/event-bus.js +14 -23
- package/dist/events/event-bus.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/notifications/notification-manager.d.ts +1 -1
- package/dist/notifications/notification-manager.js +1 -1
- package/dist/scheduler/scheduler.d.ts +5 -5
- package/dist/scheduler/scheduler.js +5 -5
- package/dist/session/session-driver.d.ts +2 -2
- package/dist/session/session-driver.js +2 -2
- package/dist/session/session-manager.d.ts +4 -4
- package/dist/session/session-manager.js +3 -3
- package/dist/tcp/mllp.d.ts +1 -1
- package/dist/tcp/mllp.js +2 -2
- package/dist/tcp/mllp.js.map +1 -1
- package/dist/validation/schema.d.ts +6 -0
- package/dist/validation/schema.d.ts.map +1 -1
- package/dist/validation/schema.js +57 -3
- package/dist/validation/schema.js.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -337,16 +337,17 @@ const db = knex({
|
|
|
337
337
|
useKnex(db);
|
|
338
338
|
```
|
|
339
339
|
|
|
340
|
-
#### 3. Using SQLite (`
|
|
341
|
-
Change `.env` to `DB_CONNECTION=sqlite`, `DB_DATABASE=storage/database.sqlite`:
|
|
340
|
+
#### 3. Using SQLite (Native `useSqlite` or `better-sqlite3`)
|
|
342
341
|
```typescript
|
|
343
|
-
import
|
|
344
|
-
|
|
345
|
-
|
|
342
|
+
import { useSqlite, useKnex } from 'aerojs';
|
|
343
|
+
|
|
344
|
+
// Option A: Built-in Native SQLite (Node.js >= 22 zero-dependency node:sqlite)
|
|
345
|
+
useSqlite('storage/database.sqlite'); // or ':memory:'
|
|
346
346
|
|
|
347
|
+
// Option B: SQLite via Knex (better-sqlite3)
|
|
347
348
|
const db = knex({
|
|
348
349
|
client: 'better-sqlite3',
|
|
349
|
-
connection:
|
|
350
|
+
connection: { filename: 'storage/database.sqlite' },
|
|
350
351
|
useNullAsDefault: true,
|
|
351
352
|
});
|
|
352
353
|
useKnex(db);
|
|
@@ -813,9 +814,9 @@ router.get('/secure/download', validateSignedUrl(), async (ctx) => {
|
|
|
813
814
|
```bash
|
|
814
815
|
aero make:job ProcessPayment
|
|
815
816
|
aero make:mail OrderReceipt
|
|
816
|
-
aero make:policy
|
|
817
|
-
aero make:event
|
|
818
|
-
aero make:listener
|
|
817
|
+
aero make:policy PostPolicy
|
|
818
|
+
aero make:event UserRegistered
|
|
819
|
+
aero make:listener SendWelcomeNotification
|
|
819
820
|
```
|
|
820
821
|
|
|
821
822
|
---
|
|
@@ -823,7 +824,7 @@ aero make:listener NotifyDoctor
|
|
|
823
824
|
## 12. Advanced Enterprise Architecture (v0.4.0)
|
|
824
825
|
|
|
825
826
|
### 12.1 Field-Level AES-256-GCM Encryption (`Crypt`, `@encrypted`)
|
|
826
|
-
Protect sensitive compliance data (SSN,
|
|
827
|
+
Protect sensitive compliance data (SSN, tax records, credentials, confidential notes) transparently at rest:
|
|
827
828
|
|
|
828
829
|
```typescript
|
|
829
830
|
import { Model, encrypted, Crypt } from 'aerojs';
|
|
@@ -833,13 +834,13 @@ const ciphertext = Crypt.encrypt('secret-data');
|
|
|
833
834
|
const plaintext = Crypt.decrypt(ciphertext);
|
|
834
835
|
|
|
835
836
|
// Model field-level transparent encryption
|
|
836
|
-
export class
|
|
837
|
-
public static override table = '
|
|
837
|
+
export class AccountRecord extends Model {
|
|
838
|
+
public static override table = 'accounts';
|
|
838
839
|
public static override primaryKey = 'id';
|
|
839
|
-
public static override fillable = ['name', 'ssn', '
|
|
840
|
+
public static override fillable = ['name', 'ssn', 'private_notes'];
|
|
840
841
|
|
|
841
842
|
// Mark fields for automatic AES-256-GCM encryption
|
|
842
|
-
public static override encrypted = ['ssn', '
|
|
843
|
+
public static override encrypted = ['ssn', 'private_notes'];
|
|
843
844
|
|
|
844
845
|
// Or use TypeScript property decorator:
|
|
845
846
|
// @encrypted()
|
|
@@ -847,10 +848,10 @@ export class Patient extends Model {
|
|
|
847
848
|
}
|
|
848
849
|
|
|
849
850
|
// Automatically encrypted on .save() and decrypted on .find() / .all() / .toJSON()
|
|
850
|
-
const
|
|
851
|
+
const account = await AccountRecord.create({
|
|
851
852
|
name: 'John Doe',
|
|
852
853
|
ssn: '123-45-6789',
|
|
853
|
-
|
|
854
|
+
private_notes: 'Confidential client notes',
|
|
854
855
|
});
|
|
855
856
|
```
|
|
856
857
|
|
package/README.md
CHANGED
|
@@ -940,71 +940,144 @@ app.listen(3000);
|
|
|
940
940
|
|
|
941
941
|
---
|
|
942
942
|
|
|
943
|
-
### 22. Active Record ORM &
|
|
943
|
+
### 22. Active Record ORM, QueryBuilder & Dialects (`Model`, `DB`, `Schema`, `useSqlite`)
|
|
944
944
|
|
|
945
|
-
|
|
945
|
+
AeroJS ships with a batteries-included, zero-lock-in database tier supporting **MySQL**, **PostgreSQL**, and **SQLite** (Node.js 24 zero-dependency `node:sqlite`).
|
|
946
946
|
|
|
947
|
+
```text
|
|
948
|
+
┌────────────────────────────────────────────────────────┐
|
|
949
|
+
│ AeroJS Database Tier │
|
|
950
|
+
├──────────────────────────┬─────────────────────────────┤
|
|
951
|
+
│ Tier 1: Batteries-Included│ Tier 2: Zero Lock-In │
|
|
952
|
+
│ Native ORM & QueryBuilder│ External ORM Bridges │
|
|
953
|
+
│ ├─ Active Record Model │ ├─ Drizzle ORM │
|
|
954
|
+
│ ├─ Fluent QueryBuilder │ ├─ Prisma Client │
|
|
955
|
+
│ ├─ Schema Migrations │ └─ Knex.js │
|
|
956
|
+
│ └─ Native SQLite / PG / MySQL │
|
|
957
|
+
└──────────────────────────┴─────────────────────────────┘
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
#### 22.1 Defining Active Record Models & Relationships
|
|
947
961
|
```typescript
|
|
948
|
-
import { Model
|
|
962
|
+
import { Model } from 'aerojs';
|
|
949
963
|
|
|
950
|
-
|
|
951
|
-
class User extends Model {
|
|
964
|
+
export class User extends Model {
|
|
952
965
|
public static override table = 'users';
|
|
966
|
+
public static override primaryKey = 'id';
|
|
967
|
+
public static override fillable = ['name', 'email', 'role'];
|
|
953
968
|
public static override hidden = ['password'];
|
|
954
969
|
public static override softDeletes = true;
|
|
955
970
|
|
|
956
971
|
public posts() {
|
|
957
972
|
return this.hasMany(Post, 'user_id', 'id');
|
|
958
973
|
}
|
|
974
|
+
|
|
975
|
+
public profile() {
|
|
976
|
+
return this.hasOne(Profile, 'user_id', 'id');
|
|
977
|
+
}
|
|
959
978
|
}
|
|
960
979
|
|
|
961
|
-
class Post extends Model {
|
|
980
|
+
export class Post extends Model {
|
|
962
981
|
public static override table = 'posts';
|
|
982
|
+
|
|
983
|
+
public user() {
|
|
984
|
+
return this.belongsTo(User, 'user_id', 'id');
|
|
985
|
+
}
|
|
963
986
|
}
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
#### 22.2 Active Record Persistence & Dirty Tracking
|
|
990
|
+
```typescript
|
|
991
|
+
// Create
|
|
992
|
+
const user = await User.create({ name: 'Alice', email: 'alice@aerojs.dev' });
|
|
964
993
|
|
|
965
|
-
//
|
|
966
|
-
const user = await User.create({ name: 'Alice', email: 'alice@aero.org' });
|
|
994
|
+
// Mutate via Proxied getters/setters & Dirty Tracking
|
|
967
995
|
user.name = 'Alice Smith';
|
|
968
|
-
await user.save();
|
|
996
|
+
await user.save(); // Only updates modified 'name' column
|
|
969
997
|
|
|
970
|
-
//
|
|
971
|
-
const usersWithPosts = await User.
|
|
998
|
+
// Eager Loading (Eliminates N+1 queries)
|
|
999
|
+
const usersWithPosts = await User.with('posts', 'profile').get();
|
|
972
1000
|
|
|
973
|
-
//
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1001
|
+
// Soft Deletes
|
|
1002
|
+
await user.delete(); // Sets deleted_at = NOW()
|
|
1003
|
+
await user.restore(); // Clears deleted_at
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
#### 22.3 Fluent QueryBuilder (`DB.table(...)`)
|
|
1007
|
+
```typescript
|
|
1008
|
+
import { DB } from 'aerojs';
|
|
1009
|
+
|
|
1010
|
+
// Conditionals, Joins & Pagination
|
|
1011
|
+
const results = await DB.table('orders')
|
|
1012
|
+
.select('orders.*', 'users.name as customer_name')
|
|
1013
|
+
.join('users', 'orders.user_id', 'users.id')
|
|
1014
|
+
.where('orders.status', '=', 'completed')
|
|
1015
|
+
.whereIn('orders.currency', ['USD', 'EUR'])
|
|
1016
|
+
.orderBy('orders.created_at', 'DESC')
|
|
1017
|
+
.paginate(1, 15); // Returns { data, total, page, perPage, lastPage }
|
|
1018
|
+
|
|
1019
|
+
// Pessimistic Locking
|
|
1020
|
+
const order = await DB.table('orders')
|
|
1021
|
+
.where('id', 1)
|
|
1022
|
+
.forUpdate()
|
|
1023
|
+
.first();
|
|
1024
|
+
|
|
1025
|
+
// Atomic Transactions & Savepoints
|
|
1026
|
+
await DB.transaction(async (trx) => {
|
|
1027
|
+
await trx.table('accounts').where('id', 1).decrement('balance', 100);
|
|
1028
|
+
await trx.table('accounts').where('id', 2).increment('balance', 100);
|
|
1029
|
+
});
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
#### 22.4 Native Zero-Dependency SQLite Adapter
|
|
1033
|
+
```typescript
|
|
1034
|
+
import { Aero, useSqlite } from 'aerojs';
|
|
1035
|
+
|
|
1036
|
+
const app = new Aero();
|
|
1037
|
+
|
|
1038
|
+
// Out-of-the-box in-memory or persistent SQLite without native compilation:
|
|
1039
|
+
app.useSqlite('storage/database.sqlite');
|
|
1040
|
+
|
|
1041
|
+
app.get('/items', async (ctx) => {
|
|
1042
|
+
const items = await ctx.sqlite.query('SELECT * FROM items WHERE is_active = ?', [1]);
|
|
1043
|
+
ctx.status(200).json(items);
|
|
1044
|
+
});
|
|
978
1045
|
```
|
|
979
1046
|
|
|
980
1047
|
---
|
|
981
1048
|
|
|
982
|
-
### 23.
|
|
1049
|
+
### 23. Zero Lock-In External Integrations (Drizzle, Prisma & Knex)
|
|
983
1050
|
|
|
984
|
-
|
|
1051
|
+
AeroJS gives you complete freedom. You can leverage AeroJS's ultra-fast HTTP routing, middleware pipeline, authentication, websockets, job queues, and error dashboard while bringing your favorite database library:
|
|
985
1052
|
|
|
986
1053
|
```typescript
|
|
987
|
-
import Aero from '
|
|
1054
|
+
import { Aero } from 'aerojs';
|
|
988
1055
|
import knex from 'knex';
|
|
989
1056
|
import { PrismaClient } from '@prisma/client';
|
|
990
1057
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
991
1058
|
|
|
992
1059
|
const app = new Aero();
|
|
993
1060
|
|
|
994
|
-
// 1. Knex
|
|
1061
|
+
// 1. Pluggable Knex.js
|
|
995
1062
|
app.useKnex(knex({ client: 'pg', connection: process.env.DATABASE_URL }));
|
|
996
1063
|
|
|
997
|
-
// 2. Prisma
|
|
1064
|
+
// 2. Pluggable Prisma Client
|
|
998
1065
|
app.usePrisma(new PrismaClient());
|
|
999
1066
|
|
|
1000
|
-
// 3. Drizzle
|
|
1067
|
+
// 3. Pluggable Drizzle ORM
|
|
1001
1068
|
app.useDrizzle(drizzle(process.env.DATABASE_URL));
|
|
1002
1069
|
|
|
1003
|
-
app.get('/
|
|
1004
|
-
//
|
|
1005
|
-
const
|
|
1006
|
-
const usersPrisma
|
|
1007
|
-
const
|
|
1070
|
+
app.get('/dashboard', async (ctx) => {
|
|
1071
|
+
// Direct injection into request context with full TypeScript inference:
|
|
1072
|
+
const activeOrders = await ctx.knex('orders').where({ status: 'pending' });
|
|
1073
|
+
const usersPrisma = await ctx.prisma.user.findMany({ where: { active: true } });
|
|
1074
|
+
const drizzlePosts = await ctx.drizzle.select().from(postsTable);
|
|
1075
|
+
|
|
1076
|
+
// Or strongly-typed generics:
|
|
1077
|
+
const customPrisma = ctx.getPrisma<PrismaClient>();
|
|
1078
|
+
const customDrizzle = ctx.getDrizzle<typeof drizzleDb>();
|
|
1079
|
+
|
|
1080
|
+
ctx.status(200).json({ activeOrders, usersPrisma, drizzlePosts });
|
|
1008
1081
|
});
|
|
1009
1082
|
```
|
|
1010
1083
|
|
|
@@ -1225,10 +1298,10 @@ Mail.configure({
|
|
|
1225
1298
|
|
|
1226
1299
|
// 2. Dispatch with attachments & HTML
|
|
1227
1300
|
await Mail.send((msg) => {
|
|
1228
|
-
msg.to('
|
|
1229
|
-
.from('billing@
|
|
1301
|
+
msg.to('customer@example.com')
|
|
1302
|
+
.from('billing@example.org', 'Billing Department')
|
|
1230
1303
|
.subject('Monthly Statement & Invoice')
|
|
1231
|
-
.html('<h1>Hello!</h1><p>Please find your
|
|
1304
|
+
.html('<h1>Hello!</h1><p>Please find your monthly invoice attached.</p>')
|
|
1232
1305
|
.attach('invoice.pdf', pdfBuffer, 'application/pdf');
|
|
1233
1306
|
});
|
|
1234
1307
|
```
|
|
@@ -1306,25 +1379,25 @@ AeroJS ships with a powerful, zero-dependency fluent HTTP client built on native
|
|
|
1306
1379
|
import { Http } from '@shohaghinfo/aerojs';
|
|
1307
1380
|
|
|
1308
1381
|
// 1. Fluent API calls
|
|
1309
|
-
const response = await Http.baseUrl('https://api.
|
|
1382
|
+
const response = await Http.baseUrl('https://api.example.com/v1')
|
|
1310
1383
|
.withToken(process.env.API_KEY!)
|
|
1311
1384
|
.withQuery({ status: 'active', limit: 50 })
|
|
1312
1385
|
.timeout(5000)
|
|
1313
1386
|
.retry(3, 200)
|
|
1314
|
-
.get('/
|
|
1387
|
+
.get('/users');
|
|
1315
1388
|
|
|
1316
1389
|
if (response.successful) {
|
|
1317
|
-
const
|
|
1318
|
-
console.log('
|
|
1390
|
+
const users = response.json();
|
|
1391
|
+
console.log('Users fetched:', users);
|
|
1319
1392
|
}
|
|
1320
1393
|
|
|
1321
1394
|
// 2. Testing Fakes (Mocking external services)
|
|
1322
1395
|
Http.fake({
|
|
1323
|
-
'/
|
|
1396
|
+
'/users': [{ id: 1, name: 'Alice Smith' }],
|
|
1324
1397
|
'/billing': Http.response({ invoiceId: 'INV-101' }, 201),
|
|
1325
1398
|
});
|
|
1326
1399
|
|
|
1327
|
-
const res = await Http.post('https://api.
|
|
1400
|
+
const res = await Http.post('https://api.example.com/v1/billing', { amount: 500 });
|
|
1328
1401
|
expect(res.status).toBe(201);
|
|
1329
1402
|
|
|
1330
1403
|
Http.assertSent((req) => req.url.includes('/billing') && req.method === 'POST');
|
|
@@ -1446,24 +1519,24 @@ Ensure HIPAA, GDPR, and PCI-DSS compliance by transparently encrypting sensitive
|
|
|
1446
1519
|
```typescript
|
|
1447
1520
|
import { Model, encrypted, Crypt } from '@shohaghinfo/aerojs';
|
|
1448
1521
|
|
|
1449
|
-
class
|
|
1450
|
-
public static override table = '
|
|
1451
|
-
public static override fillable = ['name', 'ssn', '
|
|
1452
|
-
public static override encrypted = ['ssn', '
|
|
1522
|
+
class AccountRecord extends Model {
|
|
1523
|
+
public static override table = 'accounts';
|
|
1524
|
+
public static override fillable = ['name', 'ssn', 'private_notes'];
|
|
1525
|
+
public static override encrypted = ['ssn', 'private_notes'];
|
|
1453
1526
|
|
|
1454
1527
|
@encrypted()
|
|
1455
1528
|
public ssn!: string;
|
|
1456
1529
|
}
|
|
1457
1530
|
|
|
1458
1531
|
// 1. Create - Data is stored as aero:enc:<iv>:<tag>:<ciphertext> in the database
|
|
1459
|
-
const
|
|
1532
|
+
const account = await AccountRecord.create({
|
|
1460
1533
|
name: 'Rahim Khan',
|
|
1461
1534
|
ssn: '019-99-8888',
|
|
1462
|
-
|
|
1535
|
+
private_notes: 'Confidential client information',
|
|
1463
1536
|
});
|
|
1464
1537
|
|
|
1465
1538
|
// 2. Read - Transparently decrypted on fetch
|
|
1466
|
-
const loaded = await
|
|
1539
|
+
const loaded = await AccountRecord.find(account.id);
|
|
1467
1540
|
console.log(loaded.ssn); // '019-99-8888' (Plaintext in app code)
|
|
1468
1541
|
|
|
1469
1542
|
// 3. Arbitrary payload encryption via Crypt facade:
|
|
@@ -1509,7 +1582,7 @@ const app = new Aero();
|
|
|
1509
1582
|
|
|
1510
1583
|
// Mount the dashboard with optional role-based protection
|
|
1511
1584
|
app.useQueueDashboard('/__aero/queue', {
|
|
1512
|
-
title: '
|
|
1585
|
+
title: 'AeroJS Queue Horizon',
|
|
1513
1586
|
pollInterval: 3, // auto-refresh every 3s
|
|
1514
1587
|
auth: (ctx) => ctx.session?.get('user')?.role === 'superadmin',
|
|
1515
1588
|
});
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* @file audit-trail.ts
|
|
3
3
|
* @description Immutable Audit Trail System for AeroJS.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ভুল এন্ট্রি হলে তা STATUS = VOID বা CANCELLED হবে এবং রিভার্সাল এন্ট্রি পড়বে।"
|
|
5
|
+
* Provides tamper-evident compliance tracking for sensitive database entities.
|
|
6
|
+
* Ensures auditable state history without destructive data loss.
|
|
8
7
|
*
|
|
9
8
|
* Stores: User ID, Table/Module, Record ID, Action, Old Value, New Value,
|
|
10
|
-
* IP Address, Timestamp,
|
|
9
|
+
* IP Address, Timestamp, Reason.
|
|
11
10
|
*/
|
|
12
11
|
export type AuditAction = 'CREATE' | 'UPDATE' | 'VOID' | 'APPROVE' | 'REJECT' | 'PRINT' | 'LOGIN' | 'LOGOUT' | 'LOCK' | 'RESTORE' | 'EXPORT';
|
|
13
12
|
export interface AuditLogEntry {
|
|
@@ -80,12 +79,12 @@ export declare class AuditTrailManager {
|
|
|
80
79
|
log(entry: AuditLogEntry): Promise<void>;
|
|
81
80
|
/**
|
|
82
81
|
* Get full history of changes for a specific record.
|
|
83
|
-
*
|
|
82
|
+
* Example: "Who modified this transaction? Show all changes."
|
|
84
83
|
*/
|
|
85
84
|
getHistory(tableName: string, recordId: string | number): Promise<AuditLogRecord[]>;
|
|
86
85
|
/**
|
|
87
86
|
* Get all activity by a specific user in a time range.
|
|
88
|
-
*
|
|
87
|
+
* Example: "Show all actions performed by user #42 today."
|
|
89
88
|
*/
|
|
90
89
|
getUserActivity(userId: string | number, from?: Date, to?: Date): Promise<AuditLogRecord[]>;
|
|
91
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-trail.d.ts","sourceRoot":"","sources":["../../src/audit/audit-trail.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"audit-trail.d.ts","sourceRoot":"","sources":["../../src/audit/audit-trail.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
* @file audit-trail.ts
|
|
3
3
|
* @description Immutable Audit Trail System for AeroJS.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ভুল এন্ট্রি হলে তা STATUS = VOID বা CANCELLED হবে এবং রিভার্সাল এন্ট্রি পড়বে।"
|
|
5
|
+
* Provides tamper-evident compliance tracking for sensitive database entities.
|
|
6
|
+
* Ensures auditable state history without destructive data loss.
|
|
8
7
|
*
|
|
9
8
|
* Stores: User ID, Table/Module, Record ID, Action, Old Value, New Value,
|
|
10
|
-
* IP Address, Timestamp,
|
|
9
|
+
* IP Address, Timestamp, Reason.
|
|
11
10
|
*/
|
|
12
11
|
import { DB } from '../database/connection.js';
|
|
13
12
|
/**
|
|
@@ -107,14 +106,14 @@ export class AuditTrailManager {
|
|
|
107
106
|
}
|
|
108
107
|
/**
|
|
109
108
|
* Get full history of changes for a specific record.
|
|
110
|
-
*
|
|
109
|
+
* Example: "Who modified this transaction? Show all changes."
|
|
111
110
|
*/
|
|
112
111
|
async getHistory(tableName, recordId) {
|
|
113
112
|
return await this.driver.getHistory(tableName, recordId);
|
|
114
113
|
}
|
|
115
114
|
/**
|
|
116
115
|
* Get all activity by a specific user in a time range.
|
|
117
|
-
*
|
|
116
|
+
* Example: "Show all actions performed by user #42 today."
|
|
118
117
|
*/
|
|
119
118
|
async getUserActivity(userId, from, to) {
|
|
120
119
|
return await this.driver.getUserActivity(userId, from, to);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/audit/audit-trail.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/audit/audit-trail.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file auth-manager.ts
|
|
3
3
|
* @description Central Auth Manager for AeroJS.
|
|
4
4
|
* Manages multiple named guards (session, jwt, api) and exposes ctx.auth.use('guard').
|
|
5
|
-
*
|
|
5
|
+
* Example: ctx.auth.use('session') for web dashboard, ctx.auth.use('jwt') for mobile API.
|
|
6
6
|
*/
|
|
7
7
|
import type { AeroContext } from '../core/context.js';
|
|
8
8
|
import type { AuthUser } from './guards/guard.js';
|
|
@@ -47,10 +47,10 @@ export declare class Auth {
|
|
|
47
47
|
* Guards are lazily instantiated per request.
|
|
48
48
|
*
|
|
49
49
|
* @example
|
|
50
|
-
* //
|
|
50
|
+
* // Web session auth
|
|
51
51
|
* await ctx.auth.use('session').authenticate();
|
|
52
52
|
*
|
|
53
|
-
* //
|
|
53
|
+
* // Mobile / API JWT auth
|
|
54
54
|
* const user = await ctx.auth.use('jwt').authenticate();
|
|
55
55
|
*/
|
|
56
56
|
use(name?: string): any;
|
|
@@ -88,8 +88,8 @@ export declare function authPlugin(manager: AuthManager, sessionManager?: Sessio
|
|
|
88
88
|
* Throws UnauthorizedError if not authenticated.
|
|
89
89
|
*
|
|
90
90
|
* @example
|
|
91
|
-
* router.get('/
|
|
92
|
-
* router.get('/api/
|
|
91
|
+
* router.get('/dashboard', handler).middleware(auth('session'));
|
|
92
|
+
* router.get('/api/users', handler).middleware(auth('jwt'));
|
|
93
93
|
*/
|
|
94
94
|
export declare function auth(guardName?: string): Middleware;
|
|
95
95
|
//# sourceMappingURL=auth-manager.d.ts.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file auth-manager.ts
|
|
3
3
|
* @description Central Auth Manager for AeroJS.
|
|
4
4
|
* Manages multiple named guards (session, jwt, api) and exposes ctx.auth.use('guard').
|
|
5
|
-
*
|
|
5
|
+
* Example: ctx.auth.use('session') for web dashboard, ctx.auth.use('jwt') for mobile API.
|
|
6
6
|
*/
|
|
7
7
|
import { SessionGuard } from './guards/session-guard.js';
|
|
8
8
|
import { JwtGuard } from './guards/jwt-guard.js';
|
|
@@ -28,10 +28,10 @@ export class Auth {
|
|
|
28
28
|
* Guards are lazily instantiated per request.
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
|
-
* //
|
|
31
|
+
* // Web session auth
|
|
32
32
|
* await ctx.auth.use('session').authenticate();
|
|
33
33
|
*
|
|
34
|
-
* //
|
|
34
|
+
* // Mobile / API JWT auth
|
|
35
35
|
* const user = await ctx.auth.use('jwt').authenticate();
|
|
36
36
|
*/
|
|
37
37
|
use(name) {
|
|
@@ -115,8 +115,8 @@ export function authPlugin(manager, sessionManager) {
|
|
|
115
115
|
* Throws UnauthorizedError if not authenticated.
|
|
116
116
|
*
|
|
117
117
|
* @example
|
|
118
|
-
* router.get('/
|
|
119
|
-
* router.get('/api/
|
|
118
|
+
* router.get('/dashboard', handler).middleware(auth('session'));
|
|
119
|
+
* router.get('/api/users', handler).middleware(auth('jwt'));
|
|
120
120
|
*/
|
|
121
121
|
export function auth(guardName) {
|
|
122
122
|
return async (ctx, next) => {
|
package/dist/auth/bouncer.d.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* - Policy-based authorization: ctx.bouncer.authorize(DiscountPolicy, 'approve', discount)
|
|
9
9
|
* - Data-scoped checks: enforcing branch-level data isolation
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
11
|
+
* Enterprise use:
|
|
12
|
+
* - Role-based authorization matrix
|
|
13
|
+
* - Maker-Checker dual control for approvals and transactions
|
|
14
|
+
* - Branch-scoped or organization-scoped data access
|
|
15
15
|
*/
|
|
16
16
|
import type { AuthUser } from '../auth/guards/guard.js';
|
|
17
17
|
import type { Middleware } from '../core/types.js';
|
|
@@ -22,7 +22,7 @@ export type PolicyConstructor = new () => PolicyContract;
|
|
|
22
22
|
export interface PermissionStore {
|
|
23
23
|
/**
|
|
24
24
|
* Returns all roles for a given user ID.
|
|
25
|
-
* Example: ['
|
|
25
|
+
* Example: ['member', 'editor', 'admin']
|
|
26
26
|
*/
|
|
27
27
|
getRoles(userId: string | number): Promise<string[]>;
|
|
28
28
|
/**
|
|
@@ -72,13 +72,7 @@ export declare class Bouncer {
|
|
|
72
72
|
*/
|
|
73
73
|
cannot(permission: string): Promise<boolean>;
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* Rules (Section 22):
|
|
78
|
-
* cashier → 0%
|
|
79
|
-
* supervisor → up to 5%
|
|
80
|
-
* ms → up to 15%
|
|
81
|
-
* director/ceo → unlimited
|
|
75
|
+
* Enterprise approval check: Check approval authority threshold based on role.
|
|
82
76
|
*
|
|
83
77
|
* @example
|
|
84
78
|
* if (!await ctx.bouncer.canApproveDiscount(12.5)) {
|
|
@@ -87,11 +81,10 @@ export declare class Bouncer {
|
|
|
87
81
|
*/
|
|
88
82
|
canApproveDiscount(percent: number): Promise<boolean>;
|
|
89
83
|
/**
|
|
90
|
-
*
|
|
91
|
-
* Enforces Section 25 — branch data scoping.
|
|
84
|
+
* Enterprise data scoping: Check if user belongs to a specific organizational branch or tenant.
|
|
92
85
|
*
|
|
93
86
|
* @example
|
|
94
|
-
* await ctx.bouncer.assertBranch(
|
|
87
|
+
* await ctx.bouncer.assertBranch(resource.branchId);
|
|
95
88
|
*/
|
|
96
89
|
assertBranch(resourceBranchId: string | number): Promise<void>;
|
|
97
90
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bouncer.d.ts","sourceRoot":"","sources":["../../src/auth/bouncer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,MAAM,WAAW,cAAc;IAC7B,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAClF;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,cAAc,CAAC;AAIzD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAErD;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC5D;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,KAAK,CAAC,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAqC;gBAEzC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,eAAe;IAK1D;;OAEG;YACW,SAAS;IAUvB;;OAEG;YACW,eAAe;IAU7B;;;;;OAKG;IACU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM/C;;;;;OAKG;IACU,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAMrD;;;;;OAKG;IACU,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMtD;;OAEG;IACU,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzD
|
|
1
|
+
{"version":3,"file":"bouncer.d.ts","sourceRoot":"","sources":["../../src/auth/bouncer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,MAAM,WAAW,cAAc;IAC7B,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAClF;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,cAAc,CAAC;AAIzD,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAErD;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC5D;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,KAAK,CAAC,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAqC;gBAEzC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,eAAe;IAK1D;;OAEG;YACW,SAAS;IAUvB;;OAEG;YACW,eAAe;IAU7B;;;;;OAKG;IACU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM/C;;;;;OAKG;IACU,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAMrD;;;;;OAKG;IACU,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMtD;;OAEG;IACU,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzD;;;;;;;OAOG;IACU,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlE;;;;;OAKG;IACU,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3E;;;;;;;OAOG;IACU,SAAS,CACpB,WAAW,EAAE,iBAAiB,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,OAAO,CAAC,IAAI,CAAC;IAqBhB;;OAEG;IACU,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD;;OAEG;IACU,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAK1D;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAC,CAAkB;IAEzB,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAKvC,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO;CAG/C;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAS1D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAOhE"}
|
package/dist/auth/bouncer.js
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* - Policy-based authorization: ctx.bouncer.authorize(DiscountPolicy, 'approve', discount)
|
|
9
9
|
* - Data-scoped checks: enforcing branch-level data isolation
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
11
|
+
* Enterprise use:
|
|
12
|
+
* - Role-based authorization matrix
|
|
13
|
+
* - Maker-Checker dual control for approvals and transactions
|
|
14
|
+
* - Branch-scoped or organization-scoped data access
|
|
15
15
|
*/
|
|
16
16
|
import { ForbiddenError, UnauthorizedError } from '../core/errors.js';
|
|
17
17
|
// ─── Bouncer Core ─────────────────────────────────────────────────────────────
|
|
@@ -96,13 +96,7 @@ export class Bouncer {
|
|
|
96
96
|
return !(await this.can(permission));
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* Rules (Section 22):
|
|
102
|
-
* cashier → 0%
|
|
103
|
-
* supervisor → up to 5%
|
|
104
|
-
* ms → up to 15%
|
|
105
|
-
* director/ceo → unlimited
|
|
99
|
+
* Enterprise approval check: Check approval authority threshold based on role.
|
|
106
100
|
*
|
|
107
101
|
* @example
|
|
108
102
|
* if (!await ctx.bouncer.canApproveDiscount(12.5)) {
|
|
@@ -115,18 +109,17 @@ export class Bouncer {
|
|
|
115
109
|
const roles = await this.loadRoles();
|
|
116
110
|
if (roles.includes('ceo') || roles.includes('director') || roles.includes('admin'))
|
|
117
111
|
return true;
|
|
118
|
-
if (roles.includes('
|
|
112
|
+
if (roles.includes('manager') || roles.includes('lead'))
|
|
119
113
|
return percent <= 15;
|
|
120
|
-
if (roles.includes('supervisor')
|
|
114
|
+
if (roles.includes('supervisor'))
|
|
121
115
|
return percent <= 5;
|
|
122
|
-
return percent <= 0;
|
|
116
|
+
return percent <= 0;
|
|
123
117
|
}
|
|
124
118
|
/**
|
|
125
|
-
*
|
|
126
|
-
* Enforces Section 25 — branch data scoping.
|
|
119
|
+
* Enterprise data scoping: Check if user belongs to a specific organizational branch or tenant.
|
|
127
120
|
*
|
|
128
121
|
* @example
|
|
129
|
-
* await ctx.bouncer.assertBranch(
|
|
122
|
+
* await ctx.bouncer.assertBranch(resource.branchId);
|
|
130
123
|
*/
|
|
131
124
|
async assertBranch(resourceBranchId) {
|
|
132
125
|
if (!this.user)
|