@alacard-project/shared 1.0.10 → 1.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 (134) hide show
  1. package/README.md +24 -0
  2. package/dist/constants/auth-config.constants.d.ts +7 -0
  3. package/dist/constants/auth-config.constants.js +8 -1
  4. package/dist/constants/auth-config.constants.js.map +1 -1
  5. package/dist/constants/auth.constants.d.ts +25 -0
  6. package/dist/constants/auth.constants.js +15 -1
  7. package/dist/constants/auth.constants.js.map +1 -1
  8. package/dist/constants/index.d.ts +1 -0
  9. package/dist/constants/index.js +1 -0
  10. package/dist/constants/index.js.map +1 -1
  11. package/dist/constants/queue.constants.d.ts +8 -0
  12. package/dist/constants/queue.constants.js +12 -0
  13. package/dist/constants/queue.constants.js.map +1 -0
  14. package/dist/contracts/auth.contract.d.ts +12 -9
  15. package/dist/dto/account.dto.d.ts +10 -0
  16. package/dist/dto/account.dto.js +49 -0
  17. package/dist/dto/account.dto.js.map +1 -0
  18. package/dist/dto/auth.dto.d.ts +43 -0
  19. package/dist/dto/auth.dto.js +136 -1
  20. package/dist/dto/auth.dto.js.map +1 -1
  21. package/dist/dto/card.dto.js.map +1 -1
  22. package/dist/dto/client.dto.js.map +1 -1
  23. package/dist/dto/index.d.ts +2 -0
  24. package/dist/dto/index.js +2 -0
  25. package/dist/dto/index.js.map +1 -1
  26. package/dist/dto/logging.dto.js.map +1 -1
  27. package/dist/dto/partner.dto.d.ts +1 -1
  28. package/dist/dto/partner.dto.js +7 -9
  29. package/dist/dto/partner.dto.js.map +1 -1
  30. package/dist/dto/transaction.dto.d.ts +2 -1
  31. package/dist/dto/transaction.dto.js.map +1 -1
  32. package/dist/dto/user.dto.d.ts +11 -0
  33. package/dist/dto/user.dto.js +45 -0
  34. package/dist/dto/user.dto.js.map +1 -0
  35. package/dist/enums/auth.enum.d.ts +12 -0
  36. package/dist/enums/auth.enum.js +18 -0
  37. package/dist/enums/auth.enum.js.map +1 -0
  38. package/dist/enums/iam.enum.d.ts +14 -0
  39. package/dist/enums/iam.enum.js +21 -0
  40. package/dist/enums/iam.enum.js.map +1 -0
  41. package/dist/enums/index.d.ts +2 -0
  42. package/dist/enums/index.js +2 -0
  43. package/dist/enums/index.js.map +1 -1
  44. package/dist/errors/app.error.d.ts +1 -1
  45. package/dist/filters/http-exception.filter.d.ts +5 -0
  46. package/dist/filters/http-exception.filter.js +48 -0
  47. package/dist/filters/http-exception.filter.js.map +1 -0
  48. package/dist/filters/index.d.ts +1 -0
  49. package/dist/filters/index.js +18 -0
  50. package/dist/filters/index.js.map +1 -0
  51. package/dist/index.d.ts +5 -0
  52. package/dist/index.js +5 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/interceptors/index.d.ts +2 -0
  55. package/dist/interceptors/index.js +19 -0
  56. package/dist/interceptors/index.js.map +1 -0
  57. package/dist/interceptors/logging.interceptor.d.ts +6 -0
  58. package/dist/interceptors/logging.interceptor.js +41 -0
  59. package/dist/interceptors/logging.interceptor.js.map +1 -0
  60. package/dist/interceptors/transform.interceptor.d.ts +9 -0
  61. package/dist/interceptors/transform.interceptor.js +24 -0
  62. package/dist/interceptors/transform.interceptor.js.map +1 -0
  63. package/dist/observability/index.d.ts +2 -0
  64. package/dist/observability/index.js +19 -0
  65. package/dist/observability/index.js.map +1 -0
  66. package/dist/observability/metrics/metrics.module.d.ts +2 -0
  67. package/dist/observability/metrics/metrics.module.js +28 -0
  68. package/dist/observability/metrics/metrics.module.js.map +1 -0
  69. package/dist/observability/tracing.d.ts +1 -0
  70. package/dist/observability/tracing.js +28 -0
  71. package/dist/observability/tracing.js.map +1 -0
  72. package/dist/resilience/circuit-breaker.service.d.ts +7 -0
  73. package/dist/resilience/circuit-breaker.service.js +45 -0
  74. package/dist/resilience/circuit-breaker.service.js.map +1 -0
  75. package/dist/resilience/resilience.module.d.ts +2 -0
  76. package/dist/resilience/resilience.module.js +22 -0
  77. package/dist/resilience/resilience.module.js.map +1 -0
  78. package/dist/types/auth.types.d.ts +22 -4
  79. package/dist/types/common.types.d.ts +11 -0
  80. package/dist/types/common.types.js +3 -0
  81. package/dist/types/common.types.js.map +1 -0
  82. package/dist/types/iam.types.d.ts +46 -0
  83. package/dist/types/iam.types.js +3 -0
  84. package/dist/types/iam.types.js.map +1 -0
  85. package/dist/types/index.d.ts +2 -0
  86. package/dist/types/index.js +2 -0
  87. package/dist/types/index.js.map +1 -1
  88. package/dist/types/monitoring.types.d.ts +2 -1
  89. package/dist/types/user.types.d.ts +7 -3
  90. package/dist/utils/app.utils.d.ts +1 -0
  91. package/dist/utils/app.utils.js +7 -1
  92. package/dist/utils/app.utils.js.map +1 -1
  93. package/dist/utils/health.utils.d.ts +6 -2
  94. package/dist/utils/health.utils.js +2 -1
  95. package/dist/utils/health.utils.js.map +1 -1
  96. package/package.json +28 -15
  97. package/proto/dbf.proto +1 -1
  98. package/src/constants/auth-config.constants.ts +7 -0
  99. package/src/constants/auth.constants.ts +16 -0
  100. package/src/constants/index.ts +1 -0
  101. package/src/constants/queue.constants.ts +8 -0
  102. package/src/contracts/auth.contract.ts +10 -9
  103. package/src/dto/account.dto.ts +28 -0
  104. package/src/dto/auth.dto.ts +126 -0
  105. package/src/dto/card.dto.ts +1 -1
  106. package/src/dto/client.dto.ts +7 -7
  107. package/src/dto/index.ts +2 -0
  108. package/src/dto/logging.dto.ts +3 -3
  109. package/src/dto/partner.dto.ts +3 -6
  110. package/src/dto/transaction.dto.ts +4 -3
  111. package/src/dto/user.dto.ts +28 -0
  112. package/src/enums/auth.enum.ts +13 -0
  113. package/src/enums/iam.enum.ts +28 -0
  114. package/src/enums/index.ts +2 -0
  115. package/src/filters/http-exception.filter.ts +49 -0
  116. package/src/filters/index.ts +2 -0
  117. package/src/index.ts +5 -0
  118. package/src/interceptors/index.ts +3 -0
  119. package/src/interceptors/logging.interceptor.ts +37 -0
  120. package/src/interceptors/transform.interceptor.ts +21 -0
  121. package/src/observability/index.ts +3 -0
  122. package/src/observability/metrics/metrics.module.ts +16 -0
  123. package/src/observability/tracing.ts +33 -0
  124. package/src/resilience/circuit-breaker.service.ts +46 -0
  125. package/src/resilience/resilience.module.ts +9 -0
  126. package/src/types/auth.types.ts +23 -4
  127. package/src/types/common.types.ts +18 -0
  128. package/src/types/iam.types.ts +78 -0
  129. package/src/types/index.ts +2 -0
  130. package/src/types/monitoring.types.ts +2 -4
  131. package/src/types/user.types.ts +3 -3
  132. package/src/utils/app.utils.ts +9 -0
  133. package/src/utils/health.utils.ts +11 -4
  134. package/tsconfig.json +5 -1
