@shohaghinfo/aerojs 0.3.0 → 0.4.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.
- package/AGENTS.md +226 -0
- package/README.md +149 -9
- 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 +1 -1
- package/dist/cli/runner.js +1 -1
- package/dist/core/application.d.ts +10 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/application.js +13 -0
- package/dist/core/application.js.map +1 -1
- package/dist/core/context.d.ts +1 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +3 -0
- package/dist/core/context.js.map +1 -1
- package/dist/database/connection.d.ts +32 -0
- package/dist/database/connection.d.ts.map +1 -1
- package/dist/database/connection.js +51 -0
- package/dist/database/connection.js.map +1 -1
- package/dist/database/index.d.ts +1 -1
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +1 -1
- package/dist/database/index.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 +58 -58
- package/dist/database/model.d.ts.map +1 -1
- package/dist/database/model.js +133 -71
- package/dist/database/model.js.map +1 -1
- package/dist/database/query-builder.d.ts +24 -7
- package/dist/database/query-builder.d.ts.map +1 -1
- package/dist/database/query-builder.js +88 -37
- package/dist/database/query-builder.js.map +1 -1
- 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 +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- 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/queue/dashboard.d.ts +30 -0
- package/dist/queue/dashboard.d.ts.map +1 -0
- package/dist/queue/dashboard.js +371 -0
- package/dist/queue/dashboard.js.map +1 -0
- package/dist/queue/index.d.ts +1 -0
- package/dist/queue/index.d.ts.map +1 -1
- package/dist/queue/index.js +1 -0
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/queue-manager.d.ts +31 -1
- package/dist/queue/queue-manager.d.ts.map +1 -1
- package/dist/queue/queue-manager.js +60 -0
- package/dist/queue/queue-manager.js.map +1 -1
- package/dist/queue/worker.d.ts +3 -0
- package/dist/queue/worker.d.ts.map +1 -1
- package/dist/queue/worker.js +9 -0
- package/dist/queue/worker.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts +5 -5
- package/dist/scheduler/scheduler.js +5 -5
- package/dist/security/encryption.d.ts +60 -0
- package/dist/security/encryption.d.ts.map +1 -0
- package/dist/security/encryption.js +120 -0
- package/dist/security/encryption.js.map +1 -0
- package/dist/security/fingerprint.d.ts +47 -0
- package/dist/security/fingerprint.d.ts.map +1 -0
- package/dist/security/fingerprint.js +83 -0
- package/dist/security/fingerprint.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +2 -0
- package/dist/security/index.js.map +1 -1
- package/dist/session/cookie-session-driver.d.ts +34 -0
- package/dist/session/cookie-session-driver.d.ts.map +1 -0
- package/dist/session/cookie-session-driver.js +57 -0
- package/dist/session/cookie-session-driver.js.map +1 -0
- package/dist/session/index.d.ts +8 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- 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.d.ts.map +1 -1
- package/dist/session/session-manager.js +10 -5
- package/dist/session/session-manager.js.map +1 -1
- package/dist/tcp/mllp.d.ts +1 -1
- package/dist/tcp/mllp.js +2 -2
- package/dist/tcp/mllp.js.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -707,3 +707,229 @@ When asked to build or modify any feature in an AeroJS project:
|
|
|
707
707
|
npm run build
|
|
708
708
|
npm test
|
|
709
709
|
```
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## 11. Enterprise Capabilities Reference (v0.3.0)
|
|
714
|
+
|
|
715
|
+
### 11.1 Fluent HTTP Client (`Http`)
|
|
716
|
+
```typescript
|
|
717
|
+
import { Http } from 'aerojs';
|
|
718
|
+
|
|
719
|
+
const res = await Http.baseUrl('https://api.example.com')
|
|
720
|
+
.withToken('auth-token')
|
|
721
|
+
.timeout(5000)
|
|
722
|
+
.retry(3, 100)
|
|
723
|
+
.get('/data', { page: 1 });
|
|
724
|
+
|
|
725
|
+
if (res.successful) {
|
|
726
|
+
const data = res.json();
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### 11.2 SMTP Mail Transport (`Mail`)
|
|
731
|
+
```typescript
|
|
732
|
+
import { Mail } from 'aerojs';
|
|
733
|
+
|
|
734
|
+
Mail.configure({
|
|
735
|
+
default: 'smtp',
|
|
736
|
+
mailers: {
|
|
737
|
+
smtp: {
|
|
738
|
+
driver: 'smtp',
|
|
739
|
+
host: process.env.SMTP_HOST || '127.0.0.1',
|
|
740
|
+
port: Number(process.env.SMTP_PORT) || 587,
|
|
741
|
+
auth: { user: process.env.SMTP_USER!, pass: process.env.SMTP_PASS! },
|
|
742
|
+
},
|
|
743
|
+
},
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
await Mail.send((msg) => {
|
|
747
|
+
msg.to('user@example.com')
|
|
748
|
+
.subject('Welcome')
|
|
749
|
+
.html('<h1>Welcome to AeroJS</h1>');
|
|
750
|
+
});
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### 11.3 Redis Rate Limiter & Redis Queue
|
|
754
|
+
```typescript
|
|
755
|
+
import { rateLimit, RedisRateLimitStore, RedisClient, Queue } from 'aerojs';
|
|
756
|
+
|
|
757
|
+
const redis = new RedisClient({ host: '127.0.0.1', port: 6379 });
|
|
758
|
+
|
|
759
|
+
// Rate Limiter
|
|
760
|
+
app.use(rateLimit({
|
|
761
|
+
windowMs: 60_000,
|
|
762
|
+
max: 100,
|
|
763
|
+
store: new RedisRateLimitStore({ client: redis, prefix: 'rl:api:' }),
|
|
764
|
+
}));
|
|
765
|
+
|
|
766
|
+
// Queue
|
|
767
|
+
Queue.configure({
|
|
768
|
+
default: 'redis',
|
|
769
|
+
connections: {
|
|
770
|
+
redis: { driver: 'redis', redis },
|
|
771
|
+
},
|
|
772
|
+
});
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### 11.4 OAuth 2.0 Social Login (`OAuth`)
|
|
776
|
+
```typescript
|
|
777
|
+
import { OAuth } from 'aerojs';
|
|
778
|
+
|
|
779
|
+
router.get('/auth/google', (ctx) => ctx.redirect(OAuth.driver('google').getRedirectUrl()));
|
|
780
|
+
router.get('/auth/google/callback', async (ctx) => {
|
|
781
|
+
const { user } = await OAuth.driver('google').handleCallback(ctx.query.code as string);
|
|
782
|
+
ctx.json({ user });
|
|
783
|
+
});
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### 11.5 Multi-Channel Notifications (`Notifications`, `Notification`)
|
|
787
|
+
```typescript
|
|
788
|
+
import { Notification, Notifications, MailMessage } from 'aerojs';
|
|
789
|
+
|
|
790
|
+
class OrderAlertNotification extends Notification {
|
|
791
|
+
via() { return ['mail', 'database', 'broadcast']; }
|
|
792
|
+
toMail(u: any) { return new MailMessage().subject('Alert').text('Hello'); }
|
|
793
|
+
toDatabase(u: any) { return { alert: 'Order Confirmed' }; }
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
await Notifications.send(user, new OrderAlertNotification());
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### 11.6 Tamper-Proof Signed URLs (`UrlSigner`, `validateSignedUrl`)
|
|
800
|
+
```typescript
|
|
801
|
+
import { UrlSigner, validateSignedUrl, Storage } from 'aerojs';
|
|
802
|
+
|
|
803
|
+
// Generate temporary signed link
|
|
804
|
+
const downloadUrl = await Storage.temporaryUrl('invoices/inv-101.pdf', 900);
|
|
805
|
+
|
|
806
|
+
// Validate in route
|
|
807
|
+
router.get('/secure/download', validateSignedUrl(), async (ctx) => {
|
|
808
|
+
ctx.json({ secure: true });
|
|
809
|
+
});
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### 11.7 Extended CLI Generators (`aero make:*`)
|
|
813
|
+
```bash
|
|
814
|
+
aero make:job ProcessPayment
|
|
815
|
+
aero make:mail OrderReceipt
|
|
816
|
+
aero make:policy PostPolicy
|
|
817
|
+
aero make:event UserRegistered
|
|
818
|
+
aero make:listener SendWelcomeNotification
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
---
|
|
822
|
+
|
|
823
|
+
## 12. Advanced Enterprise Architecture (v0.4.0)
|
|
824
|
+
|
|
825
|
+
### 12.1 Field-Level AES-256-GCM Encryption (`Crypt`, `@encrypted`)
|
|
826
|
+
Protect sensitive compliance data (SSN, tax records, credentials, confidential notes) transparently at rest:
|
|
827
|
+
|
|
828
|
+
```typescript
|
|
829
|
+
import { Model, encrypted, Crypt } from 'aerojs';
|
|
830
|
+
|
|
831
|
+
// Encrypt standalone strings or objects
|
|
832
|
+
const ciphertext = Crypt.encrypt('secret-data');
|
|
833
|
+
const plaintext = Crypt.decrypt(ciphertext);
|
|
834
|
+
|
|
835
|
+
// Model field-level transparent encryption
|
|
836
|
+
export class AccountRecord extends Model {
|
|
837
|
+
public static override table = 'accounts';
|
|
838
|
+
public static override primaryKey = 'id';
|
|
839
|
+
public static override fillable = ['name', 'ssn', 'private_notes'];
|
|
840
|
+
|
|
841
|
+
// Mark fields for automatic AES-256-GCM encryption
|
|
842
|
+
public static override encrypted = ['ssn', 'private_notes'];
|
|
843
|
+
|
|
844
|
+
// Or use TypeScript property decorator:
|
|
845
|
+
// @encrypted()
|
|
846
|
+
// public ssn!: string;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Automatically encrypted on .save() and decrypted on .find() / .all() / .toJSON()
|
|
850
|
+
const account = await AccountRecord.create({
|
|
851
|
+
name: 'John Doe',
|
|
852
|
+
ssn: '123-45-6789',
|
|
853
|
+
private_notes: 'Confidential client notes',
|
|
854
|
+
});
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### 12.2 Database Read Replicas & Master-Slave Routing
|
|
858
|
+
Scale database read throughput across horizontal replica pools with automatic write pinning and master-slave routing:
|
|
859
|
+
|
|
860
|
+
```typescript
|
|
861
|
+
import { Database, DB } from 'aerojs';
|
|
862
|
+
|
|
863
|
+
Database.configureReplication({
|
|
864
|
+
write: { client: 'pg', connection: { host: 'primary.db.internal' } },
|
|
865
|
+
read: [
|
|
866
|
+
{ client: 'pg', connection: { host: 'replica-1.db.internal' } },
|
|
867
|
+
{ client: 'pg', connection: { host: 'replica-2.db.internal' } },
|
|
868
|
+
],
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
// SELECT queries automatically balance across replicas in round-robin:
|
|
872
|
+
const users = await DB.table('users').where('is_active', true).get();
|
|
873
|
+
|
|
874
|
+
// INSERT / UPDATE / DELETE automatically target the primary write connection:
|
|
875
|
+
await DB.table('users').insert({ name: 'Alice', email: 'alice@example.com' });
|
|
876
|
+
|
|
877
|
+
// Read-your-own-writes consistency via .useWriteConnection():
|
|
878
|
+
const freshUser = await DB.table('users').useWriteConnection().where('email', 'alice@example.com').first();
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### 12.3 Interactive Queue Horizon Dashboard
|
|
882
|
+
A dark-mode glassmorphic real-time administration dashboard for inspecting background job queues and metrics:
|
|
883
|
+
|
|
884
|
+
```typescript
|
|
885
|
+
import { app } from './bootstrap.js';
|
|
886
|
+
|
|
887
|
+
// Mount real-time queue inspector GUI & REST API
|
|
888
|
+
app.useQueueDashboard('/__aero/queue', {
|
|
889
|
+
auth: (ctx) => ctx.state?.user?.role === 'admin', // Optional authorization guard
|
|
890
|
+
});
|
|
891
|
+
```
|
|
892
|
+
- Web UI: Navigate to `http://localhost:3000/__aero/queue`
|
|
893
|
+
- REST Endpoints:
|
|
894
|
+
- `GET /__aero/queue/api/metrics` — Active jobs, processed counts, failure rates, queue throughput.
|
|
895
|
+
- `GET /__aero/queue/api/failed` — Failed job payloads, error messages, and stack traces.
|
|
896
|
+
- `POST /__aero/queue/api/retry/:id` — Instant dead-letter job retry.
|
|
897
|
+
- `POST /__aero/queue/api/retry-all` — Batch retry all failed jobs.
|
|
898
|
+
- `DELETE /__aero/queue/api/purge-all` — Purge failed jobs.
|
|
899
|
+
|
|
900
|
+
### 12.4 Encrypted Stateless Cookie Session Driver
|
|
901
|
+
Stateless, horizontally scalable user session storage secured via AES-256-GCM authenticated encryption:
|
|
902
|
+
|
|
903
|
+
```typescript
|
|
904
|
+
import { SessionManager, CookieSessionDriver } from 'aerojs';
|
|
905
|
+
|
|
906
|
+
const sessionManager = new SessionManager({
|
|
907
|
+
driver: 'cookie',
|
|
908
|
+
secret: process.env.APP_KEY, // 32-byte secret key
|
|
909
|
+
cookie: {
|
|
910
|
+
name: 'aero_session',
|
|
911
|
+
httpOnly: true,
|
|
912
|
+
secure: true,
|
|
913
|
+
sameSite: 'lax',
|
|
914
|
+
},
|
|
915
|
+
});
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
### 12.5 Request Fingerprinting & Anti-Hijack Guard
|
|
919
|
+
Prevent session hijacking and credential replay attacks across network switches or spoofed browsers:
|
|
920
|
+
|
|
921
|
+
```typescript
|
|
922
|
+
import { fingerprintGuard, RequestFingerprint } from 'aerojs';
|
|
923
|
+
|
|
924
|
+
// Generate or inspect request fingerprint
|
|
925
|
+
const hash = RequestFingerprint.generate(ctx, { checkIp: false });
|
|
926
|
+
|
|
927
|
+
// Bind to security middleware stack
|
|
928
|
+
app.use(fingerprintGuard({
|
|
929
|
+
strict: true,
|
|
930
|
+
checkIp: false, // Set true for high-security intranets or false for mobile networks
|
|
931
|
+
onHijackAttempt: (ctx, expected, actual) => {
|
|
932
|
+
ctx.logger?.warn(`Session hijacking attempt detected: expected ${expected}, got ${actual}`);
|
|
933
|
+
},
|
|
934
|
+
}));
|
|
935
|
+
```
|
package/README.md
CHANGED
|
@@ -1225,10 +1225,10 @@ Mail.configure({
|
|
|
1225
1225
|
|
|
1226
1226
|
// 2. Dispatch with attachments & HTML
|
|
1227
1227
|
await Mail.send((msg) => {
|
|
1228
|
-
msg.to('
|
|
1229
|
-
.from('billing@
|
|
1228
|
+
msg.to('customer@example.com')
|
|
1229
|
+
.from('billing@example.org', 'Billing Department')
|
|
1230
1230
|
.subject('Monthly Statement & Invoice')
|
|
1231
|
-
.html('<h1>Hello!</h1><p>Please find your
|
|
1231
|
+
.html('<h1>Hello!</h1><p>Please find your monthly invoice attached.</p>')
|
|
1232
1232
|
.attach('invoice.pdf', pdfBuffer, 'application/pdf');
|
|
1233
1233
|
});
|
|
1234
1234
|
```
|
|
@@ -1306,25 +1306,25 @@ AeroJS ships with a powerful, zero-dependency fluent HTTP client built on native
|
|
|
1306
1306
|
import { Http } from '@shohaghinfo/aerojs';
|
|
1307
1307
|
|
|
1308
1308
|
// 1. Fluent API calls
|
|
1309
|
-
const response = await Http.baseUrl('https://api.
|
|
1309
|
+
const response = await Http.baseUrl('https://api.example.com/v1')
|
|
1310
1310
|
.withToken(process.env.API_KEY!)
|
|
1311
1311
|
.withQuery({ status: 'active', limit: 50 })
|
|
1312
1312
|
.timeout(5000)
|
|
1313
1313
|
.retry(3, 200)
|
|
1314
|
-
.get('/
|
|
1314
|
+
.get('/users');
|
|
1315
1315
|
|
|
1316
1316
|
if (response.successful) {
|
|
1317
|
-
const
|
|
1318
|
-
console.log('
|
|
1317
|
+
const users = response.json();
|
|
1318
|
+
console.log('Users fetched:', users);
|
|
1319
1319
|
}
|
|
1320
1320
|
|
|
1321
1321
|
// 2. Testing Fakes (Mocking external services)
|
|
1322
1322
|
Http.fake({
|
|
1323
|
-
'/
|
|
1323
|
+
'/users': [{ id: 1, name: 'Alice Smith' }],
|
|
1324
1324
|
'/billing': Http.response({ invoiceId: 'INV-101' }, 201),
|
|
1325
1325
|
});
|
|
1326
1326
|
|
|
1327
|
-
const res = await Http.post('https://api.
|
|
1327
|
+
const res = await Http.post('https://api.example.com/v1/billing', { amount: 500 });
|
|
1328
1328
|
expect(res.status).toBe(201);
|
|
1329
1329
|
|
|
1330
1330
|
Http.assertSent((req) => req.url.includes('/billing') && req.method === 'POST');
|
|
@@ -1439,6 +1439,146 @@ if (!ctx.hasValidSignature()) {
|
|
|
1439
1439
|
|
|
1440
1440
|
---
|
|
1441
1441
|
|
|
1442
|
+
### 38. Field-Level Database Encryption (`@encrypted()` & `Crypt`)
|
|
1443
|
+
|
|
1444
|
+
Ensure HIPAA, GDPR, and PCI-DSS compliance by transparently encrypting sensitive database columns at rest using authenticated **AES-256-GCM** encryption:
|
|
1445
|
+
|
|
1446
|
+
```typescript
|
|
1447
|
+
import { Model, encrypted, Crypt } from '@shohaghinfo/aerojs';
|
|
1448
|
+
|
|
1449
|
+
class AccountRecord extends Model {
|
|
1450
|
+
public static override table = 'accounts';
|
|
1451
|
+
public static override fillable = ['name', 'ssn', 'private_notes'];
|
|
1452
|
+
public static override encrypted = ['ssn', 'private_notes'];
|
|
1453
|
+
|
|
1454
|
+
@encrypted()
|
|
1455
|
+
public ssn!: string;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
// 1. Create - Data is stored as aero:enc:<iv>:<tag>:<ciphertext> in the database
|
|
1459
|
+
const account = await AccountRecord.create({
|
|
1460
|
+
name: 'Rahim Khan',
|
|
1461
|
+
ssn: '019-99-8888',
|
|
1462
|
+
private_notes: 'Confidential client information',
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
// 2. Read - Transparently decrypted on fetch
|
|
1466
|
+
const loaded = await AccountRecord.find(account.id);
|
|
1467
|
+
console.log(loaded.ssn); // '019-99-8888' (Plaintext in app code)
|
|
1468
|
+
|
|
1469
|
+
// 3. Arbitrary payload encryption via Crypt facade:
|
|
1470
|
+
const cipher = Crypt.encrypt({ account: '123456', balance: 5000 });
|
|
1471
|
+
const data = Crypt.decrypt(cipher);
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
---
|
|
1475
|
+
|
|
1476
|
+
### 39. Database Read Replicas & Master-Slave Routing
|
|
1477
|
+
|
|
1478
|
+
Route all high-volume read traffic to replica pools with round-robin load distribution while ensuring writes and transactions hit the primary master:
|
|
1479
|
+
|
|
1480
|
+
```typescript
|
|
1481
|
+
import { Database, DB } from '@shohaghinfo/aerojs';
|
|
1482
|
+
|
|
1483
|
+
// Configure replication pool
|
|
1484
|
+
Database.configureReplication({
|
|
1485
|
+
write: 'primary_master',
|
|
1486
|
+
read: ['replica_east_1', 'replica_east_2', 'replica_west_1'],
|
|
1487
|
+
});
|
|
1488
|
+
|
|
1489
|
+
// 1. Automatically queries a read replica (round-robin balanced)
|
|
1490
|
+
const users = await DB.table('users').where('active', true).get();
|
|
1491
|
+
|
|
1492
|
+
// 2. Force reading from the master node for read-your-own-writes consistency
|
|
1493
|
+
const freshUser = await DB.table('users').useWriteConnection().where('id', 1).first();
|
|
1494
|
+
|
|
1495
|
+
// 3. Direct write queries always execute on the primary write database
|
|
1496
|
+
await DB.table('users').where('id', 1).update({ status: 'verified' });
|
|
1497
|
+
```
|
|
1498
|
+
|
|
1499
|
+
---
|
|
1500
|
+
|
|
1501
|
+
### 40. Interactive Queue Horizon Dashboard (`app.useQueueDashboard`)
|
|
1502
|
+
|
|
1503
|
+
A built-in, dark-mode developer control panel for real-time background task monitoring and failure recovery:
|
|
1504
|
+
|
|
1505
|
+
```typescript
|
|
1506
|
+
import { Aero } from '@shohaghinfo/aerojs';
|
|
1507
|
+
|
|
1508
|
+
const app = new Aero();
|
|
1509
|
+
|
|
1510
|
+
// Mount the dashboard with optional role-based protection
|
|
1511
|
+
app.useQueueDashboard('/__aero/queue', {
|
|
1512
|
+
title: 'AeroJS Queue Horizon',
|
|
1513
|
+
pollInterval: 3, // auto-refresh every 3s
|
|
1514
|
+
auth: (ctx) => ctx.session?.get('user')?.role === 'superadmin',
|
|
1515
|
+
});
|
|
1516
|
+
```
|
|
1517
|
+
|
|
1518
|
+
- **Live GUI (`GET /__aero/queue`)**: Glassmorphic dark UI with live throughput KPI cards, queues status, and dead letter queue inspector.
|
|
1519
|
+
- **REST APIs**:
|
|
1520
|
+
- `GET /__aero/queue/api/metrics` — JSON statistics
|
|
1521
|
+
- `GET /__aero/queue/api/failed` — List dead-letter failed jobs with full stack traces
|
|
1522
|
+
- `POST /__aero/queue/api/retry/:id` — Retry single failed task
|
|
1523
|
+
- `DELETE /__aero/queue/api/failed/:id` — Delete failed task
|
|
1524
|
+
- `POST /__aero/queue/api/retry-all` — Batch retry all failed jobs
|
|
1525
|
+
- `DELETE /__aero/queue/api/purge-all` — Purge dead letter queue
|
|
1526
|
+
|
|
1527
|
+
---
|
|
1528
|
+
|
|
1529
|
+
### 41. Encrypted Stateless Cookie Session Driver (`CookieSessionDriver`)
|
|
1530
|
+
|
|
1531
|
+
Store session state entirely on the client within an encrypted, authenticated, and tamper-proof HTTP-only cookie using AES-256-GCM. Ideal for serverless, Edge, and horizontal autoscaling:
|
|
1532
|
+
|
|
1533
|
+
```typescript
|
|
1534
|
+
import { Aero, sessionPlugin, CookieSessionDriver } from '@shohaghinfo/aerojs';
|
|
1535
|
+
|
|
1536
|
+
const app = new Aero();
|
|
1537
|
+
|
|
1538
|
+
app.use(sessionPlugin({
|
|
1539
|
+
driver: new CookieSessionDriver(),
|
|
1540
|
+
cookieName: 'aero_session',
|
|
1541
|
+
lifetime: 8 * 3600, // 8-hour shift
|
|
1542
|
+
cookie: { httpOnly: true, secure: true, sameSite: 'lax' },
|
|
1543
|
+
}));
|
|
1544
|
+
|
|
1545
|
+
app.post('/login', async (ctx) => {
|
|
1546
|
+
await ctx.session.put('user', { id: 1, role: 'physician' });
|
|
1547
|
+
ctx.json({ loggedIn: true });
|
|
1548
|
+
});
|
|
1549
|
+
```
|
|
1550
|
+
|
|
1551
|
+
---
|
|
1552
|
+
|
|
1553
|
+
### 42. Client Request Fingerprinting & Anti-Hijacking Guard
|
|
1554
|
+
|
|
1555
|
+
Prevent stolen session cookies and session fixation attacks by fingerprinting client browser characteristics (User-Agent, client IP, accept headers):
|
|
1556
|
+
|
|
1557
|
+
```typescript
|
|
1558
|
+
import { Aero, sessionPlugin, fingerprintGuard, RequestFingerprint } from '@shohaghinfo/aerojs';
|
|
1559
|
+
|
|
1560
|
+
const app = new Aero();
|
|
1561
|
+
app.use(sessionPlugin());
|
|
1562
|
+
|
|
1563
|
+
// Automatically binds and verifies client fingerprint on every session request
|
|
1564
|
+
app.use(fingerprintGuard({
|
|
1565
|
+
ip: true,
|
|
1566
|
+
userAgent: true,
|
|
1567
|
+
acceptLanguage: true,
|
|
1568
|
+
onMismatch: (ctx) => {
|
|
1569
|
+
ctx.status(401).json({ error: 'Session hijacked from an unauthorized device' });
|
|
1570
|
+
},
|
|
1571
|
+
}));
|
|
1572
|
+
|
|
1573
|
+
// Or generate manually for audit logs:
|
|
1574
|
+
app.get('/audit', (ctx) => {
|
|
1575
|
+
const fp = RequestFingerprint.generate(ctx);
|
|
1576
|
+
ctx.json({ fingerprint: fp });
|
|
1577
|
+
});
|
|
1578
|
+
```
|
|
1579
|
+
|
|
1580
|
+
---
|
|
1581
|
+
|
|
1442
1582
|
## 📊 Comparison Matrix
|
|
1443
1583
|
|
|
1444
1584
|
| Feature | Express | Koa | Fastify | AdonisJS | **AeroJS** |
|
|
@@ -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"}
|