@aifabrix/miso-client 2.0.0 → 2.1.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/README.md +231 -2
- package/dist/express/async-handler.d.ts +41 -0
- package/dist/express/async-handler.d.ts.map +1 -0
- package/dist/express/async-handler.js +58 -0
- package/dist/express/async-handler.js.map +1 -0
- package/dist/express/encryption.d.ts +29 -0
- package/dist/express/encryption.d.ts.map +1 -0
- package/dist/express/encryption.js +95 -0
- package/dist/express/encryption.js.map +1 -0
- package/dist/express/error-handler.d.ts +23 -0
- package/dist/express/error-handler.d.ts.map +1 -0
- package/dist/express/error-handler.js +140 -0
- package/dist/express/error-handler.js.map +1 -0
- package/dist/express/error-response.d.ts +55 -0
- package/dist/express/error-response.d.ts.map +1 -0
- package/dist/express/error-response.js +95 -0
- package/dist/express/error-response.js.map +1 -0
- package/dist/express/error-types.d.ts +46 -0
- package/dist/express/error-types.d.ts.map +1 -0
- package/dist/express/error-types.js +93 -0
- package/dist/express/error-types.js.map +1 -0
- package/dist/express/express.d.ts +47 -0
- package/dist/express/index.d.ts +14 -0
- package/dist/express/index.d.ts.map +1 -0
- package/dist/express/index.js +39 -0
- package/dist/express/index.js.map +1 -0
- package/dist/express/response-helper.d.ts +67 -0
- package/dist/express/response-helper.d.ts.map +1 -0
- package/dist/express/response-helper.js +83 -0
- package/dist/express/response-helper.js.map +1 -0
- package/dist/express/response-middleware.d.ts +18 -0
- package/dist/express/response-middleware.d.ts.map +1 -0
- package/dist/express/response-middleware.js +29 -0
- package/dist/express/response-middleware.js.map +1 -0
- package/dist/express/validation-helper.d.ts +66 -0
- package/dist/express/validation-helper.d.ts.map +1 -0
- package/dist/express/validation-helper.js +102 -0
- package/dist/express/validation-helper.js.map +1 -0
- package/dist/index.d.ts +23 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -23
- package/dist/index.js.map +1 -1
- package/dist/services/auth.service.d.ts +3 -3
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +24 -18
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/cache.service.d.ts +1 -1
- package/dist/services/cache.service.d.ts.map +1 -1
- package/dist/services/cache.service.js +1 -1
- package/dist/services/cache.service.js.map +1 -1
- package/dist/services/logger.service.d.ts +3 -3
- package/dist/services/logger.service.d.ts.map +1 -1
- package/dist/services/logger.service.js +32 -25
- package/dist/services/logger.service.js.map +1 -1
- package/dist/services/permission.service.d.ts +3 -3
- package/dist/services/permission.service.d.ts.map +1 -1
- package/dist/services/permission.service.js +9 -6
- package/dist/services/permission.service.js.map +1 -1
- package/dist/services/redis.service.d.ts +1 -1
- package/dist/services/redis.service.js +10 -10
- package/dist/services/role.service.d.ts +3 -3
- package/dist/services/role.service.d.ts.map +1 -1
- package/dist/services/role.service.js +8 -5
- package/dist/services/role.service.js.map +1 -1
- package/dist/types/config.types.d.ts +4 -4
- package/dist/types/config.types.d.ts.map +1 -1
- package/dist/types/config.types.js +6 -5
- package/dist/types/config.types.js.map +1 -1
- package/dist/types/filter.types.d.ts +1 -1
- package/dist/types/filter.types.d.ts.map +1 -1
- package/dist/types/filter.types.js +2 -2
- package/dist/types/filter.types.js.map +1 -1
- package/dist/types/sort.types.d.ts +1 -1
- package/dist/utils/audit-log-queue.d.ts +4 -4
- package/dist/utils/audit-log-queue.d.ts.map +1 -1
- package/dist/utils/audit-log-queue.js +11 -11
- package/dist/utils/audit-log-queue.js.map +1 -1
- package/dist/utils/auth-strategy.d.ts +1 -1
- package/dist/utils/auth-strategy.d.ts.map +1 -1
- package/dist/utils/auth-strategy.js +19 -17
- package/dist/utils/auth-strategy.js.map +1 -1
- package/dist/utils/config-loader.d.ts +2 -2
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +11 -10
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/data-masker.d.ts.map +1 -1
- package/dist/utils/data-masker.js +7 -7
- package/dist/utils/data-masker.js.map +1 -1
- package/dist/utils/errors.d.ts +2 -2
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +37 -30
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/filter.utils.d.ts +2 -2
- package/dist/utils/filter.utils.d.ts.map +1 -1
- package/dist/utils/filter.utils.js +24 -18
- package/dist/utils/filter.utils.js.map +1 -1
- package/dist/utils/http-client-audit.d.ts +4 -4
- package/dist/utils/http-client-audit.d.ts.map +1 -1
- package/dist/utils/http-client-audit.js +30 -22
- package/dist/utils/http-client-audit.js.map +1 -1
- package/dist/utils/http-client-masking.d.ts +1 -1
- package/dist/utils/http-client-masking.d.ts.map +1 -1
- package/dist/utils/http-client-masking.js +31 -21
- package/dist/utils/http-client-masking.js.map +1 -1
- package/dist/utils/http-client-metadata.d.ts +2 -2
- package/dist/utils/http-client-metadata.d.ts.map +1 -1
- package/dist/utils/http-client-metadata.js +7 -7
- package/dist/utils/http-client-metadata.js.map +1 -1
- package/dist/utils/http-client.d.ts +6 -6
- package/dist/utils/http-client.d.ts.map +1 -1
- package/dist/utils/http-client.js +8 -9
- package/dist/utils/http-client.js.map +1 -1
- package/dist/utils/internal-http-client.d.ts +5 -5
- package/dist/utils/internal-http-client.d.ts.map +1 -1
- package/dist/utils/internal-http-client.js +48 -42
- package/dist/utils/internal-http-client.js.map +1 -1
- package/dist/utils/pagination.utils.d.ts +1 -1
- package/dist/utils/pagination.utils.d.ts.map +1 -1
- package/dist/utils/pagination.utils.js +3 -3
- package/dist/utils/pagination.utils.js.map +1 -1
- package/dist/utils/sensitive-fields.loader.d.ts.map +1 -1
- package/dist/utils/sensitive-fields.loader.js +77 -60
- package/dist/utils/sensitive-fields.loader.js.map +1 -1
- package/dist/utils/sort.utils.d.ts +14 -3
- package/dist/utils/sort.utils.d.ts.map +1 -1
- package/dist/utils/sort.utils.js +73 -9
- package/dist/utils/sort.utils.js.map +1 -1
- package/package.json +12 -3
- package/dist/services/encryption.service.d.ts +0 -32
- package/dist/services/encryption.service.d.ts.map +0 -1
- package/dist/services/encryption.service.js +0 -135
- package/dist/services/encryption.service.js.map +0 -1
package/README.md
CHANGED
|
@@ -10,18 +10,21 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
10
10
|
### 🔐 Enterprise Security
|
|
11
11
|
|
|
12
12
|
**SSO and Federated Identity**
|
|
13
|
+
|
|
13
14
|
- Single Sign-On (SSO) with Keycloak
|
|
14
15
|
- OAuth 2.0 and OpenID Connect (OIDC) support
|
|
15
16
|
- Multi-factor authentication (MFA) ready
|
|
16
17
|
- Social login integration (Google, Microsoft, etc.)
|
|
17
18
|
|
|
18
19
|
**Centralized Access Control**
|
|
20
|
+
|
|
19
21
|
- Role-based access control (RBAC)
|
|
20
22
|
- Fine-grained permissions
|
|
21
23
|
- Dynamic policy enforcement
|
|
22
24
|
- Attribute-based access control (ABAC)
|
|
23
25
|
|
|
24
26
|
**API Security**
|
|
27
|
+
|
|
25
28
|
- JWT token validation
|
|
26
29
|
- API key authentication
|
|
27
30
|
- Token revocation support
|
|
@@ -31,24 +34,28 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
31
34
|
### 📊 Compliance & Audit
|
|
32
35
|
|
|
33
36
|
**ISO 27001 Compliance**
|
|
37
|
+
|
|
34
38
|
- Comprehensive audit trails for all user actions
|
|
35
39
|
- Data access logging and monitoring
|
|
36
40
|
- Security event tracking
|
|
37
41
|
- Accountability and non-repudiation
|
|
38
42
|
|
|
39
43
|
**Regulatory Compliance**
|
|
44
|
+
|
|
40
45
|
- GDPR-ready data protection
|
|
41
46
|
- HIPAA-compliant audit logging
|
|
42
47
|
- SOC 2 audit trail requirements
|
|
43
48
|
- Industry-standard security controls
|
|
44
49
|
|
|
45
50
|
**Audit Capabilities**
|
|
51
|
+
|
|
46
52
|
- Real-time audit event logging
|
|
47
53
|
- Immutable audit records
|
|
48
54
|
- Forensic analysis support
|
|
49
55
|
- Compliance reporting automation
|
|
50
56
|
|
|
51
57
|
**HTTP Request Audit (ISO 27001 Compliant)**
|
|
58
|
+
|
|
52
59
|
- Automatic audit logging for all HTTP requests
|
|
53
60
|
- Sensitive data masking (passwords, tokens, PII, financial data)
|
|
54
61
|
- Configurable sensitive fields via JSON configuration
|
|
@@ -59,6 +66,7 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
59
66
|
### ⚡ Performance & Scalability
|
|
60
67
|
|
|
61
68
|
**Intelligent Caching**
|
|
69
|
+
|
|
62
70
|
- Redis-based role and permission caching
|
|
63
71
|
- Generic cache service with Redis and in-memory fallback
|
|
64
72
|
- Configurable cache TTL (default: 15 minutes)
|
|
@@ -66,12 +74,14 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
66
74
|
- Fallback to controller when Redis unavailable
|
|
67
75
|
|
|
68
76
|
**High Availability**
|
|
77
|
+
|
|
69
78
|
- Automatic failover to controller
|
|
70
79
|
- Redundant infrastructure support
|
|
71
80
|
- Load balancing compatible
|
|
72
81
|
- Zero-downtime deployments
|
|
73
82
|
|
|
74
83
|
**Optimized Network**
|
|
84
|
+
|
|
75
85
|
- Efficient API calls with caching
|
|
76
86
|
- Batch operations support
|
|
77
87
|
- Connection pooling
|
|
@@ -80,18 +90,21 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
80
90
|
### 🛠️ Developer Experience
|
|
81
91
|
|
|
82
92
|
**Easy Integration**
|
|
93
|
+
|
|
83
94
|
- Progressive activation (6-step setup)
|
|
84
95
|
- Works with any framework (Express, Next.js, NestJS, Fastify)
|
|
85
96
|
- TypeScript-first with full type definitions
|
|
86
97
|
- Browser and Node.js support
|
|
87
98
|
|
|
88
99
|
**Flexible Configuration**
|
|
100
|
+
|
|
89
101
|
- Environment-based configuration
|
|
90
102
|
- Support for dev, test, and production environments
|
|
91
103
|
- Docker and Kubernetes ready
|
|
92
104
|
- CI/CD friendly
|
|
93
105
|
|
|
94
106
|
**Observability**
|
|
107
|
+
|
|
95
108
|
- Centralized logging with correlation IDs
|
|
96
109
|
- Performance tracking and metrics
|
|
97
110
|
- Error tracking and debugging
|
|
@@ -166,7 +179,7 @@ aifabrix run miso-controller
|
|
|
166
179
|
|
|
167
180
|
---
|
|
168
181
|
|
|
169
|
-
##
|
|
182
|
+
## 🔍 How It Works
|
|
170
183
|
|
|
171
184
|
**What happens:** Your app validates user tokens from Keycloak.
|
|
172
185
|
|
|
@@ -345,6 +358,7 @@ MISO_SENSITIVE_FIELDS_CONFIG=/path/to/sensitive-fields.config.json
|
|
|
345
358
|
|
|
346
359
|
**Built-in Performance Optimizations:**
|
|
347
360
|
The SDK automatically optimizes audit logging performance:
|
|
361
|
+
|
|
348
362
|
- Automatic response body truncation for large payloads
|
|
349
363
|
- Optimized masking operations with intelligent size-based processing
|
|
350
364
|
- Batch logging to minimize network overhead
|
|
@@ -366,12 +380,14 @@ const client = new MisoClient({
|
|
|
366
380
|
```
|
|
367
381
|
|
|
368
382
|
**What gets audited:**
|
|
383
|
+
|
|
369
384
|
- All HTTP requests to the controller
|
|
370
385
|
- Request/response metadata (method, URL, status, duration, size)
|
|
371
386
|
- User context (extracted from JWT tokens)
|
|
372
387
|
- Sensitive data is automatically masked (passwords, tokens, PII, credit cards, etc.)
|
|
373
388
|
|
|
374
389
|
**ISO 27001 Compliance:**
|
|
390
|
+
|
|
375
391
|
- Automatic sensitive data masking before logging
|
|
376
392
|
- Configurable sensitive field patterns
|
|
377
393
|
- Audit trail for all API communications
|
|
@@ -483,7 +499,211 @@ const response = createPaginatedListResponse(
|
|
|
483
499
|
|
|
484
500
|
---
|
|
485
501
|
|
|
486
|
-
### Step 9:
|
|
502
|
+
### Step 9: Express.js Utilities
|
|
503
|
+
|
|
504
|
+
**What happens:** Use Express-specific utilities for building REST APIs with standardized responses, error handling, and validation.
|
|
505
|
+
|
|
506
|
+
#### Installation
|
|
507
|
+
|
|
508
|
+
For Express.js applications, the SDK includes optional Express utilities:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
npm install @aifabrix/miso-client express
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### Quick Start
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
import express from 'express';
|
|
518
|
+
import {
|
|
519
|
+
injectResponseHelpers,
|
|
520
|
+
asyncHandler,
|
|
521
|
+
ValidationHelper,
|
|
522
|
+
setErrorLogger,
|
|
523
|
+
EncryptionUtil
|
|
524
|
+
} from '@aifabrix/miso-client';
|
|
525
|
+
|
|
526
|
+
const app = express();
|
|
527
|
+
|
|
528
|
+
// Inject response helpers
|
|
529
|
+
app.use(injectResponseHelpers);
|
|
530
|
+
|
|
531
|
+
// Configure error logger (optional)
|
|
532
|
+
setErrorLogger({
|
|
533
|
+
async logError(message, options) {
|
|
534
|
+
console.error(message, options);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Use asyncHandler for automatic error handling
|
|
539
|
+
app.get('/users/:id', asyncHandler(async (req, res) => {
|
|
540
|
+
const user = await ValidationHelper.findOrFail(
|
|
541
|
+
() => db.user.findById(req.params.id),
|
|
542
|
+
'User',
|
|
543
|
+
req.params.id
|
|
544
|
+
);
|
|
545
|
+
res.success(user, 'User retrieved');
|
|
546
|
+
}));
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
#### Response Helpers
|
|
550
|
+
|
|
551
|
+
Standardized API response formatting:
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
import { ResponseHelper } from '@aifabrix/miso-client';
|
|
555
|
+
|
|
556
|
+
// Success response (200)
|
|
557
|
+
return ResponseHelper.success(res, data, 'Success message');
|
|
558
|
+
|
|
559
|
+
// Created response (201)
|
|
560
|
+
return ResponseHelper.created(res, newResource, 'Resource created');
|
|
561
|
+
|
|
562
|
+
// Paginated response
|
|
563
|
+
return ResponseHelper.paginated(res, items, {
|
|
564
|
+
currentPage: 1,
|
|
565
|
+
pageSize: 20,
|
|
566
|
+
totalItems: 100,
|
|
567
|
+
type: 'user'
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// No content (204)
|
|
571
|
+
return ResponseHelper.noContent(res);
|
|
572
|
+
|
|
573
|
+
// Accepted (202)
|
|
574
|
+
return ResponseHelper.accepted(res, { jobId: '123' }, 'Job queued');
|
|
575
|
+
|
|
576
|
+
// Or use injected methods on res object
|
|
577
|
+
res.success(user);
|
|
578
|
+
res.created(newPost);
|
|
579
|
+
res.paginated(users, meta);
|
|
580
|
+
res.noContent();
|
|
581
|
+
res.accepted(data);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
#### Async Handler
|
|
585
|
+
|
|
586
|
+
Eliminates try-catch blocks in route handlers:
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
import { asyncHandler } from '@aifabrix/miso-client';
|
|
590
|
+
|
|
591
|
+
// Automatic error handling
|
|
592
|
+
router.post('/users', asyncHandler(async (req, res) => {
|
|
593
|
+
const user = await userService.create(req.body);
|
|
594
|
+
res.created(user, 'User created');
|
|
595
|
+
}));
|
|
596
|
+
|
|
597
|
+
// Named variant for better error messages
|
|
598
|
+
router.get('/users/:id', asyncHandlerNamed('getUser', async (req, res) => {
|
|
599
|
+
const user = await userService.findById(req.params.id);
|
|
600
|
+
res.success(user);
|
|
601
|
+
}));
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
#### Validation Helper
|
|
605
|
+
|
|
606
|
+
Common validation patterns:
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import { ValidationHelper } from '@aifabrix/miso-client';
|
|
610
|
+
|
|
611
|
+
// Find or throw 404
|
|
612
|
+
const user = await ValidationHelper.findOrFail(
|
|
613
|
+
() => prisma.user.findUnique({ where: { id } }),
|
|
614
|
+
'User',
|
|
615
|
+
id
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
// Ensure doesn't exist or throw 409
|
|
619
|
+
await ValidationHelper.ensureNotExists(
|
|
620
|
+
() => prisma.user.findUnique({ where: { email } }),
|
|
621
|
+
'User',
|
|
622
|
+
email
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
// Check ownership or admin role
|
|
626
|
+
ValidationHelper.ensureOwnershipOrAdmin(req, resourceUserId);
|
|
627
|
+
|
|
628
|
+
// Validate required fields
|
|
629
|
+
ValidationHelper.validateRequiredFields(data, ['name', 'email'], 'User');
|
|
630
|
+
|
|
631
|
+
// Validate string length
|
|
632
|
+
ValidationHelper.validateStringLength(password, 'password', 8, 128);
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
#### Error Handling
|
|
636
|
+
|
|
637
|
+
RFC 7807 compliant error responses with optional custom logger:
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
import { setErrorLogger } from '@aifabrix/miso-client';
|
|
641
|
+
|
|
642
|
+
// Configure during app initialization
|
|
643
|
+
setErrorLogger({
|
|
644
|
+
async logError(message, options) {
|
|
645
|
+
await yourLogger.error(message, options);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
// Errors are automatically handled by asyncHandler
|
|
650
|
+
// AppError is automatically converted to RFC 7807 format
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
#### Encryption
|
|
654
|
+
|
|
655
|
+
AES-256-GCM encryption for sensitive data:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
import { EncryptionUtil } from '@aifabrix/miso-client';
|
|
659
|
+
|
|
660
|
+
// Initialize once at startup (uses ENCRYPTION_KEY env var)
|
|
661
|
+
EncryptionUtil.initialize();
|
|
662
|
+
|
|
663
|
+
// Encrypt sensitive data
|
|
664
|
+
const encrypted = EncryptionUtil.encrypt('sensitive-data');
|
|
665
|
+
|
|
666
|
+
// Decrypt
|
|
667
|
+
const decrypted = EncryptionUtil.decrypt(encrypted);
|
|
668
|
+
|
|
669
|
+
// Generate new key (for setup)
|
|
670
|
+
const key = EncryptionUtil.generateKey();
|
|
671
|
+
console.log('ENCRYPTION_KEY=' + key);
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
#### Sort Utilities
|
|
675
|
+
|
|
676
|
+
Parse and apply sorting for API queries:
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
import { parseSortParams, applySorting } from '@aifabrix/miso-client';
|
|
680
|
+
|
|
681
|
+
// Parse sort query parameters
|
|
682
|
+
const sortOptions = parseSortParams({ sort: ['-createdAt', 'name'] });
|
|
683
|
+
// Returns: [{ field: 'createdAt', order: 'desc' }, { field: 'name', order: 'asc' }]
|
|
684
|
+
|
|
685
|
+
// Apply sorting to in-memory data (client-side)
|
|
686
|
+
const sortedData = applySorting(users, sortOptions);
|
|
687
|
+
|
|
688
|
+
// Or parse from Express request query
|
|
689
|
+
app.get('/users', (req, res) => {
|
|
690
|
+
const sortOptions = parseSortParams(req.query);
|
|
691
|
+
// Use sortOptions to build database query with Prisma/SQL
|
|
692
|
+
const users = await prisma.user.findMany({
|
|
693
|
+
orderBy: sortOptions.map(s => ({ [s.field]: s.order }))
|
|
694
|
+
});
|
|
695
|
+
res.success(users);
|
|
696
|
+
});
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**Note:** For large datasets, always sort at the database level. Use `applySorting()` only for small in-memory datasets or client-side sorting.
|
|
700
|
+
|
|
701
|
+
→ [Complete Express examples](examples/)
|
|
702
|
+
→ [API Reference](docs/api-reference.md#express-utilities)
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
### Step 10: Multi-Authentication Strategy
|
|
487
707
|
|
|
488
708
|
**What happens:** Configure flexible authentication methods with priority-based fallback for advanced authentication scenarios.
|
|
489
709
|
|
|
@@ -516,6 +736,7 @@ const defaultStrategy = client.getDefaultAuthStrategy(token);
|
|
|
516
736
|
```
|
|
517
737
|
|
|
518
738
|
**Supported Authentication Methods:**
|
|
739
|
+
|
|
519
740
|
- `bearer` - Bearer token authentication (Authorization: Bearer <token>)
|
|
520
741
|
- `client-token` - Client token authentication (x-client-token header)
|
|
521
742
|
- `client-credentials` - Client credentials authentication (X-Client-Id and X-Client-Secret headers)
|
|
@@ -524,6 +745,7 @@ const defaultStrategy = client.getDefaultAuthStrategy(token);
|
|
|
524
745
|
**Priority-Based Fallback:** Methods are tried in the order specified in the strategy array until one succeeds.
|
|
525
746
|
|
|
526
747
|
**Environment Variable Configuration:**
|
|
748
|
+
|
|
527
749
|
```bash
|
|
528
750
|
MISO_AUTH_STRATEGY=bearer,client-token,api-key
|
|
529
751
|
MISO_BEARER_TOKEN=optional-bearer-token
|
|
@@ -599,16 +821,19 @@ The SDK consists of five core services:
|
|
|
599
821
|
**First time setup?** Use the AI Fabrix Builder:
|
|
600
822
|
|
|
601
823
|
1. **Create your app:**
|
|
824
|
+
|
|
602
825
|
```bash
|
|
603
826
|
aifabrix create myapp --port 3000 --database --language typescript
|
|
604
827
|
```
|
|
605
828
|
|
|
606
829
|
2. **Login to controller:**
|
|
830
|
+
|
|
607
831
|
```bash
|
|
608
832
|
aifabrix login
|
|
609
833
|
```
|
|
610
834
|
|
|
611
835
|
3. **Register your application:**
|
|
836
|
+
|
|
612
837
|
```bash
|
|
613
838
|
aifabrix app register myapp --environment dev
|
|
614
839
|
```
|
|
@@ -622,6 +847,7 @@ The SDK consists of five core services:
|
|
|
622
847
|
## 💡 Next Steps
|
|
623
848
|
|
|
624
849
|
### Learn More
|
|
850
|
+
|
|
625
851
|
- [Express.js Middleware](docs/examples.md#expressjs-middleware) - Protect API routes
|
|
626
852
|
- [React Authentication](docs/examples.md#react-authentication) - Frontend auth
|
|
627
853
|
- [NestJS Guards](docs/examples.md#nestjs-guards) - Decorator-based auth
|
|
@@ -630,6 +856,7 @@ The SDK consists of five core services:
|
|
|
630
856
|
### Common Tasks
|
|
631
857
|
|
|
632
858
|
**Add authentication middleware:**
|
|
859
|
+
|
|
633
860
|
```typescript
|
|
634
861
|
app.use(async (req, res, next) => {
|
|
635
862
|
const token = client.getToken(req);
|
|
@@ -644,6 +871,7 @@ app.use(async (req, res, next) => {
|
|
|
644
871
|
```
|
|
645
872
|
|
|
646
873
|
**Protect routes by role:**
|
|
874
|
+
|
|
647
875
|
```typescript
|
|
648
876
|
app.get('/admin', async (req, res) => {
|
|
649
877
|
const token = client.getToken(req);
|
|
@@ -658,6 +886,7 @@ app.get('/admin', async (req, res) => {
|
|
|
658
886
|
```
|
|
659
887
|
|
|
660
888
|
**Use environment variables:**
|
|
889
|
+
|
|
661
890
|
```bash
|
|
662
891
|
MISO_CLIENTID=ctrl-dev-my-app
|
|
663
892
|
MISO_CLIENTSECRET=your-secret
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async Handler Utility
|
|
3
|
+
* Wraps async route handlers to automatically catch and handle errors
|
|
4
|
+
*
|
|
5
|
+
* This eliminates the need for try-catch blocks in every route handler
|
|
6
|
+
* and provides consistent error handling across the application.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* router.get('/users/:id',
|
|
11
|
+
* asyncHandler(async (req, res) => {
|
|
12
|
+
* const user = await userService.findById(req.params.id);
|
|
13
|
+
* res.success(user);
|
|
14
|
+
* })
|
|
15
|
+
* );
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { Request, Response, NextFunction, RequestHandler } from "express";
|
|
19
|
+
/**
|
|
20
|
+
* Wraps an async route handler to catch errors automatically
|
|
21
|
+
*
|
|
22
|
+
* @param fn - Async route handler function
|
|
23
|
+
* @param operationName - Optional operation name for error logging
|
|
24
|
+
* @returns Express RequestHandler that catches errors
|
|
25
|
+
*/
|
|
26
|
+
export declare function asyncHandler(fn: (req: Request, res: Response, next: NextFunction) => Promise<void>, operationName?: string): RequestHandler;
|
|
27
|
+
/**
|
|
28
|
+
* Alternative syntax for named operations
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* router.get('/users/:id',
|
|
33
|
+
* asyncHandlerNamed('getUser', async (req, res) => {
|
|
34
|
+
* const user = await userService.findById(req.params.id);
|
|
35
|
+
* res.success(user);
|
|
36
|
+
* })
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function asyncHandlerNamed(operationName: string, fn: (req: Request, res: Response, next: NextFunction) => Promise<void>): RequestHandler;
|
|
41
|
+
//# sourceMappingURL=async-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-handler.d.ts","sourceRoot":"","sources":["../../src/express/async-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG1E;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,EACtE,aAAa,CAAC,EAAE,MAAM,GACrB,cAAc,CAehB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GACrE,cAAc,CAEhB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Async Handler Utility
|
|
4
|
+
* Wraps async route handlers to automatically catch and handle errors
|
|
5
|
+
*
|
|
6
|
+
* This eliminates the need for try-catch blocks in every route handler
|
|
7
|
+
* and provides consistent error handling across the application.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* router.get('/users/:id',
|
|
12
|
+
* asyncHandler(async (req, res) => {
|
|
13
|
+
* const user = await userService.findById(req.params.id);
|
|
14
|
+
* res.success(user);
|
|
15
|
+
* })
|
|
16
|
+
* );
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.asyncHandler = asyncHandler;
|
|
21
|
+
exports.asyncHandlerNamed = asyncHandlerNamed;
|
|
22
|
+
const error_handler_1 = require("./error-handler");
|
|
23
|
+
/**
|
|
24
|
+
* Wraps an async route handler to catch errors automatically
|
|
25
|
+
*
|
|
26
|
+
* @param fn - Async route handler function
|
|
27
|
+
* @param operationName - Optional operation name for error logging
|
|
28
|
+
* @returns Express RequestHandler that catches errors
|
|
29
|
+
*/
|
|
30
|
+
function asyncHandler(fn, operationName) {
|
|
31
|
+
return async (req, res, next) => {
|
|
32
|
+
try {
|
|
33
|
+
await fn(req, res, next);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// Extract operation name from route if not provided
|
|
37
|
+
const operation = operationName || `${req.method} ${req.route?.path || req.path}`;
|
|
38
|
+
await (0, error_handler_1.handleRouteError)(error, req, res, operation);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Alternative syntax for named operations
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* router.get('/users/:id',
|
|
48
|
+
* asyncHandlerNamed('getUser', async (req, res) => {
|
|
49
|
+
* const user = await userService.findById(req.params.id);
|
|
50
|
+
* res.success(user);
|
|
51
|
+
* })
|
|
52
|
+
* );
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
function asyncHandlerNamed(operationName, fn) {
|
|
56
|
+
return asyncHandler(fn, operationName);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=async-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-handler.js","sourceRoot":"","sources":["../../src/express/async-handler.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAYH,oCAkBC;AAeD,8CAKC;AA/CD,mDAAmD;AAEnD;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,EAAsE,EACtE,aAAsB;IAEtB,OAAO,KAAK,EACV,GAAY,EACZ,GAAa,EACb,IAAkB,EACH,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,oDAAoD;YACpD,MAAM,SAAS,GACb,aAAa,IAAI,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAClE,MAAM,IAAA,gCAAgB,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,iBAAiB,CAC/B,aAAqB,EACrB,EAAsE;IAEtE,OAAO,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption Utility
|
|
3
|
+
* AES-256-GCM encryption for sensitive database fields
|
|
4
|
+
*/
|
|
5
|
+
export declare class EncryptionUtil {
|
|
6
|
+
private static algorithm;
|
|
7
|
+
private static key;
|
|
8
|
+
private static initialized;
|
|
9
|
+
/**
|
|
10
|
+
* Initialize encryption with key from environment
|
|
11
|
+
* Must be called before encrypt/decrypt operations
|
|
12
|
+
*/
|
|
13
|
+
static initialize(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Encrypt a string value
|
|
16
|
+
* Returns: iv:authTag:encryptedData (all in hex)
|
|
17
|
+
*/
|
|
18
|
+
static encrypt(text: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Decrypt an encrypted string
|
|
21
|
+
* Expects format: iv:authTag:encryptedData (all in hex)
|
|
22
|
+
*/
|
|
23
|
+
static decrypt(encryptedText: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Generate a new encryption key (for setup/documentation)
|
|
26
|
+
*/
|
|
27
|
+
static generateKey(): string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/express/encryption.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAiB;IACzC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAC,WAAW,CAAS;IAEnC;;;OAGG;IACH,MAAM,CAAC,UAAU,IAAI,IAAI;IAwBzB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA2BpC;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAuC7C;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,MAAM;CAG7B"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Encryption Utility
|
|
4
|
+
* AES-256-GCM encryption for sensitive database fields
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.EncryptionUtil = void 0;
|
|
11
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
12
|
+
class EncryptionUtil {
|
|
13
|
+
/**
|
|
14
|
+
* Initialize encryption with key from environment
|
|
15
|
+
* Must be called before encrypt/decrypt operations
|
|
16
|
+
*/
|
|
17
|
+
static initialize() {
|
|
18
|
+
if (this.initialized) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const encryptionKey = process.env["ENCRYPTION_KEY"];
|
|
22
|
+
if (!encryptionKey) {
|
|
23
|
+
throw new Error("ENCRYPTION_KEY environment variable not configured");
|
|
24
|
+
}
|
|
25
|
+
// Validate key length (should be 64 hex characters = 32 bytes)
|
|
26
|
+
if (encryptionKey.length !== 64) {
|
|
27
|
+
throw new Error("ENCRYPTION_KEY must be 64 hex characters (32 bytes)");
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
this.key = Buffer.from(encryptionKey, "hex");
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new Error("ENCRYPTION_KEY must be valid hex string");
|
|
34
|
+
}
|
|
35
|
+
this.initialized = true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Encrypt a string value
|
|
39
|
+
* Returns: iv:authTag:encryptedData (all in hex)
|
|
40
|
+
*/
|
|
41
|
+
static encrypt(text) {
|
|
42
|
+
if (!this.initialized) {
|
|
43
|
+
throw new Error("EncryptionUtil not initialized. Call initialize() first.");
|
|
44
|
+
}
|
|
45
|
+
if (!text) {
|
|
46
|
+
throw new Error("Cannot encrypt empty text");
|
|
47
|
+
}
|
|
48
|
+
const iv = crypto_1.default.randomBytes(16);
|
|
49
|
+
const cipher = crypto_1.default.createCipheriv(this.algorithm, this.key, iv);
|
|
50
|
+
let encrypted = cipher.update(text, "utf8", "hex");
|
|
51
|
+
encrypted += cipher.final("hex");
|
|
52
|
+
const authTag = cipher.getAuthTag();
|
|
53
|
+
// Format: iv:authTag:encryptedData
|
|
54
|
+
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Decrypt an encrypted string
|
|
58
|
+
* Expects format: iv:authTag:encryptedData (all in hex)
|
|
59
|
+
*/
|
|
60
|
+
static decrypt(encryptedText) {
|
|
61
|
+
if (!this.initialized) {
|
|
62
|
+
throw new Error("EncryptionUtil not initialized. Call initialize() first.");
|
|
63
|
+
}
|
|
64
|
+
if (!encryptedText) {
|
|
65
|
+
throw new Error("Cannot decrypt empty text");
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const parts = encryptedText.split(":");
|
|
69
|
+
if (parts.length !== 3) {
|
|
70
|
+
throw new Error("Invalid encrypted text format");
|
|
71
|
+
}
|
|
72
|
+
const iv = Buffer.from(parts[0] || "", "hex");
|
|
73
|
+
const authTag = Buffer.from(parts[1] || "", "hex");
|
|
74
|
+
const encrypted = parts[2] || "";
|
|
75
|
+
const decipher = crypto_1.default.createDecipheriv(this.algorithm, this.key, iv);
|
|
76
|
+
decipher.setAuthTag(authTag);
|
|
77
|
+
let decrypted = decipher.update(encrypted, "hex", "utf8");
|
|
78
|
+
decrypted += decipher.final("utf8");
|
|
79
|
+
return decrypted;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
throw new Error(`Decryption failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generate a new encryption key (for setup/documentation)
|
|
87
|
+
*/
|
|
88
|
+
static generateKey() {
|
|
89
|
+
return crypto_1.default.randomBytes(32).toString("hex");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.EncryptionUtil = EncryptionUtil;
|
|
93
|
+
EncryptionUtil.algorithm = "aes-256-gcm";
|
|
94
|
+
EncryptionUtil.initialized = false;
|
|
95
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/express/encryption.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,oDAA4B;AAE5B,MAAa,cAAc;IAKzB;;;OAGG;IACH,MAAM,CAAC,UAAU;QACf,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACpD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QAED,+DAA+D;QAC/D,IAAI,aAAa,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,EAAE,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,gBAAM,CAAC,cAAc,CAClC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,GAAG,EACR,EAAE,CACiB,CAAC;QAEtB,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACnD,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAEjC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QAEpC,mCAAmC;QACnC,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;IACzE,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,aAAqB;QAClC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEjC,MAAM,QAAQ,GAAG,gBAAM,CAAC,gBAAgB,CACtC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,GAAG,EACR,EAAE,CACmB,CAAC;YACxB,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAE7B,IAAI,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC1D,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAEpC,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,OAAO,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;;AAhHH,wCAiHC;AAhHgB,wBAAS,GAAG,aAAa,CAAC;AAE1B,0BAAW,GAAG,KAAK,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Error Handler Utility
|
|
3
|
+
* Provides standardized error handling for all route handlers
|
|
4
|
+
*/
|
|
5
|
+
import { Request, Response } from "express";
|
|
6
|
+
/**
|
|
7
|
+
* Error logger interface for dependency injection
|
|
8
|
+
* Allows applications to provide their own logger implementation
|
|
9
|
+
*/
|
|
10
|
+
export interface ErrorLogger {
|
|
11
|
+
logError(message: string, options: unknown): Promise<void> | void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Set custom error logger for the application
|
|
15
|
+
* @param logger - Custom logger implementing ErrorLogger interface, or null to use stderr
|
|
16
|
+
*/
|
|
17
|
+
export declare function setErrorLogger(logger: ErrorLogger | null): void;
|
|
18
|
+
/**
|
|
19
|
+
* Generic route error handler
|
|
20
|
+
* Logs error and sends RFC 7807 compliant error response
|
|
21
|
+
*/
|
|
22
|
+
export declare function handleRouteError(error: unknown, req: Request, res: Response, operation?: string): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/express/error-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQ5C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnE;AAKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE/D;AAqGD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAsDf"}
|