@@ -1,5 +1,6 @@
1
1
  import { IsEmail, IsString, MinLength, IsEnum, IsOptional } from 'class-validator';
2
2
  import { UserRole } from '../enums/user.enum';
3
+ import { ServiceTokenType, IdentifierType } from '../enums';
3
4
 
4
5
  export class RegisterDto {
5
6
  @IsEmail()
@@ -34,6 +35,32 @@ export class LoginDto {
34
35
  password!: string;
35
36
  }
36
37
 
38
+ /**
39
+ * Employee Login DTO
40
+ * Used for employee authentication via email
41
+ */
42
+ export class EmployeeLoginDto {
43
+ @IsEmail()
44
+ email!: string;
45
+
46
+ @IsString()
47
+ @MinLength(8)
48
+ password!: string;
49
+ }
50
+
51
+ /**
52
+ * Public Login DTO
53
+ * Used for client and partner authentication via username
54
+ */
55
+ export class PublicLoginDto {
56
+ @IsString()
57
+ username!: string;
58
+
59
+ @IsString()
60
+ @MinLength(8)
61
+ password!: string;
62
+ }
63
+
37
64
  export interface UserResponse {
38
65
  id: string;
39
66
  email: string;
@@ -105,3 +132,102 @@ export class ResetPasswordConfirmBody {
105
132
  @MinLength(8)
106
133
  newPassword!: string;
107
134
  }
135
+
136
+ /**
137
+ * Logout DTO
138
+ */
139
+ export class LogoutDto {
140
+ @IsString()
141
+ @IsOptional()
142
+ refreshToken?: string;
143
+
144
+ @IsString()
145
+ @IsOptional()
146
+ sessionId?: string;
147
+ }
148
+
149
+ export class RefreshTokenDto {
150
+ @IsString()
151
+ refreshToken!: string;
152
+ }
153
+
154
+ /**
155
+ * Service Token DTOs
156
+ */
157
+ export class CreateServiceTokenDto {
158
+ @IsString()
159
+ serviceName!: string;
160
+
161
+ @IsEnum(ServiceTokenType)
162
+ type!: ServiceTokenType;
163
+
164
+ @IsOptional()
165
+ @IsString()
166
+ description?: string;
167
+
168
+ @IsOptional()
169
+ @IsString()
170
+ name?: string;
171
+
172
+ @IsString()
173
+ identityId!: string;
174
+
175
+ @IsOptional()
176
+ @IsString()
177
+ expiresInDays?: number;
178
+ }
179
+
180
+ export class ValidateServiceTokenDto {
181
+ @IsString()
182
+ token!: string;
183
+ }
184
+
185
+ /**
186
+ * Credential DTOs
187
+ */
188
+ export class CreateCredentialDto {
189
+ @IsEnum(IdentifierType)
190
+ identifierType!: IdentifierType;
191
+
192
+ @IsString()
193
+ identifierValue!: string;
194
+
195
+ @IsString()
196
+ password!: string;
197
+
198
+ @IsString()
199
+ identityId!: string;
200
+ }
201
+
202
+ /**
203
+ * Session DTOs
204
+ */
205
+ export class CreateSessionDto {
206
+ @IsString()
207
+ identityId!: string;
208
+
209
+ @IsOptional()
210
+ @IsString()
211
+ ipAddress?: string;
212
+
213
+ @IsOptional()
214
+ @IsString()
215
+ userAgent?: string;
216
+
217
+ @IsOptional()
218
+ @IsString()
219
+ deviceInfo?: string;
220
+ }
221
+
222
+ /**
223
+ * 2FA Verification DTO
224
+ */
225
+ export class Verify2faDto {
226
+ @IsString()
227
+ challengeId!: string;
228
+
229
+ @IsString()
230
+ @MinLength(6)
231
+ code!: string;
232
+ }
233
+
@@ -3,7 +3,7 @@ import { Type } from 'class-transformer';
3
3
 
4
4
  export class CreateCardDto {
5
5
  @IsString()
6
- cardNumber: string;
6
+ cardNumber!: string;
7
7
 
8
8
  @IsOptional()
9
9
  @IsString()
@@ -4,10 +4,10 @@ import { RegisterDto } from './auth.dto';
4
4
 
5
5
  export class CreateClientContactDto {
6
6
  @IsString()
7
- contactType: string;
7
+ contactType!: string;
8
8
 
9
9
  @IsString()
10
- value: string;
10
+ value!: string;
11
11
 
12
12
  @IsOptional()
13
13
  @IsBoolean()
@@ -16,10 +16,10 @@ export class CreateClientContactDto {
16
16
 
17
17
  export class CreateClientDetailDto {
18
18
  @IsString()
19
- detailType: string;
19
+ detailType!: string;
20
20
 
21
21
  @IsString()
22
- value: string;
22
+ value!: string;
23
23
 
24
24
  @IsOptional()
25
25
  @IsBoolean()
@@ -28,21 +28,21 @@ export class CreateClientDetailDto {
28
28
 
29
29
  export class CreateClientDto {
30
30
  @IsString()
31
- clientNumber: string;
31
+ clientNumber!: string;
32
32
 
33
33
  @IsOptional()
34
34
  @IsString()
35
35
  clientNumberFormatted?: string;
36
36
 
37
37
  @IsString()
38
- clientType: string;
38
+ clientType!: string;
39
39
 
40
40
  @IsOptional()
41
41
  @IsString()
42
42
  shortName?: string;
43
43
 
44
44
  @IsString()
45
- fullName: string;
45
+ fullName!: string;
46
46
 
47
47
  @IsOptional()
48
48
  @IsBoolean()
package/src/dto/index.ts CHANGED
@@ -4,3 +4,5 @@ export * from './client.dto';
4
4
  export * from './transaction.dto';
5
5
  export * from './card.dto';
6
6
  export * from './partner.dto';
7
+ export * from './user.dto';
8
+ export * from './account.dto';
@@ -43,10 +43,10 @@ export class LogFilterDto {
43
43
 
44
44
  export class LogCleanupDto {
45
45
  @IsDateString()
46
- startDate: string;
46
+ startDate!: string;
47
47
 
48
48
  @IsDateString()
49
- endDate: string;
49
+ endDate!: string;
50
50
 
51
51
  @IsOptional()
52
52
  @IsString()
@@ -62,7 +62,7 @@ export class RetentionPeriodDto {
62
62
  @IsInt()
63
63
  @Min(1)
64
64
  @Max(365)
65
- retentionDays: number;
65
+ retentionDays!: number;
66
66
  }
67
67
 
68
68
  export class UserActionFilterDto {
@@ -2,19 +2,16 @@ import { IsString, IsOptional, IsBoolean, ValidateNested, IsObject } from 'class
2
2
  import { Type } from 'class-transformer';
3
3
  import { RegisterDto } from './auth.dto';
4
4
 
5
- export class CreatePartnerDto {
5
+ export class PartnerDto {
6
6
  @IsString()
7
- name: string;
7
+ name!: string;
8
8
 
9
9
  @IsString()
10
- type: string;
10
+ type!: string;
11
11
 
12
12
  @IsOptional()
13
13
  @IsBoolean()
14
14
  isActive?: boolean;
15
-
16
- @IsOptional()
17
- @ValidateNested()
18
15
  @IsObject()
19
16
  @Type(() => RegisterDto)
20
17
  adminUser?: RegisterDto;
@@ -1,5 +1,6 @@
1
1
  import { IsString, IsOptional, IsNumber, Min, IsUUID } from 'class-validator';
2
2
  import { Type } from 'class-transformer';
3
+ import type { JsonValue } from '../types/common.types';
3
4
 
4
5
  export class CreateTransactionDto {
5
6
  @IsOptional()
@@ -7,11 +8,11 @@ export class CreateTransactionDto {
7
8
  externalId?: string;
8
9
 
9
10
  @IsString()
10
- cardId: string;
11
+ cardId!: string;
11
12
 
12
13
  @IsNumber()
13
14
  @Min(0)
14
- amount: number;
15
+ amount!: number;
15
16
 
16
17
  @IsOptional()
17
18
  @IsString()
@@ -47,5 +48,5 @@ export class UpdateTransactionDto {
47
48
  status?: string;
48
49
 
49
50
  @IsOptional()
50
- metadata?: any;
51
+ metadata?: JsonValue;
51
52
  }
@@ -0,0 +1,28 @@
1
+ import { IsEmail, IsEnum, IsOptional, IsString, IsUUID } from 'class-validator';
2
+ import { UserRole } from '../enums';
3
+
4
+ export class UserDto {
5
+ @IsUUID()
6
+ id!: string;
7
+
8
+ @IsEmail()
9
+ email!: string;
10
+
11
+ @IsString()
12
+ @IsOptional()
13
+ firstName?: string;
14
+
15
+ @IsString()
16
+ @IsOptional()
17
+ lastName?: string;
18
+
19
+ @IsEnum(UserRole)
20
+ role!: UserRole;
21
+
22
+ @IsString()
23
+ @IsOptional()
24
+ phoneNumber?: string;
25
+
26
+ createdAt!: Date;
27
+ updatedAt!: Date;
28
+ }
@@ -0,0 +1,13 @@
1
+ export enum CredentialStatus {
2
+ ACTIVE = 'ACTIVE',
3
+ INACTIVE = 'INACTIVE',
4
+ LOCKED = 'LOCKED',
5
+ SUSPENDED = 'SUSPENDED',
6
+ DELETED = 'DELETED',
7
+ }
8
+
9
+ export enum ServiceTokenType {
10
+ API = 'API',
11
+ INTERNAL = 'INTERNAL',
12
+ WEBHOOK = 'WEBHOOK',
13
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Subject Type Enum
3
+ * Defines the type of subject in the system (immutable after creation)
4
+ */
5
+ export enum SubjectType {
6
+ EMPLOYEE = 'EMPLOYEE',
7
+ CLIENT = 'CLIENT',
8
+ PARTNER = 'PARTNER',
9
+ }
10
+
11
+ /**
12
+ * Identifier Type Enum
13
+ * Defines the type of login identifier used for authentication
14
+ */
15
+ export enum IdentifierType {
16
+ EMAIL = 'EMAIL',
17
+ USERNAME = 'USERNAME',
18
+ }
19
+
20
+ /**
21
+ * Identity Status Enum
22
+ * Defines the status of an identity in the IAM system
23
+ */
24
+ export enum IdentityStatus {
25
+ ACTIVE = 'ACTIVE',
26
+ BLOCKED = 'BLOCKED',
27
+ DELETED = 'DELETED',
28
+ }
@@ -1,8 +1,10 @@
1
1
  export * from './env.enum';
2
2
  export * from './user.enum';
3
+ export * from './iam.enum';
3
4
  export * from './health.enum';
4
5
  export * from './logging.enum';
5
6
  export * from './notification.enum';
6
7
  export * from './error.enum';
8
+ export * from './auth.enum';
7
9
  export * from './permission.enum';
8
10
  export * from './events.enum';
@@ -0,0 +1,49 @@
1
+
2
+ import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus, Logger } from '@nestjs/common';
3
+ import { Request, Response } from 'express';
4
+
5
+ @Catch()
6
+ export class HttpExceptionFilter implements ExceptionFilter {
7
+ private readonly logger = new Logger(HttpExceptionFilter.name);
8
+
9
+ catch(exception: unknown, host: ArgumentsHost) {
10
+ const ctx = host.switchToHttp();
11
+ const response = ctx.getResponse<Response>();
12
+ const request = ctx.getRequest<Request>();
13
+
14
+ const status =
15
+ exception instanceof HttpException
16
+ ? exception.getStatus()
17
+ : HttpStatus.INTERNAL_SERVER_ERROR;
18
+
19
+ const message =
20
+ exception instanceof HttpException
21
+ ? exception.getResponse()
22
+ : 'Internal server error';
23
+
24
+ // Determine the actual error message string
25
+ const errorMessage = typeof message === 'string'
26
+ ? message
27
+ : (message as any).message || message;
28
+
29
+ // Log the error
30
+ if (status >= 500) {
31
+ this.logger.error(
32
+ `[${request.method}] ${request.url} - ${status} - ${JSON.stringify(errorMessage)}`,
33
+ exception instanceof Error ? exception.stack : '',
34
+ );
35
+ } else {
36
+ this.logger.warn(
37
+ `[${request.method}] ${request.url} - ${status} - ${JSON.stringify(errorMessage)}`,
38
+ );
39
+ }
40
+
41
+ response.status(status).json({
42
+ statusCode: status,
43
+ timestamp: new Date().toISOString(),
44
+ path: request.url,
45
+ method: request.method,
46
+ error: errorMessage,
47
+ });
48
+ }
49
+ }
@@ -0,0 +1,2 @@
1
+
2
+ export * from './http-exception.filter';
package/src/index.ts CHANGED
@@ -10,3 +10,8 @@ export * from './utils/proto-path';
10
10
  export * from './utils/user.utils';
11
11
  export * from './utils/app.utils';
12
12
  export * from './utils/health.utils';
13
+ export * from './filters';
14
+ export * from './interceptors';
15
+ export * from './observability';
16
+ export * from './resilience/resilience.module';
17
+ export * from './resilience/circuit-breaker.service';
@@ -0,0 +1,3 @@
1
+
2
+ export * from './logging.interceptor';
3
+ export * from './transform.interceptor';
@@ -0,0 +1,37 @@
1
+
2
+ import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
3
+ import { Observable } from 'rxjs';
4
+ import { tap } from 'rxjs/operators';
5
+ import { randomUUID } from 'crypto';
6
+ import { Request, Response } from 'express';
7
+
8
+ @Injectable()
9
+ export class LoggingInterceptor implements NestInterceptor {
10
+ private readonly logger = new Logger(LoggingInterceptor.name);
11
+
12
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
13
+ const httpContext = context.switchToHttp();
14
+ const request = httpContext.getRequest<Request>();
15
+ const response = httpContext.getResponse<Response>();
16
+
17
+ const userAgent = request.get('user-agent') || '';
18
+ const { ip, method, path: url } = request;
19
+
20
+ // Generate or retrieve Trace ID
21
+ const traceId = request.headers['x-request-id'] || randomUUID();
22
+ request.headers['x-request-id'] = traceId as string;
23
+ response.setHeader('x-request-id', traceId);
24
+
25
+ this.logger.log(`[${traceId}] Incoming Request: ${method} ${url} - ${userAgent} ${ip}`);
26
+
27
+ const now = Date.now();
28
+ return next
29
+ .handle()
30
+ .pipe(
31
+ tap(() => {
32
+ const duration = Date.now() - now;
33
+ this.logger.log(`[${traceId}] Response Sent: ${method} ${url} ${response.statusCode} - ${duration}ms`);
34
+ }),
35
+ );
36
+ }
37
+ }
@@ -0,0 +1,21 @@
1
+
2
+ import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
3
+ import { Observable } from 'rxjs';
4
+ import { map } from 'rxjs/operators';
5
+
6
+ export interface Response<T> {
7
+ statusCode: number;
8
+ data: T;
9
+ }
10
+
11
+ @Injectable()
12
+ export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
13
+ intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
14
+ return next.handle().pipe(
15
+ map(data => ({
16
+ statusCode: context.switchToHttp().getResponse().statusCode,
17
+ data,
18
+ })),
19
+ );
20
+ }
21
+ }
@@ -0,0 +1,3 @@
1
+
2
+ export * from './metrics/metrics.module';
3
+ export * from './tracing';
@@ -0,0 +1,16 @@
1
+
2
+ import { Module } from '@nestjs/common';
3
+ import { PrometheusModule } from '@willsoto/nestjs-prometheus';
4
+
5
+ @Module({
6
+ imports: [
7
+ PrometheusModule.register({
8
+ path: '/metrics',
9
+ defaultMetrics: {
10
+ enabled: true,
11
+ },
12
+ }),
13
+ ],
14
+ exports: [PrometheusModule],
15
+ })
16
+ export class MetricsModule { }
@@ -0,0 +1,33 @@
1
+ import { NodeSDK } from '@opentelemetry/sdk-node';
2
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
3
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
4
+ import { Logger } from '@nestjs/common';
5
+
6
+ const logger = new Logger('Tracing');
7
+
8
+ export function initTracing(serviceName: string) {
9
+ const otelExporterOtlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://jaeger:4318/v1/traces';
10
+
11
+ const traceExporter = new OTLPTraceExporter({
12
+ url: otelExporterOtlpEndpoint,
13
+ });
14
+
15
+ // Set service name via env var so auto-detection picks it up
16
+ process.env.OTEL_SERVICE_NAME = serviceName;
17
+
18
+ const sdk = new NodeSDK({
19
+ traceExporter,
20
+ instrumentations: [getNodeAutoInstrumentations()],
21
+ });
22
+
23
+ sdk.start();
24
+
25
+ logger.log(`Initialized tracing for ${serviceName} sending to ${otelExporterOtlpEndpoint}`);
26
+
27
+ process.on('SIGTERM', () => {
28
+ sdk.shutdown()
29
+ .then(() => console.log('Tracing terminated'))
30
+ .catch((error) => console.log('Error terminating tracing', error))
31
+ .finally(() => process.exit(0));
32
+ });
33
+ }
@@ -0,0 +1,46 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+ import CircuitBreaker = require('opossum');
3
+
4
+ @Injectable()
5
+ export class CircuitBreakerService {
6
+ private readonly logger = new Logger(CircuitBreakerService.name);
7
+ private readonly breakers = new Map<string, CircuitBreaker>();
8
+
9
+ /**
10
+ * Execute an async action through a circuit breaker.
11
+ * @param key Unique key for the breaker (e.g., service URL)
12
+ * @param action The async action to execute
13
+ * @param options Circuit Breaker options
14
+ */
15
+ async execute<T>(
16
+ key: string,
17
+ action: () => Promise<T>,
18
+ options?: CircuitBreaker.Options
19
+ ): Promise<T> {
20
+ let breaker = this.breakers.get(key);
21
+
22
+ if (!breaker) {
23
+ const defaultOptions: CircuitBreaker.Options = {
24
+ timeout: 5000,
25
+ errorThresholdPercentage: 50,
26
+ resetTimeout: 10000,
27
+ ...options,
28
+ };
29
+
30
+ // Wrap a pass-through function to allow dynamic actions
31
+ const passThrough = async (promiseFactory: () => Promise<T>) => promiseFactory();
32
+ breaker = new CircuitBreaker(passThrough, defaultOptions);
33
+ this.bindEvents(breaker, key);
34
+ this.breakers.set(key, breaker);
35
+ }
36
+
37
+ return breaker.fire(action) as Promise<T>;
38
+ }
39
+
40
+ private bindEvents(breaker: CircuitBreaker, key: string) {
41
+ breaker.on('open', () => this.logger.warn(`Circuit Breaker OPEN for ${key}`));
42
+ breaker.on('halfOpen', () => this.logger.log(`Circuit Breaker HALF-OPEN for ${key}`));
43
+ breaker.on('close', () => this.logger.log(`Circuit Breaker CLOSED for ${key}`));
44
+ breaker.on('fallback', () => this.logger.warn(`Circuit Breaker FALLBACK for ${key}`));
45
+ }
46
+ }
@@ -0,0 +1,9 @@
1
+ import { Module, Global } from '@nestjs/common';
2
+ import { CircuitBreakerService } from './circuit-breaker.service';
3
+
4
+ @Global()
5
+ @Module({
6
+ providers: [CircuitBreakerService],
7
+ exports: [CircuitBreakerService],
8
+ })
9
+ export class ResilienceModule { }
@@ -1,7 +1,10 @@
1
- export interface JwtPayload {
1
+ import { JsonObject, JsonValue } from './common.types';
2
+ import { SubjectType } from '../enums/iam.enum';
3
+ export interface JwtPayload extends JsonObject {
2
4
  sub: string;
3
- email: string;
5
+ email?: string;
4
6
  role: string;
7
+ subjectType: SubjectType;
5
8
  scopes: string[];
6
9
  iat?: number;
7
10
  exp?: number;
@@ -14,6 +17,22 @@ export interface JwtTokens {
14
17
  }
15
18
 
16
19
  export interface AuthenticatedRequest {
17
- user: any;
18
- [key: string]: any;
20
+ user: JwtPayload;
21
+ [key: string]: JsonValue;
22
+ }
23
+ export interface ValidateServiceTokenResponse {
24
+ isValid: boolean;
25
+ identityId?: string;
26
+ tokenId?: string;
27
+ }
28
+
29
+ export interface Session {
30
+ sessionId: string;
31
+ identityId: string;
32
+ ipAddress?: string;
33
+ userAgent?: string;
34
+ deviceInfo?: string;
35
+ createdAt: Date;
36
+ expiresAt: Date;
37
+ isRevoked?: boolean;
19
38
  }
@@ -0,0 +1,18 @@
1
+ export type JsonPrimitive = string | number | boolean | null | undefined;
2
+
3
+ export interface JsonObject {
4
+ [key: string]: JsonValue;
5
+ }
6
+
7
+ export interface JsonArray extends Array<JsonValue> { }
8
+
9
+ export type JsonValue =
10
+ | JsonPrimitive
11
+ | JsonObject
12
+ | JsonArray;
13
+
14
+ export interface Metadata {
15
+ [key: string]: JsonValue;
16
+ }
17
+
18
+ export type MetricType = 'counter' | 'gauge' | 'histogram' | 'summary';