@aifabrix/miso-client 1.9.2 → 2.1.0

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.
Files changed (131) hide show
  1. package/README.md +231 -2
  2. package/dist/express/async-handler.d.ts +41 -0
  3. package/dist/express/async-handler.d.ts.map +1 -0
  4. package/dist/express/async-handler.js +58 -0
  5. package/dist/express/async-handler.js.map +1 -0
  6. package/dist/express/encryption.d.ts +29 -0
  7. package/dist/express/encryption.d.ts.map +1 -0
  8. package/dist/express/encryption.js +95 -0
  9. package/dist/express/encryption.js.map +1 -0
  10. package/dist/express/error-handler.d.ts +23 -0
  11. package/dist/express/error-handler.d.ts.map +1 -0
  12. package/dist/express/error-handler.js +140 -0
  13. package/dist/express/error-handler.js.map +1 -0
  14. package/dist/express/error-response.d.ts +55 -0
  15. package/dist/express/error-response.d.ts.map +1 -0
  16. package/dist/express/error-response.js +95 -0
  17. package/dist/express/error-response.js.map +1 -0
  18. package/dist/express/error-types.d.ts +46 -0
  19. package/dist/express/error-types.d.ts.map +1 -0
  20. package/dist/express/error-types.js +93 -0
  21. package/dist/express/error-types.js.map +1 -0
  22. package/dist/express/index.d.ts +14 -0
  23. package/dist/express/index.d.ts.map +1 -0
  24. package/dist/express/index.js +39 -0
  25. package/dist/express/index.js.map +1 -0
  26. package/dist/express/response-helper.d.ts +67 -0
  27. package/dist/express/response-helper.d.ts.map +1 -0
  28. package/dist/express/response-helper.js +83 -0
  29. package/dist/express/response-helper.js.map +1 -0
  30. package/dist/express/response-middleware.d.ts +18 -0
  31. package/dist/express/response-middleware.d.ts.map +1 -0
  32. package/dist/express/response-middleware.js +29 -0
  33. package/dist/express/response-middleware.js.map +1 -0
  34. package/dist/express/validation-helper.d.ts +66 -0
  35. package/dist/express/validation-helper.d.ts.map +1 -0
  36. package/dist/express/validation-helper.js +102 -0
  37. package/dist/express/validation-helper.js.map +1 -0
  38. package/dist/index.d.ts +23 -29
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +22 -23
  41. package/dist/index.js.map +1 -1
  42. package/dist/services/auth.service.d.ts +9 -3
  43. package/dist/services/auth.service.d.ts.map +1 -1
  44. package/dist/services/auth.service.js +129 -15
  45. package/dist/services/auth.service.js.map +1 -1
  46. package/dist/services/cache.service.d.ts +1 -1
  47. package/dist/services/cache.service.d.ts.map +1 -1
  48. package/dist/services/cache.service.js +1 -1
  49. package/dist/services/cache.service.js.map +1 -1
  50. package/dist/services/logger.service.d.ts +3 -3
  51. package/dist/services/logger.service.d.ts.map +1 -1
  52. package/dist/services/logger.service.js +32 -25
  53. package/dist/services/logger.service.js.map +1 -1
  54. package/dist/services/permission.service.d.ts +3 -3
  55. package/dist/services/permission.service.d.ts.map +1 -1
  56. package/dist/services/permission.service.js +9 -6
  57. package/dist/services/permission.service.js.map +1 -1
  58. package/dist/services/redis.service.d.ts +1 -1
  59. package/dist/services/redis.service.js +10 -10
  60. package/dist/services/role.service.d.ts +3 -3
  61. package/dist/services/role.service.d.ts.map +1 -1
  62. package/dist/services/role.service.js +8 -5
  63. package/dist/services/role.service.js.map +1 -1
  64. package/dist/types/config.types.d.ts +13 -7
  65. package/dist/types/config.types.d.ts.map +1 -1
  66. package/dist/types/config.types.js +6 -5
  67. package/dist/types/config.types.js.map +1 -1
  68. package/dist/types/filter.types.d.ts +1 -1
  69. package/dist/types/filter.types.d.ts.map +1 -1
  70. package/dist/types/filter.types.js +2 -2
  71. package/dist/types/filter.types.js.map +1 -1
  72. package/dist/types/sort.types.d.ts +1 -1
  73. package/dist/utils/audit-log-queue.d.ts +4 -4
  74. package/dist/utils/audit-log-queue.d.ts.map +1 -1
  75. package/dist/utils/audit-log-queue.js +11 -11
  76. package/dist/utils/audit-log-queue.js.map +1 -1
  77. package/dist/utils/auth-strategy.d.ts +1 -1
  78. package/dist/utils/auth-strategy.d.ts.map +1 -1
  79. package/dist/utils/auth-strategy.js +19 -17
  80. package/dist/utils/auth-strategy.js.map +1 -1
  81. package/dist/utils/config-loader.d.ts +2 -2
  82. package/dist/utils/config-loader.d.ts.map +1 -1
  83. package/dist/utils/config-loader.js +11 -10
  84. package/dist/utils/config-loader.js.map +1 -1
  85. package/dist/utils/data-masker.d.ts.map +1 -1
  86. package/dist/utils/data-masker.js +7 -7
  87. package/dist/utils/data-masker.js.map +1 -1
  88. package/dist/utils/errors.d.ts +2 -2
  89. package/dist/utils/errors.d.ts.map +1 -1
  90. package/dist/utils/errors.js +37 -30
  91. package/dist/utils/errors.js.map +1 -1
  92. package/dist/utils/filter.utils.d.ts +2 -2
  93. package/dist/utils/filter.utils.d.ts.map +1 -1
  94. package/dist/utils/filter.utils.js +24 -18
  95. package/dist/utils/filter.utils.js.map +1 -1
  96. package/dist/utils/http-client-audit.d.ts +4 -4
  97. package/dist/utils/http-client-audit.d.ts.map +1 -1
  98. package/dist/utils/http-client-audit.js +30 -22
  99. package/dist/utils/http-client-audit.js.map +1 -1
  100. package/dist/utils/http-client-masking.d.ts +1 -1
  101. package/dist/utils/http-client-masking.d.ts.map +1 -1
  102. package/dist/utils/http-client-masking.js +31 -21
  103. package/dist/utils/http-client-masking.js.map +1 -1
  104. package/dist/utils/http-client-metadata.d.ts +2 -2
  105. package/dist/utils/http-client-metadata.d.ts.map +1 -1
  106. package/dist/utils/http-client-metadata.js +7 -7
  107. package/dist/utils/http-client-metadata.js.map +1 -1
  108. package/dist/utils/http-client.d.ts +6 -6
  109. package/dist/utils/http-client.d.ts.map +1 -1
  110. package/dist/utils/http-client.js +8 -9
  111. package/dist/utils/http-client.js.map +1 -1
  112. package/dist/utils/internal-http-client.d.ts +9 -5
  113. package/dist/utils/internal-http-client.d.ts.map +1 -1
  114. package/dist/utils/internal-http-client.js +98 -45
  115. package/dist/utils/internal-http-client.js.map +1 -1
  116. package/dist/utils/pagination.utils.d.ts +1 -1
  117. package/dist/utils/pagination.utils.d.ts.map +1 -1
  118. package/dist/utils/pagination.utils.js +3 -3
  119. package/dist/utils/pagination.utils.js.map +1 -1
  120. package/dist/utils/sensitive-fields.loader.d.ts.map +1 -1
  121. package/dist/utils/sensitive-fields.loader.js +77 -60
  122. package/dist/utils/sensitive-fields.loader.js.map +1 -1
  123. package/dist/utils/sort.utils.d.ts +14 -3
  124. package/dist/utils/sort.utils.d.ts.map +1 -1
  125. package/dist/utils/sort.utils.js +73 -9
  126. package/dist/utils/sort.utils.js.map +1 -1
  127. package/package.json +14 -2
  128. package/dist/services/encryption.service.d.ts +0 -32
  129. package/dist/services/encryption.service.d.ts.map +0 -1
  130. package/dist/services/encryption.service.js +0 -135
  131. 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
- ## 📚 Documentation
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: Multi-Authentication Strategy
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":"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"}
@@ -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"}