@takentrade/takentrade-libs 2.0.7 → 3.0.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.
- package/LICENSE +87 -0
- package/README.md +112 -743
- package/dist/common/health/health.controller.js +0 -2
- package/dist/common/index.d.ts +0 -2
- package/dist/common/index.js +0 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/metrics/circuit-breaker-metrics.service.d.ts +61 -0
- package/dist/metrics/circuit-breaker-metrics.service.js +149 -0
- package/dist/metrics/index.d.ts +5 -0
- package/dist/metrics/index.js +21 -0
- package/dist/metrics/metrics-registry.d.ts +50 -0
- package/dist/metrics/metrics-registry.js +156 -0
- package/dist/metrics/metrics-updater.d.ts +32 -0
- package/dist/metrics/metrics-updater.js +102 -0
- package/dist/metrics/metrics.controller.d.ts +11 -0
- package/dist/metrics/metrics.controller.js +32 -0
- package/dist/metrics/metrics.interface.d.ts +106 -0
- package/dist/metrics/metrics.interface.js +35 -0
- package/dist/metrics/metrics.module.d.ts +11 -0
- package/dist/metrics/metrics.module.js +39 -0
- package/dist/metrics/metrics.service.d.ts +50 -0
- package/dist/metrics/metrics.service.js +165 -0
- package/dist/notification/notification.interface.d.ts +2 -0
- package/dist/resilience/circuit-breaker-event-handler.d.ts +16 -0
- package/dist/resilience/circuit-breaker-event-handler.js +70 -0
- package/dist/resilience/circuit-breaker-factory.d.ts +19 -0
- package/dist/resilience/circuit-breaker-factory.js +51 -0
- package/dist/resilience/circuit-breaker-stats.service.d.ts +37 -0
- package/dist/resilience/circuit-breaker-stats.service.js +69 -0
- package/dist/resilience/circuit-breaker.interface.d.ts +134 -0
- package/dist/resilience/circuit-breaker.interface.js +31 -0
- package/dist/{common/circuit-breaker → resilience}/circuit-breaker.module.js +1 -0
- package/dist/resilience/circuit-breaker.service.d.ts +119 -0
- package/dist/resilience/circuit-breaker.service.js +234 -0
- package/dist/resilience/index.d.ts +3 -0
- package/dist/resilience/index.js +19 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/dto/pagination.js +0 -6
- package/package.json +5 -2
- package/dist/common/circuit-breaker/circuit-breaker.service.d.ts +0 -13
- package/dist/common/circuit-breaker/circuit-breaker.service.js +0 -120
- package/dist/common/circuit-breaker/circuit-breaker.types.d.ts +0 -19
- package/dist/common/circuit-breaker/circuit-breaker.types.js +0 -9
- /package/dist/{common/circuit-breaker → resilience}/circuit-breaker.module.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TakeNTrade Microservices Libraries
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared libraries for the TakeNTrade microservices architecture, providing authentication, caching, messaging, notifications, resilience patterns, metrics, and common utilities.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,808 +8,177 @@ This package contains shared libraries used across the TakeNTrade microservices
|
|
|
8
8
|
npm install @takentrade/takentrade-libs
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
- [Authentication & Authorization](#authentication--authorization)
|
|
14
|
-
- [Cache Library (`@/libs/cache`)](#cache-library-libscache)
|
|
15
|
-
- [BullMQ Library (`@/libs/bullmq`)](#bullmq-library-libsbullmq)
|
|
16
|
-
- [NATS Library (`@/libs/nats`)](#nats-library-libsnats)
|
|
17
|
-
- [Notification Client](#notification-client)
|
|
18
|
-
- [Prisma Module](#prisma-module)
|
|
19
|
-
- [RPC Utilities](#rpc-utilities)
|
|
20
|
-
- [Common Utilities](#common-utilities)
|
|
21
|
-
- [Utils Module](#utils-module)
|
|
22
|
-
- [Configuration](#configuration)
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Authentication & Authorization
|
|
27
|
-
|
|
28
|
-
### TNTBaseAuthGuard
|
|
29
|
-
|
|
30
|
-
A base implementation of the auth guard to be used across each service in the system.
|
|
31
|
-
|
|
32
|
-
#### Dependencies
|
|
33
|
-
|
|
34
|
-
- A JWT secret (provided via `ConfigService` or environment variable)
|
|
35
|
-
|
|
36
|
-
#### Usage
|
|
11
|
+
## Quick Start
|
|
37
12
|
|
|
38
13
|
```typescript
|
|
39
14
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
ROLES_KEY,
|
|
15
|
+
CacheModule,
|
|
16
|
+
MetricsModule,
|
|
17
|
+
CircuitBreakerModule,
|
|
44
18
|
} from '@takentrade/takentrade-libs';
|
|
45
|
-
import { Reflector } from '@nestjs/core';
|
|
46
|
-
import { ConfigService } from '@nestjs/config';
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Create your own auth guard extending the TNTBaseAuthGuard.
|
|
50
|
-
* This ensures the guard is in the same context as your NestJS application for better error capturing.
|
|
51
|
-
*/
|
|
52
|
-
export class AuthGuard extends TNTBaseAuthGuard {
|
|
53
|
-
constructor(
|
|
54
|
-
private reflector: Reflector,
|
|
55
|
-
private configService: ConfigService
|
|
56
|
-
) {
|
|
57
|
-
super(reflector);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
61
|
-
const result = await super.canActivate(
|
|
62
|
-
context,
|
|
63
|
-
this.configService.get('JWT_SECRET') as string
|
|
64
|
-
);
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// In your controller
|
|
70
|
-
@Controller('example')
|
|
71
|
-
@UseGuards(AuthGuard)
|
|
72
|
-
export class ExampleController {
|
|
73
|
-
// Public endpoint (no authentication required)
|
|
74
|
-
@Public()
|
|
75
|
-
@Get('public')
|
|
76
|
-
publicEndpoint() {
|
|
77
|
-
return { message: 'This is public' };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Protected endpoint (authentication required)
|
|
81
|
-
@Get('protected')
|
|
82
|
-
protectedEndpoint() {
|
|
83
|
-
return { message: 'This requires authentication' };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Role-based access control
|
|
87
|
-
@Roles('admin', 'moderator')
|
|
88
|
-
@Get('admin')
|
|
89
|
-
adminEndpoint() {
|
|
90
|
-
return { message: 'This requires admin or moderator role' };
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### Decorators
|
|
96
|
-
|
|
97
|
-
- **`@Public()`**: Marks a route as publicly accessible (bypasses authentication)
|
|
98
|
-
- **`@Roles(...roles: string[])`**: Restricts access to routes based on user roles
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Cache Library (`@/libs/cache`)
|
|
103
|
-
|
|
104
|
-
Redis-based caching implementation for the microservices.
|
|
105
|
-
|
|
106
|
-
### Cache Environment Variables
|
|
107
|
-
|
|
108
|
-
```env
|
|
109
|
-
REDIS_HOST=localhost # Default: localhost
|
|
110
|
-
REDIS_PORT=6379 # Default: 6379
|
|
111
|
-
REDIS_USERNAME= # Optional
|
|
112
|
-
REDIS_PASSWORD= # Optional
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Cache Usage
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { CacheModule, CacheService } from '@takentrade/takentrade-libs';
|
|
119
19
|
|
|
120
|
-
@Module({
|
|
121
|
-
imports: [CacheModule.register()],
|
|
122
|
-
})
|
|
123
|
-
export class AppModule {}
|
|
124
|
-
|
|
125
|
-
// In your service
|
|
126
|
-
@Injectable()
|
|
127
|
-
export class MyService {
|
|
128
|
-
constructor(private readonly cacheService: CacheService) {}
|
|
129
|
-
|
|
130
|
-
// Basic cache operations
|
|
131
|
-
async example() {
|
|
132
|
-
// Set with TTL (time to live in seconds)
|
|
133
|
-
await this.cacheService.set('key', 'value', 3600); // expires in 1 hour
|
|
134
|
-
|
|
135
|
-
// Get value
|
|
136
|
-
const value = await this.cacheService.get('key');
|
|
137
|
-
|
|
138
|
-
// Delete key
|
|
139
|
-
await this.cacheService.del('key');
|
|
140
|
-
|
|
141
|
-
// Hash operations (Redis hashes)
|
|
142
|
-
await this.cacheService.hset('hash-key', 'field', 'value');
|
|
143
|
-
const hashValue = await this.cacheService.hget('hash-key', 'field');
|
|
144
|
-
const allValues = await this.cacheService.hgetall('hash-key');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Cache Methods
|
|
150
|
-
|
|
151
|
-
- `set(key: string, value: any, ttlSeconds?: number)`: Set a key-value pair with optional TTL
|
|
152
|
-
- `get(key: string)`: Get a value by key
|
|
153
|
-
- `del(key: string)`: Delete a key
|
|
154
|
-
- `hset(key: string, field: string, value: any)`: Set a hash field
|
|
155
|
-
- `hget(key: string, field: string)`: Get a hash field value
|
|
156
|
-
- `hgetall(key: string)`: Get all fields and values from a hash
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## BullMQ Library (`@/libs/bullmq`)
|
|
161
|
-
|
|
162
|
-
Background job processing library for handling long-running tasks, retries, and scheduled jobs.
|
|
163
|
-
|
|
164
|
-
### BullMQ Environment Variables
|
|
165
|
-
|
|
166
|
-
```env
|
|
167
|
-
REDIS_HOST=localhost
|
|
168
|
-
REDIS_PORT=6379
|
|
169
|
-
REDIS_PASSWORD=your_password
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### BullMQ Usage
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
import { BullmqModule } from '@takentrade/takentrade-libs';
|
|
176
|
-
import { Queue, Job } from 'bullmq';
|
|
177
|
-
import { Inject } from '@nestjs/common';
|
|
178
|
-
import { join } from 'path';
|
|
179
|
-
|
|
180
|
-
// Register in your module
|
|
181
20
|
@Module({
|
|
182
21
|
imports: [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
concurrency: 3,
|
|
187
|
-
defaultJobOptions: {
|
|
188
|
-
attempts: 3,
|
|
189
|
-
backoff: {
|
|
190
|
-
type: 'exponential',
|
|
191
|
-
delay: 1000,
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
}),
|
|
22
|
+
CacheModule.register(),
|
|
23
|
+
MetricsModule.register({ defaultMetrics: true }),
|
|
24
|
+
CircuitBreakerModule,
|
|
195
25
|
],
|
|
196
26
|
})
|
|
197
27
|
export class AppModule {}
|
|
198
|
-
|
|
199
|
-
// Create a job processor (my.processor.ts)
|
|
200
|
-
export default async function myProcessor(job: Job) {
|
|
201
|
-
try {
|
|
202
|
-
console.log(`Processing job ${job.id}`);
|
|
203
|
-
await job.updateProgress(50);
|
|
204
|
-
// Your job logic here
|
|
205
|
-
return { processed: true };
|
|
206
|
-
} catch (error) {
|
|
207
|
-
console.error(`Error processing job ${job.id}:`, error);
|
|
208
|
-
throw error;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// In your service
|
|
213
|
-
@Injectable()
|
|
214
|
-
export class MyService {
|
|
215
|
-
constructor(
|
|
216
|
-
@Inject('BullQueue_my-queue')
|
|
217
|
-
private myQueue: Queue
|
|
218
|
-
) {}
|
|
219
|
-
|
|
220
|
-
async addJob(data: any) {
|
|
221
|
-
// Regular job
|
|
222
|
-
await this.myQueue.add('job-name', data);
|
|
223
|
-
|
|
224
|
-
// Delayed job (executes after 5 seconds)
|
|
225
|
-
await this.myQueue.add('delayed-job', data, {
|
|
226
|
-
delay: 5000,
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Repeatable job (executes every minute)
|
|
230
|
-
await this.myQueue.add('repeatable-job', data, {
|
|
231
|
-
repeat: {
|
|
232
|
-
every: 1000 * 60, // Every minute
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
28
|
```
|
|
238
29
|
|
|
239
|
-
|
|
30
|
+
## Modules
|
|
240
31
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
32
|
+
| Module | Description | Documentation |
|
|
33
|
+
| ------------------ | ---------------------------------------------- | ---------------------------------------------- |
|
|
34
|
+
| **Authentication** | Route protection and role-based access control | [docs/auth.md](docs/auth.md) |
|
|
35
|
+
| **Cache** | Redis-based caching with TTL support | [docs/cache.md](docs/cache.md) |
|
|
36
|
+
| **BullMQ** | Background job processing and queues | [docs/bullmq.md](docs/bullmq.md) |
|
|
37
|
+
| **NATS** | Microservice messaging and event streaming | [docs/nats.md](docs/nats.md) |
|
|
38
|
+
| **Notifications** | Email, SMS, and push notifications | [docs/notifications.md](docs/notifications.md) |
|
|
39
|
+
| **RPC** | Request-response patterns for NATS | [docs/rpc.md](docs/rpc.md) |
|
|
40
|
+
| **Resilience** | Circuit breakers for fault tolerance | [docs/resilience.md](docs/resilience.md) |
|
|
41
|
+
| **Metrics** | Prometheus metrics collection | [docs/metrics.md](docs/metrics.md) |
|
|
42
|
+
| **Common** | Shared constants, enums, and utilities | [docs/common.md](docs/common.md) |
|
|
43
|
+
| **Utils** | DTOs, pipes, filters, and helpers | [docs/utils.md](docs/utils.md) |
|
|
247
44
|
|
|
248
|
-
|
|
45
|
+
## Features
|
|
249
46
|
|
|
250
|
-
|
|
47
|
+
### 🔐 Authentication & Authorization
|
|
251
48
|
|
|
252
|
-
|
|
49
|
+
- `@Public()` and `@Roles()` decorators
|
|
50
|
+
- JWT-based authentication support
|
|
51
|
+
- Role-based access control
|
|
253
52
|
|
|
254
|
-
###
|
|
53
|
+
### 💾 Caching
|
|
255
54
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
### NATS Usage
|
|
262
|
-
|
|
263
|
-
```typescript
|
|
264
|
-
import {
|
|
265
|
-
NatsSubjects,
|
|
266
|
-
NatsEventPattern,
|
|
267
|
-
NatsMessageDto,
|
|
268
|
-
NatsLoggingInterceptor,
|
|
269
|
-
NATS_CLIENT,
|
|
270
|
-
DEFAULT_NATS_CONFIG,
|
|
271
|
-
} from '@takentrade/takentrade-libs';
|
|
272
|
-
import { ClientProxy, Inject } from '@nestjs/common';
|
|
273
|
-
|
|
274
|
-
// Event handler (listening to events)
|
|
275
|
-
@Controller()
|
|
276
|
-
export class MyController {
|
|
277
|
-
@NatsEventPattern(NatsSubjects.USER_CREATED)
|
|
278
|
-
async handleUserCreated(@Payload() data: NatsMessageDto) {
|
|
279
|
-
console.log('User created:', data);
|
|
280
|
-
// Handle the event
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Using the standard EventPattern with logging
|
|
284
|
-
@EventPattern('custom.event')
|
|
285
|
-
@UseInterceptors(NatsLoggingInterceptor)
|
|
286
|
-
async handleCustomEvent(@Payload() data: any) {
|
|
287
|
-
// Handle event
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Event publisher (sending events)
|
|
292
|
-
@Injectable()
|
|
293
|
-
export class MyService {
|
|
294
|
-
constructor(@Inject(NATS_CLIENT) private readonly natsClient: ClientProxy) {}
|
|
295
|
-
|
|
296
|
-
async publishEvent() {
|
|
297
|
-
this.natsClient.emit(NatsSubjects.USER_CREATED, {
|
|
298
|
-
userId: '123',
|
|
299
|
-
email: 'user@example.com',
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// RPC request-response pattern
|
|
304
|
-
async requestData() {
|
|
305
|
-
const response = await this.natsClient
|
|
306
|
-
.send(NatsSubjects.GET_USER_BY_ID, { userId: '123' })
|
|
307
|
-
.toPromise();
|
|
308
|
-
return response;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### NATS Subjects
|
|
55
|
+
- Redis integration with ioredis
|
|
56
|
+
- TTL support
|
|
57
|
+
- Hash operations
|
|
58
|
+
- Auto-reconnection
|
|
314
59
|
|
|
315
|
-
|
|
60
|
+
### 📊 Metrics & Observability
|
|
316
61
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
NatsSubjects.SUBACCOUNT_UPDATE_AMOUNT;
|
|
323
|
-
NatsSubjects.NOTIFICATION_SEND;
|
|
324
|
-
NatsSubjects.AJO_CREATE;
|
|
325
|
-
NatsSubjects.CHAT_GET_CONVERSATIONS;
|
|
326
|
-
// ... and many more
|
|
327
|
-
```
|
|
62
|
+
- Prometheus metrics with prom-client
|
|
63
|
+
- Default process metrics (CPU, memory, event loop)
|
|
64
|
+
- Custom counters, gauges, histograms, summaries
|
|
65
|
+
- Circuit breaker metrics integration
|
|
66
|
+
- `/metrics` endpoint for scraping
|
|
328
67
|
|
|
329
|
-
###
|
|
68
|
+
### 🔄 Resilience
|
|
330
69
|
|
|
331
|
-
-
|
|
332
|
-
-
|
|
70
|
+
- Circuit breakers using Opossum
|
|
71
|
+
- Automatic failure detection
|
|
72
|
+
- Fallback support
|
|
73
|
+
- Health checks
|
|
74
|
+
- Request caching
|
|
75
|
+
- Comprehensive metrics
|
|
333
76
|
|
|
334
|
-
|
|
77
|
+
### 🚀 Background Jobs
|
|
335
78
|
|
|
336
|
-
|
|
79
|
+
- BullMQ integration
|
|
80
|
+
- Job scheduling and retries
|
|
81
|
+
- Delayed and repeatable jobs
|
|
82
|
+
- Progress tracking
|
|
337
83
|
|
|
338
|
-
|
|
84
|
+
### 📨 Messaging
|
|
339
85
|
|
|
340
|
-
|
|
86
|
+
- NATS integration
|
|
87
|
+
- Event patterns
|
|
88
|
+
- Request-response (RPC)
|
|
89
|
+
- Subject constants
|
|
90
|
+
- Automatic logging
|
|
341
91
|
|
|
342
|
-
|
|
343
|
-
import {
|
|
344
|
-
NotificationClientModule,
|
|
345
|
-
NotificationClient,
|
|
346
|
-
} from '@takentrade/takentrade-libs';
|
|
92
|
+
### 📧 Notifications
|
|
347
93
|
|
|
348
|
-
|
|
349
|
-
imports: [NotificationClientModule],
|
|
350
|
-
})
|
|
351
|
-
export class AppModule {}
|
|
352
|
-
|
|
353
|
-
// In your service
|
|
354
|
-
@Injectable()
|
|
355
|
-
export class MyService {
|
|
356
|
-
constructor(private readonly notificationClient: NotificationClient) {}
|
|
357
|
-
|
|
358
|
-
async sendNotifications() {
|
|
359
|
-
// Send SMS
|
|
360
|
-
await this.notificationClient.sendSms(
|
|
361
|
-
'+2341234567890',
|
|
362
|
-
'Your OTP is 123456'
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
// Send Email
|
|
366
|
-
await this.notificationClient.sendEmailVerificationMail(
|
|
367
|
-
'user@example.com',
|
|
368
|
-
{
|
|
369
|
-
name: 'John Doe',
|
|
370
|
-
verificationLink: 'https://example.com/verify?token=abc123',
|
|
371
|
-
}
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
// Send OTP Email
|
|
375
|
-
await this.notificationClient.sendOTPMail('user@example.com', {
|
|
376
|
-
name: 'John Doe',
|
|
377
|
-
otp: '123456',
|
|
378
|
-
purpose: 'phone_verification',
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// Send Password Reset Email
|
|
382
|
-
await this.notificationClient.sendPasswordResetMail('user@example.com', {
|
|
383
|
-
name: 'John Doe',
|
|
384
|
-
resetLink: 'https://example.com/reset?token=abc123',
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Send Push Notification
|
|
388
|
-
await this.notificationClient.sendPushNotification({
|
|
389
|
-
userId: '123',
|
|
390
|
-
title: 'New Message',
|
|
391
|
-
body: 'You have a new message',
|
|
392
|
-
data: { messageId: '456' },
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Notification Client Methods
|
|
399
|
-
|
|
400
|
-
The `NotificationClient` provides numerous methods for different notification types:
|
|
401
|
-
|
|
402
|
-
- Email notifications (verification, OTP, password reset, transaction alerts, etc.)
|
|
94
|
+
- Email (verification, OTP, password reset, etc.)
|
|
403
95
|
- SMS notifications
|
|
404
96
|
- Push notifications
|
|
405
|
-
-
|
|
406
|
-
|
|
407
|
-
---
|
|
97
|
+
- Template support
|
|
408
98
|
|
|
409
|
-
##
|
|
99
|
+
## Environment Variables
|
|
410
100
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
import { PrismaModule, PrismaService } from '@takentrade/takentrade-libs';
|
|
417
|
-
|
|
418
|
-
@Module({
|
|
419
|
-
imports: [PrismaModule], // Global module, available everywhere
|
|
420
|
-
})
|
|
421
|
-
export class AppModule {}
|
|
422
|
-
|
|
423
|
-
// In your service
|
|
424
|
-
@Injectable()
|
|
425
|
-
export class MyService {
|
|
426
|
-
constructor(private readonly prisma: PrismaService) {}
|
|
427
|
-
|
|
428
|
-
async getUsers() {
|
|
429
|
-
return this.prisma.user.findMany();
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
## RPC Utilities
|
|
437
|
-
|
|
438
|
-
Utilities for handling RPC (Request-Response) patterns in NATS.
|
|
439
|
-
|
|
440
|
-
### RPC Usage
|
|
441
|
-
|
|
442
|
-
```typescript
|
|
443
|
-
import { TakeNTradeRpc, TakeNTradeRpcV2 } from '@takentrade/takentrade-libs';
|
|
444
|
-
import { NatsContext } from '@nestjs/microservices';
|
|
445
|
-
|
|
446
|
-
// RPC handler with automatic error handling
|
|
447
|
-
@Controller()
|
|
448
|
-
export class MyController {
|
|
449
|
-
@MessagePattern('get.user.by.id')
|
|
450
|
-
async getUserById(@Payload() data: any, @Ctx() ctx: NatsContext) {
|
|
451
|
-
return TakeNTradeRpc.handleRequest(
|
|
452
|
-
this.userService.findById(data.userId),
|
|
453
|
-
ctx
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Alternative version that returns error directly instead of RpcException
|
|
458
|
-
@MessagePattern('get.user.balance')
|
|
459
|
-
async getUserBalance(@Payload() data: any, @Ctx() ctx: NatsContext) {
|
|
460
|
-
return TakeNTradeRpcV2.handleRequest(
|
|
461
|
-
this.userService.getBalance(data.userId),
|
|
462
|
-
ctx
|
|
463
|
-
);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// RPC client (sending requests)
|
|
468
|
-
@Injectable()
|
|
469
|
-
export class MyService {
|
|
470
|
-
constructor(@Inject(NATS_CLIENT) private readonly natsClient: ClientProxy) {}
|
|
471
|
-
|
|
472
|
-
async getUserData(userId: string) {
|
|
473
|
-
const response = await TakeNTradeRpc.withReply(
|
|
474
|
-
this.natsClient.send('get.user.by.id', { userId })
|
|
475
|
-
);
|
|
476
|
-
return response.data;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### RPC Classes
|
|
482
|
-
|
|
483
|
-
- **`TakeNTradeRpc`**: Main RPC utility with automatic error handling that throws `RpcException`
|
|
484
|
-
- **`TakeNTradeRpcV2`**: Alternative RPC utility that returns error objects instead of throwing exceptions
|
|
485
|
-
|
|
486
|
-
---
|
|
487
|
-
|
|
488
|
-
## Common Utilities
|
|
489
|
-
|
|
490
|
-
### Common Constants
|
|
101
|
+
```env
|
|
102
|
+
# Cache & BullMQ
|
|
103
|
+
REDIS_HOST=localhost
|
|
104
|
+
REDIS_PORT=6379
|
|
105
|
+
REDIS_PASSWORD=your_password
|
|
491
106
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
AJO_QUEUE,
|
|
496
|
-
PAYMENT_QUEUE,
|
|
497
|
-
// ... and other queue constants
|
|
498
|
-
} from '@takentrade/takentrade-libs';
|
|
107
|
+
# NATS
|
|
108
|
+
NATS_URL=nats://localhost:4222
|
|
109
|
+
NATS_SERVICE_QUEUE=service_queue
|
|
499
110
|
|
|
500
|
-
|
|
501
|
-
|
|
111
|
+
# JWT
|
|
112
|
+
JWT_SECRET=your_jwt_secret
|
|
502
113
|
```
|
|
503
114
|
|
|
504
|
-
|
|
115
|
+
## Usage Examples
|
|
505
116
|
|
|
506
|
-
|
|
507
|
-
import {
|
|
508
|
-
OtpPurpose,
|
|
509
|
-
SubAccountType,
|
|
510
|
-
TicketStatus, // from common/enums
|
|
511
|
-
SupportActionType, // from common/enums
|
|
512
|
-
} from '@takentrade/takentrade-libs';
|
|
513
|
-
|
|
514
|
-
// OTP purposes
|
|
515
|
-
const purpose: OtpPurpose = OtpPurpose.PHONE_VERIFICATION;
|
|
516
|
-
|
|
517
|
-
// Subaccount types
|
|
518
|
-
const accountType: SubAccountType = SubAccountType.SAVINGS_ACCOUNT;
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
### String Utilities
|
|
117
|
+
### Cache
|
|
522
118
|
|
|
523
119
|
```typescript
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
maskPhoneNumber,
|
|
527
|
-
} from '@takentrade/takentrade-libs';
|
|
528
|
-
|
|
529
|
-
// Format phone number to international format
|
|
530
|
-
const formatted = formatPhoneNumber('08123456789'); // '2348123456789'
|
|
531
|
-
|
|
532
|
-
// Mask phone number for display
|
|
533
|
-
const masked = maskPhoneNumber('+2348123456789'); // '2348******789'
|
|
120
|
+
await this.cacheService.set('key', 'value', 3600); // 1 hour TTL
|
|
121
|
+
const value = await this.cacheService.get('key');
|
|
534
122
|
```
|
|
535
123
|
|
|
536
|
-
###
|
|
124
|
+
### Metrics
|
|
537
125
|
|
|
538
126
|
```typescript
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
// Custom options
|
|
548
|
-
const randomPassword = generateRandomString({
|
|
549
|
-
length: 12,
|
|
550
|
-
digits: true,
|
|
551
|
-
lowerCaseAlphabets: true,
|
|
552
|
-
upperCaseAlphabets: true,
|
|
553
|
-
specialChars: true,
|
|
127
|
+
this.metricsService.registerCounter({
|
|
128
|
+
name: 'requests_total',
|
|
129
|
+
help: 'Total requests',
|
|
130
|
+
labelNames: ['method', 'status'],
|
|
131
|
+
});
|
|
132
|
+
this.metricsService.incrementCounter('requests_total', {
|
|
133
|
+
method: 'GET',
|
|
134
|
+
status: '200',
|
|
554
135
|
});
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
### Reference Utilities
|
|
558
|
-
|
|
559
|
-
```typescript
|
|
560
|
-
import { generateReference } from '@takentrade/takentrade-libs';
|
|
561
|
-
|
|
562
|
-
// Generate unique reference string
|
|
563
|
-
const ref = generateReference('TXN'); // 'TXN-1234567890-ABC'
|
|
564
136
|
```
|
|
565
137
|
|
|
566
138
|
### Circuit Breaker
|
|
567
139
|
|
|
568
140
|
```typescript
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
@Module({
|
|
575
|
-
imports: [CircuitBreakerModule],
|
|
576
|
-
})
|
|
577
|
-
export class AppModule {}
|
|
578
|
-
|
|
579
|
-
@Injectable()
|
|
580
|
-
export class MyService {
|
|
581
|
-
constructor(private readonly circuitBreaker: CircuitBreakerService) {}
|
|
582
|
-
|
|
583
|
-
async callExternalService() {
|
|
584
|
-
const breaker = this.circuitBreaker.createBreaker('external-api', {
|
|
585
|
-
failureThreshold: 5,
|
|
586
|
-
resetTimeout: 60000,
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
if (this.circuitBreaker.isOpen('external-api')) {
|
|
590
|
-
throw new Error('Circuit breaker is open');
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
try {
|
|
594
|
-
const result = await this.externalApiCall();
|
|
595
|
-
this.circuitBreaker.recordSuccess('external-api');
|
|
596
|
-
return result;
|
|
597
|
-
} catch (error) {
|
|
598
|
-
this.circuitBreaker.recordFailure('external-api');
|
|
599
|
-
throw error;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
### Health Module
|
|
606
|
-
|
|
607
|
-
```typescript
|
|
608
|
-
import { HealthModule } from '@takentrade/takentrade-libs';
|
|
609
|
-
|
|
610
|
-
@Module({
|
|
611
|
-
imports: [HealthModule],
|
|
612
|
-
})
|
|
613
|
-
export class AppModule {}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
The health module provides a `/health` endpoint for service health checks.
|
|
617
|
-
|
|
618
|
-
---
|
|
619
|
-
|
|
620
|
-
## Utils Module
|
|
621
|
-
|
|
622
|
-
### DTOs
|
|
623
|
-
|
|
624
|
-
```typescript
|
|
625
|
-
import { PaginationDto } from '@takentrade/takentrade-libs';
|
|
626
|
-
|
|
627
|
-
// Pagination DTO for request queries
|
|
628
|
-
export class GetUsersDto extends PaginationDto {
|
|
629
|
-
@IsOptional()
|
|
630
|
-
@IsString()
|
|
631
|
-
search?: string;
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
### Pipes
|
|
636
|
-
|
|
637
|
-
```typescript
|
|
638
|
-
import { PaginationQueryCleanerPipe } from '@takentrade/takentrade-libs';
|
|
639
|
-
|
|
640
|
-
@Controller('users')
|
|
641
|
-
export class UserController {
|
|
642
|
-
@Get()
|
|
643
|
-
async getUsers(
|
|
644
|
-
@Query(PaginationQueryCleanerPipe) query: any // Removes page and limit from query
|
|
645
|
-
) {
|
|
646
|
-
// query object will not contain page and limit fields
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
### Interceptors
|
|
652
|
-
|
|
653
|
-
```typescript
|
|
654
|
-
import { ResponseInterceptor } from '@takentrade/takentrade-libs';
|
|
655
|
-
|
|
656
|
-
@Module({
|
|
657
|
-
providers: [
|
|
658
|
-
{
|
|
659
|
-
provide: APP_INTERCEPTOR,
|
|
660
|
-
useClass: ResponseInterceptor,
|
|
661
|
-
},
|
|
662
|
-
],
|
|
663
|
-
})
|
|
664
|
-
export class AppModule {}
|
|
665
|
-
```
|
|
666
|
-
|
|
667
|
-
The `ResponseInterceptor` automatically wraps all responses in a standard format:
|
|
668
|
-
|
|
669
|
-
```json
|
|
670
|
-
{
|
|
671
|
-
"success": true,
|
|
672
|
-
"message": "Operation successful",
|
|
673
|
-
"data": {
|
|
674
|
-
/* your data */
|
|
675
|
-
},
|
|
676
|
-
"metadata": {
|
|
677
|
-
"path": "/api/users",
|
|
678
|
-
"requestId": "uuid",
|
|
679
|
-
"timestamp": "2024-01-01T00:00:00Z"
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
### Filters
|
|
685
|
-
|
|
686
|
-
```typescript
|
|
687
|
-
import { HttpExceptionFilter } from '@takentrade/takentrade-libs';
|
|
688
|
-
|
|
689
|
-
@Module({
|
|
690
|
-
providers: [
|
|
691
|
-
{
|
|
692
|
-
provide: APP_FILTER,
|
|
693
|
-
useClass: HttpExceptionFilter,
|
|
694
|
-
},
|
|
695
|
-
],
|
|
696
|
-
})
|
|
697
|
-
export class AppModule {}
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
The `HttpExceptionFilter` catches all exceptions and formats them consistently.
|
|
701
|
-
|
|
702
|
-
### Validators
|
|
703
|
-
|
|
704
|
-
```typescript
|
|
705
|
-
import { ValidateNatsMessage } from '@takentrade/takentrade-libs';
|
|
706
|
-
|
|
707
|
-
@Controller()
|
|
708
|
-
export class MyController {
|
|
709
|
-
@EventPattern('user.created')
|
|
710
|
-
async handleUserCreated(
|
|
711
|
-
@Payload(ValidateNatsMessage(UserCreatedDto)) data: UserCreatedDto
|
|
712
|
-
) {
|
|
713
|
-
// data is validated and typed
|
|
714
|
-
}
|
|
715
|
-
}
|
|
141
|
+
this.circuitBreaker.createBreaker('api', async (data) => this.apiCall(data), {
|
|
142
|
+
timeout: 5000,
|
|
143
|
+
errorThresholdPercentage: 50,
|
|
144
|
+
});
|
|
145
|
+
const result = await this.circuitBreaker.fire('api', requestData);
|
|
716
146
|
```
|
|
717
147
|
|
|
718
|
-
###
|
|
148
|
+
### Background Jobs
|
|
719
149
|
|
|
720
150
|
```typescript
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const users = await this.userService.findAll();
|
|
728
|
-
return AppResponse.success(users, 'Users retrieved successfully');
|
|
151
|
+
await this.queue.add(
|
|
152
|
+
'process-order',
|
|
153
|
+
{ orderId: '123' },
|
|
154
|
+
{
|
|
155
|
+
attempts: 3,
|
|
156
|
+
backoff: { type: 'exponential', delay: 1000 },
|
|
729
157
|
}
|
|
730
|
-
|
|
158
|
+
);
|
|
731
159
|
```
|
|
732
160
|
|
|
733
|
-
|
|
161
|
+
## Documentation
|
|
734
162
|
|
|
735
|
-
|
|
736
|
-
|
|
163
|
+
- [Authentication](docs/auth.md) - Route protection and RBAC
|
|
164
|
+
- [Cache](docs/cache.md) - Redis caching
|
|
165
|
+
- [BullMQ](docs/bullmq.md) - Background jobs
|
|
166
|
+
- [NATS](docs/nats.md) - Messaging
|
|
167
|
+
- [Notifications](docs/notifications.md) - Email, SMS, push
|
|
168
|
+
- [RPC](docs/rpc.md) - Request-response patterns
|
|
169
|
+
- [Resilience](docs/resilience.md) - Circuit breakers
|
|
170
|
+
- [Metrics](docs/metrics.md) - Prometheus metrics
|
|
171
|
+
- [Common](docs/common.md) - Shared utilities
|
|
172
|
+
- [Utils](docs/utils.md) - DTOs, pipes, filters
|
|
737
173
|
|
|
738
|
-
|
|
739
|
-
// Returns: { data: [1, 2], total: 5, page: 1, limit: 2, totalPages: 3 }
|
|
740
|
-
```
|
|
741
|
-
|
|
742
|
-
### OTP Utilities
|
|
743
|
-
|
|
744
|
-
```typescript
|
|
745
|
-
import { generateOTP, verifyOTP } from '@takentrade/takentrade-libs';
|
|
174
|
+
## Contributing
|
|
746
175
|
|
|
747
|
-
|
|
748
|
-
const otp = generateOTP(6); // 6-digit OTP
|
|
176
|
+
This is a private package for TakeNTrade microservices.
|
|
749
177
|
|
|
750
|
-
|
|
751
|
-
const isValid = verifyOTP(otp, storedOtp, expirationTime);
|
|
752
|
-
```
|
|
753
|
-
|
|
754
|
-
### Configuration Utilities
|
|
755
|
-
|
|
756
|
-
```typescript
|
|
757
|
-
import { getConfiguration } from '@takentrade/takentrade-libs';
|
|
758
|
-
|
|
759
|
-
const config = getConfiguration();
|
|
760
|
-
// Returns typed configuration object
|
|
761
|
-
```
|
|
762
|
-
|
|
763
|
-
---
|
|
764
|
-
|
|
765
|
-
## Configuration
|
|
766
|
-
|
|
767
|
-
Most libraries require configuration through environment variables. Ensure these are set in your service's `.env` file:
|
|
768
|
-
|
|
769
|
-
```env
|
|
770
|
-
# Cache & BullMQ Configuration
|
|
771
|
-
REDIS_HOST=localhost
|
|
772
|
-
REDIS_PORT=6379
|
|
773
|
-
REDIS_USERNAME=
|
|
774
|
-
REDIS_PASSWORD=your_password
|
|
775
|
-
|
|
776
|
-
# NATS Configuration
|
|
777
|
-
NATS_URL=nats://localhost:4222
|
|
778
|
-
NATS_SERVICE_QUEUE=service_queue # Replace 'service' with your service name
|
|
779
|
-
|
|
780
|
-
# JWT Configuration
|
|
781
|
-
JWT_SECRET=your_jwt_secret
|
|
782
|
-
|
|
783
|
-
# Database (for Prisma)
|
|
784
|
-
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
|
|
785
|
-
```
|
|
786
|
-
|
|
787
|
-
---
|
|
788
|
-
|
|
789
|
-
## Best Practices
|
|
790
|
-
|
|
791
|
-
1. **Always import from the library's main entry point**: Use `@takentrade/takentrade-libs` instead of internal paths
|
|
792
|
-
2. **Use TypeScript types and interfaces**: Take advantage of the provided types for better type safety
|
|
793
|
-
3. **Follow async/await pattern**: Most library functions are promise-based
|
|
794
|
-
4. **Configure modules properly**: Register modules in your service's root module
|
|
795
|
-
5. **Handle errors appropriately**: Use the provided filters and interceptors for consistent error handling
|
|
796
|
-
6. **Use constants for NATS subjects**: Always use `NatsSubjects` enum instead of hardcoding subject strings
|
|
797
|
-
7. **Leverage RPC utilities**: Use `TakeNTradeRpc` for consistent RPC error handling
|
|
798
|
-
|
|
799
|
-
---
|
|
800
|
-
|
|
801
|
-
## Exports
|
|
802
|
-
|
|
803
|
-
The package exports the following sub-paths:
|
|
804
|
-
|
|
805
|
-
- `@takentrade/takentrade-libs` - Main entry point
|
|
806
|
-
- `@takentrade/takentrade-libs/bullmq` - BullMQ module
|
|
807
|
-
- `@takentrade/takentrade-libs/cache` - Cache module
|
|
808
|
-
- `@takentrade/takentrade-libs/common` - Common utilities
|
|
809
|
-
- `@takentrade/takentrade-libs/nats` - NATS utilities
|
|
178
|
+
## License
|
|
810
179
|
|
|
811
|
-
|
|
180
|
+
Proprietary - See [LICENSE](LICENSE) file for details.
|
|
812
181
|
|
|
813
|
-
##
|
|
182
|
+
## Support
|
|
814
183
|
|
|
815
|
-
|
|
184
|
+
For issues or questions, contact the TakeNTrade development team.
|