@fabx.vn/core 1.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/README.md +270 -0
- package/dist/config/cookie.config.d.ts +3 -0
- package/dist/config/cookie.config.js +7 -0
- package/dist/config/cookie.config.js.map +1 -0
- package/dist/config/cors.config.d.ts +6 -0
- package/dist/config/cors.config.js +15 -0
- package/dist/config/cors.config.js.map +1 -0
- package/dist/config/database.config.d.ts +13 -0
- package/dist/config/database.config.js +17 -0
- package/dist/config/database.config.js.map +1 -0
- package/dist/config/google-oauth.config.d.ts +6 -0
- package/dist/config/google-oauth.config.js +10 -0
- package/dist/config/google-oauth.config.js.map +1 -0
- package/dist/config/internal.config.d.ts +8 -0
- package/dist/config/internal.config.js +15 -0
- package/dist/config/internal.config.js.map +1 -0
- package/dist/config/jwt.config.d.ts +5 -0
- package/dist/config/jwt.config.js +9 -0
- package/dist/config/jwt.config.js.map +1 -0
- package/dist/config/rabbitmq.config.d.ts +19 -0
- package/dist/config/rabbitmq.config.js +25 -0
- package/dist/config/rabbitmq.config.js.map +1 -0
- package/dist/config/redis.config.d.ts +9 -0
- package/dist/config/redis.config.js +13 -0
- package/dist/config/redis.config.js.map +1 -0
- package/dist/constants/http-status.constants.d.ts +106 -0
- package/dist/constants/http-status.constants.js +110 -0
- package/dist/constants/http-status.constants.js.map +1 -0
- package/dist/constants/messages.constants.d.ts +112 -0
- package/dist/constants/messages.constants.js +116 -0
- package/dist/constants/messages.constants.js.map +1 -0
- package/dist/core/core.module.d.ts +2 -0
- package/dist/core/core.module.js +72 -0
- package/dist/core/core.module.js.map +1 -0
- package/dist/core/decorators/current-user.decorator.d.ts +1 -0
- package/dist/core/decorators/current-user.decorator.js +9 -0
- package/dist/core/decorators/current-user.decorator.js.map +1 -0
- package/dist/core/decorators/public.decorator.d.ts +2 -0
- package/dist/core/decorators/public.decorator.js +8 -0
- package/dist/core/decorators/public.decorator.js.map +1 -0
- package/dist/core/decorators/require-permissions.decorator.d.ts +4 -0
- package/dist/core/decorators/require-permissions.decorator.js +11 -0
- package/dist/core/decorators/require-permissions.decorator.js.map +1 -0
- package/dist/core/dtos/api-response.dto.d.ts +10 -0
- package/dist/core/dtos/api-response.dto.js +22 -0
- package/dist/core/dtos/api-response.dto.js.map +1 -0
- package/dist/core/dtos/pagination.dto.d.ts +17 -0
- package/dist/core/dtos/pagination.dto.js +61 -0
- package/dist/core/dtos/pagination.dto.js.map +1 -0
- package/dist/core/filters/http-exception.filter.d.ts +5 -0
- package/dist/core/filters/http-exception.filter.js +47 -0
- package/dist/core/filters/http-exception.filter.js.map +1 -0
- package/dist/core/guards/internal-auth.guard.d.ts +7 -0
- package/dist/core/guards/internal-auth.guard.js +42 -0
- package/dist/core/guards/internal-auth.guard.js.map +1 -0
- package/dist/core/guards/jwt-auth.guard.d.ts +12 -0
- package/dist/core/guards/jwt-auth.guard.js +56 -0
- package/dist/core/guards/jwt-auth.guard.js.map +1 -0
- package/dist/core/guards/permission.guard.d.ts +9 -0
- package/dist/core/guards/permission.guard.js +71 -0
- package/dist/core/guards/permission.guard.js.map +1 -0
- package/dist/core/interceptors/request-context.interceptor.d.ts +8 -0
- package/dist/core/interceptors/request-context.interceptor.js +39 -0
- package/dist/core/interceptors/request-context.interceptor.js.map +1 -0
- package/dist/core/services/cache.service.d.ts +13 -0
- package/dist/core/services/cache.service.js +51 -0
- package/dist/core/services/cache.service.js.map +1 -0
- package/dist/core/services/cookie.service.d.ts +13 -0
- package/dist/core/services/cookie.service.js +50 -0
- package/dist/core/services/cookie.service.js.map +1 -0
- package/dist/core/services/jwt.service.d.ts +37 -0
- package/dist/core/services/jwt.service.js +187 -0
- package/dist/core/services/jwt.service.js.map +1 -0
- package/dist/core/services/permission.service.d.ts +23 -0
- package/dist/core/services/permission.service.js +83 -0
- package/dist/core/services/permission.service.js.map +1 -0
- package/dist/core/services/rabbitmq-publisher.service.d.ts +9 -0
- package/dist/core/services/rabbitmq-publisher.service.js +57 -0
- package/dist/core/services/rabbitmq-publisher.service.js.map +1 -0
- package/dist/core/services/redis.service.d.ts +18 -0
- package/dist/core/services/redis.service.js +66 -0
- package/dist/core/services/redis.service.js.map +1 -0
- package/dist/core/services/request-context.service.d.ts +18 -0
- package/dist/core/services/request-context.service.js +40 -0
- package/dist/core/services/request-context.service.js.map +1 -0
- package/dist/core/services/request-info.service.d.ts +8 -0
- package/dist/core/services/request-info.service.js +32 -0
- package/dist/core/services/request-info.service.js.map +1 -0
- package/dist/core/services/session.service.d.ts +21 -0
- package/dist/core/services/session.service.js +70 -0
- package/dist/core/services/session.service.js.map +1 -0
- package/dist/core/strategies/jwt.strategy.d.ts +7 -0
- package/dist/core/strategies/jwt.strategy.js +38 -0
- package/dist/core/strategies/jwt.strategy.js.map +1 -0
- package/dist/core/subscribers/audit.subscriber.d.ts +8 -0
- package/dist/core/subscribers/audit.subscriber.js +40 -0
- package/dist/core/subscribers/audit.subscriber.js.map +1 -0
- package/dist/core.module.d.ts +2 -0
- package/dist/core.module.js +72 -0
- package/dist/core.module.js.map +1 -0
- package/dist/decorators/current-user.decorator.d.ts +1 -0
- package/dist/decorators/current-user.decorator.js +9 -0
- package/dist/decorators/current-user.decorator.js.map +1 -0
- package/dist/decorators/public.decorator.d.ts +2 -0
- package/dist/decorators/public.decorator.js +8 -0
- package/dist/decorators/public.decorator.js.map +1 -0
- package/dist/decorators/require-permissions.decorator.d.ts +4 -0
- package/dist/decorators/require-permissions.decorator.js +11 -0
- package/dist/decorators/require-permissions.decorator.js.map +1 -0
- package/dist/dtos/api-response.dto.d.ts +10 -0
- package/dist/dtos/api-response.dto.js +22 -0
- package/dist/dtos/api-response.dto.js.map +1 -0
- package/dist/dtos/pagination.dto.d.ts +17 -0
- package/dist/dtos/pagination.dto.js +61 -0
- package/dist/dtos/pagination.dto.js.map +1 -0
- package/dist/filters/http-exception.filter.d.ts +5 -0
- package/dist/filters/http-exception.filter.js +47 -0
- package/dist/filters/http-exception.filter.js.map +1 -0
- package/dist/guards/internal-auth.guard.d.ts +7 -0
- package/dist/guards/internal-auth.guard.js +42 -0
- package/dist/guards/internal-auth.guard.js.map +1 -0
- package/dist/guards/jwt-auth.guard.d.ts +12 -0
- package/dist/guards/jwt-auth.guard.js +56 -0
- package/dist/guards/jwt-auth.guard.js.map +1 -0
- package/dist/guards/permission.guard.d.ts +9 -0
- package/dist/guards/permission.guard.js +71 -0
- package/dist/guards/permission.guard.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors/request-context.interceptor.d.ts +8 -0
- package/dist/interceptors/request-context.interceptor.js +39 -0
- package/dist/interceptors/request-context.interceptor.js.map +1 -0
- package/dist/libs/axios/axios-client.d.ts +8 -0
- package/dist/libs/axios/axios-client.js +61 -0
- package/dist/libs/axios/axios-client.js.map +1 -0
- package/dist/libs/axios/index.d.ts +1 -0
- package/dist/libs/axios/index.js +8 -0
- package/dist/libs/axios/index.js.map +1 -0
- package/dist/services/cookie.service.d.ts +13 -0
- package/dist/services/cookie.service.js +50 -0
- package/dist/services/cookie.service.js.map +1 -0
- package/dist/services/jwt.service.d.ts +37 -0
- package/dist/services/jwt.service.js +187 -0
- package/dist/services/jwt.service.js.map +1 -0
- package/dist/services/rabbitmq-publisher.service.d.ts +9 -0
- package/dist/services/rabbitmq-publisher.service.js +57 -0
- package/dist/services/rabbitmq-publisher.service.js.map +1 -0
- package/dist/services/redis.service.d.ts +18 -0
- package/dist/services/redis.service.js +66 -0
- package/dist/services/redis.service.js.map +1 -0
- package/dist/services/request-context.service.d.ts +18 -0
- package/dist/services/request-context.service.js +40 -0
- package/dist/services/request-context.service.js.map +1 -0
- package/dist/services/request-info.service.d.ts +8 -0
- package/dist/services/request-info.service.js +32 -0
- package/dist/services/request-info.service.js.map +1 -0
- package/dist/services/session.service.d.ts +21 -0
- package/dist/services/session.service.js +70 -0
- package/dist/services/session.service.js.map +1 -0
- package/dist/strategies/jwt.strategy.d.ts +7 -0
- package/dist/strategies/jwt.strategy.js +38 -0
- package/dist/strategies/jwt.strategy.js.map +1 -0
- package/dist/subscribers/audit.subscriber.d.ts +8 -0
- package/dist/subscribers/audit.subscriber.js +40 -0
- package/dist/subscribers/audit.subscriber.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils/date.utils.d.ts +4 -0
- package/dist/utils/date.utils.js +52 -0
- package/dist/utils/date.utils.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @package-core
|
|
2
|
+
|
|
3
|
+
Shared core module for all ERP services. Contains reusable core functionality including JWT handling, session management, authentication guards, interceptors, and common utilities.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### 1. Update `tsconfig.json` in your service:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"compilerOptions": {
|
|
12
|
+
"paths": {
|
|
13
|
+
"@package-core": ["../package-core/src"],
|
|
14
|
+
"@package-core/*": ["../package-core/src/*"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Import in your service:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { CoreModule } from "@package-core";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Import CoreModule in AppModule
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { Module } from "@nestjs/common";
|
|
32
|
+
import { CoreModule } from "@package-core";
|
|
33
|
+
|
|
34
|
+
@Module({
|
|
35
|
+
imports: [CoreModule], // @Global() - available everywhere after import
|
|
36
|
+
})
|
|
37
|
+
export class AppModule {}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Use Guards
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { Controller, Get, UseGuards } from "@nestjs/common";
|
|
44
|
+
import {
|
|
45
|
+
JwtAuthGuard,
|
|
46
|
+
CurrentUser,
|
|
47
|
+
CurrentUserDto,
|
|
48
|
+
Public,
|
|
49
|
+
} from "@package-core";
|
|
50
|
+
|
|
51
|
+
@Controller("api")
|
|
52
|
+
export class MyController {
|
|
53
|
+
@Get("public")
|
|
54
|
+
@Public() // Skip authentication
|
|
55
|
+
publicEndpoint() {
|
|
56
|
+
return { message: "Public" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Get("protected")
|
|
60
|
+
@UseGuards(JwtAuthGuard)
|
|
61
|
+
protectedEndpoint(@CurrentUser() user: CurrentUserDto) {
|
|
62
|
+
return user;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Use Permission Guard
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { Controller, Get, UseGuards } from "@nestjs/common";
|
|
71
|
+
import { PermissionGuard, RequirePermissions } from "@package-core";
|
|
72
|
+
|
|
73
|
+
@Controller("admin")
|
|
74
|
+
@UseGuards(PermissionGuard)
|
|
75
|
+
export class AdminController {
|
|
76
|
+
@Get("users")
|
|
77
|
+
@RequirePermissions("user:read", "user:list")
|
|
78
|
+
getUsers() {
|
|
79
|
+
return { users: [] };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Use Services
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { Injectable } from "@nestjs/common";
|
|
88
|
+
import {
|
|
89
|
+
CoreJwtService,
|
|
90
|
+
SessionService,
|
|
91
|
+
CacheService,
|
|
92
|
+
CookieService,
|
|
93
|
+
RabbitMQPublisher,
|
|
94
|
+
RABBITMQ_ROUTING_KEYS,
|
|
95
|
+
} from "@package-core";
|
|
96
|
+
|
|
97
|
+
@Injectable()
|
|
98
|
+
export class MyService {
|
|
99
|
+
constructor(
|
|
100
|
+
private coreJwtService: CoreJwtService,
|
|
101
|
+
private sessionService: SessionService,
|
|
102
|
+
private cacheService: CacheService,
|
|
103
|
+
private rabbitmqPublisher: RabbitMQPublisher
|
|
104
|
+
) {}
|
|
105
|
+
|
|
106
|
+
async createToken(userId: string) {
|
|
107
|
+
return await this.coreJwtService.signToken({ sub: userId });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async setSession(sessionId: string, userData: CurrentUserDto) {
|
|
111
|
+
await this.sessionService.setSession(sessionId, userData);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async cacheData(key: string, value: string, ttl: number = 3600) {
|
|
115
|
+
await this.cacheService.set(key, value, ttl);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async publishEvent(data: any) {
|
|
119
|
+
this.rabbitmqPublisher.publish(
|
|
120
|
+
RABBITMQ_ROUTING_KEYS.AUTH_USER_CREATED,
|
|
121
|
+
data
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 5. Use Constants
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { MESSAGES, ERROR_MESSAGES, SUCCESS_MESSAGES } from "@package-core";
|
|
131
|
+
import { BadRequestException } from "@nestjs/common";
|
|
132
|
+
|
|
133
|
+
throw new BadRequestException(MESSAGES.AUTH.INVALID_CREDENTIALS);
|
|
134
|
+
throw new BadRequestException(MESSAGES.VALIDATION.EMAIL_REQUIRED);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Available Exports
|
|
138
|
+
|
|
139
|
+
### Core Module
|
|
140
|
+
|
|
141
|
+
- **`CoreModule`** - Main module (marked as `@Global()`)
|
|
142
|
+
|
|
143
|
+
### Services
|
|
144
|
+
|
|
145
|
+
- **`CoreJwtService`** - JWT token creation, validation, session management
|
|
146
|
+
- **`SessionService`** - Redis-based session management
|
|
147
|
+
- **`CacheService`** - Redis cache operations
|
|
148
|
+
- **`CookieService`** - Cookie handling for authentication tokens
|
|
149
|
+
- **`RabbitMQPublisher`** - RabbitMQ message publishing
|
|
150
|
+
- **`RequestContextService`** - Request context management (AsyncLocalStorage)
|
|
151
|
+
- **`RequestInfoService`** - Extract request information (IP, user agent)
|
|
152
|
+
|
|
153
|
+
### Guards
|
|
154
|
+
|
|
155
|
+
- **`JwtAuthGuard`** - JWT authentication guard (extracts token from cookies)
|
|
156
|
+
- **`InternalAuthGuard`** - Internal service-to-service authentication
|
|
157
|
+
- **`PermissionGuard`** - Permission-based access control
|
|
158
|
+
|
|
159
|
+
### Decorators
|
|
160
|
+
|
|
161
|
+
- **`@CurrentUser()`** - Extract current user from request
|
|
162
|
+
- **`@Public()`** - Mark route as public (skip authentication)
|
|
163
|
+
- **`@RequirePermissions(...permissions)`** - Require ALL specified permissions
|
|
164
|
+
- **`@RequireAnyPermission(...permissions)`** - Require ANY of specified permissions
|
|
165
|
+
|
|
166
|
+
### DTOs & Types
|
|
167
|
+
|
|
168
|
+
- **`CurrentUserDto`** - Current user data structure
|
|
169
|
+
- **`ApiResponseDto<T>`** - Standardized API response
|
|
170
|
+
- **`PaginationDto`** - Pagination query parameters
|
|
171
|
+
- **`PaginationResponseDto<T>`** - Paginated response structure
|
|
172
|
+
- **`JwtTokenData`** - JWT token payload structure
|
|
173
|
+
- **`JwtValidationResult`** - JWT validation result
|
|
174
|
+
|
|
175
|
+
### Filters & Interceptors
|
|
176
|
+
|
|
177
|
+
- **`HttpExceptionFilter`** - Global exception filter
|
|
178
|
+
- **`RequestContextInterceptor`** - Request context interceptor (auto-registered)
|
|
179
|
+
|
|
180
|
+
### Config
|
|
181
|
+
|
|
182
|
+
- **`jwtConfig`** - JWT configuration
|
|
183
|
+
- **`redisConfig`** - Redis configuration
|
|
184
|
+
- **`rabbitmqConfig`** - RabbitMQ configuration
|
|
185
|
+
- **`RABBITMQ_ROUTING_KEYS`** - RabbitMQ routing keys constants
|
|
186
|
+
- **`cookieConfig`** - Cookie configuration
|
|
187
|
+
- **`internalConfig`** - Internal service configuration
|
|
188
|
+
- **`corsConfig`** - CORS configuration
|
|
189
|
+
- **`googleOAuthConfig`** - Google OAuth configuration
|
|
190
|
+
|
|
191
|
+
### Constants
|
|
192
|
+
|
|
193
|
+
- **`MESSAGES`** - Vietnamese user-facing messages (AUTH, VALIDATION, etc.)
|
|
194
|
+
- **`ERROR_MESSAGES`** - Error message constants
|
|
195
|
+
- **`SUCCESS_MESSAGES`** - Success message constants
|
|
196
|
+
|
|
197
|
+
### Utils & Libs
|
|
198
|
+
|
|
199
|
+
- **`DateUtils`** - Date utility functions
|
|
200
|
+
- **`AxiosClient`**, **`apiClient`**, **`createServiceClient`** - Axios client utilities
|
|
201
|
+
|
|
202
|
+
## Environment Variables
|
|
203
|
+
|
|
204
|
+
```env
|
|
205
|
+
# JWT
|
|
206
|
+
JWT_SECRET=your-jwt-secret
|
|
207
|
+
JWT_EXPIRES_IN=15m
|
|
208
|
+
JWT_REFRESH_EXPIRES_IN=7d
|
|
209
|
+
JWT_SESSION_EXPIRES_IN=24h
|
|
210
|
+
|
|
211
|
+
# Redis
|
|
212
|
+
SHARED_REDIS_HOST=localhost
|
|
213
|
+
SHARED_REDIS_PORT=6379
|
|
214
|
+
SHARED_REDIS_PASSWORD=
|
|
215
|
+
SHARED_REDIS_DB=0
|
|
216
|
+
|
|
217
|
+
# RabbitMQ
|
|
218
|
+
RABBITMQ_HOST=rabbitmq
|
|
219
|
+
RABBITMQ_PORT=5672
|
|
220
|
+
RABBITMQ_USER=admin
|
|
221
|
+
RABBITMQ_PASSWORD=admin123
|
|
222
|
+
RABBITMQ_VHOST=/erp
|
|
223
|
+
RABBITMQ_EVENTS_EXCHANGE=events_exchange
|
|
224
|
+
|
|
225
|
+
# Cookie
|
|
226
|
+
AUTH_COOKIE_NAME=auth_tokens
|
|
227
|
+
|
|
228
|
+
# Internal Service
|
|
229
|
+
INTERNAL_SECRET=internal-secret
|
|
230
|
+
USER_MANAGEMENT_SERVICE_URL=http://service-user-management:3002
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Package Structure
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
package-core/
|
|
237
|
+
├── src/
|
|
238
|
+
│ ├── index.ts # Main export file
|
|
239
|
+
│ ├── core/
|
|
240
|
+
│ │ ├── core.module.ts # Core module
|
|
241
|
+
│ │ ├── services/ # 7 services
|
|
242
|
+
│ │ ├── guards/ # 3 guards
|
|
243
|
+
│ │ ├── decorators/ # 3 decorators
|
|
244
|
+
│ │ ├── dtos/ # 2 DTOs
|
|
245
|
+
│ │ ├── filters/ # 1 filter
|
|
246
|
+
│ │ ├── interceptors/ # 1 interceptor
|
|
247
|
+
│ │ ├── strategies/ # 1 strategy
|
|
248
|
+
│ │ └── subscribers/ # 1 subscriber
|
|
249
|
+
│ ├── config/ # 8 config files
|
|
250
|
+
│ ├── constants/ # 2 constant files
|
|
251
|
+
│ ├── utils/ # 1 util file
|
|
252
|
+
│ └── libs/ # 1 lib (axios)
|
|
253
|
+
├── package.json
|
|
254
|
+
├── tsconfig.json
|
|
255
|
+
└── README.md
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Building
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
cd package-core
|
|
262
|
+
npm run build
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Notes
|
|
266
|
+
|
|
267
|
+
- **Global Module**: `CoreModule` is marked as `@Global()`, import once in `AppModule` and use everywhere
|
|
268
|
+
- **Request Context**: `RequestContextInterceptor` is auto-registered via `APP_INTERCEPTOR`
|
|
269
|
+
- **Internal Imports**: Package uses alias imports internally (`@core`, `@config`, `@constants`, etc.)
|
|
270
|
+
- **Type Safety**: All exports are fully typed with TypeScript
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie.config.js","sourceRoot":"","sources":["../../src/config/cookie.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG;IAC1B,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,aAAa;CAC1D,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.corsConfig = void 0;
|
|
4
|
+
exports.corsConfig = {
|
|
5
|
+
origin: process.env.CORS_ORIGIN || "*",
|
|
6
|
+
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
7
|
+
allowedHeaders: [
|
|
8
|
+
"Content-Type",
|
|
9
|
+
"Authorization",
|
|
10
|
+
"Accept",
|
|
11
|
+
"X-Requested-With",
|
|
12
|
+
],
|
|
13
|
+
credentials: true,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=cors.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.config.js","sourceRoot":"","sources":["../../src/config/cors.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG;IACxB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG;IACtC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;IAC7D,cAAc,EAAE;QACd,cAAc;QACd,eAAe;QACf,QAAQ;QACR,kBAAkB;KACnB;IACD,WAAW,EAAE,IAAI;CAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const databaseConfig: {
|
|
2
|
+
type: "mysql";
|
|
3
|
+
host: string;
|
|
4
|
+
port: number;
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
database: string;
|
|
8
|
+
entities: string[];
|
|
9
|
+
logging: boolean;
|
|
10
|
+
synchronize: boolean;
|
|
11
|
+
autoLoadEntities: boolean;
|
|
12
|
+
timezone: string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.databaseConfig = void 0;
|
|
4
|
+
exports.databaseConfig = {
|
|
5
|
+
type: "mysql",
|
|
6
|
+
host: process.env.MYSQL_HOST || "localhost",
|
|
7
|
+
port: parseInt(process.env.MYSQL_PORT || "3306"),
|
|
8
|
+
username: process.env.MYSQL_USER || "service_user",
|
|
9
|
+
password: process.env.MYSQL_PASSWORD || "service_pass",
|
|
10
|
+
database: process.env.MYSQL_DATABASE || "service_db",
|
|
11
|
+
entities: [__dirname + "/../modules/**/*.entity{.ts,.js}"],
|
|
12
|
+
logging: process.env.NODE_ENV === "development",
|
|
13
|
+
synchronize: true,
|
|
14
|
+
autoLoadEntities: true,
|
|
15
|
+
timezone: "+07:00",
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=database.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.config.js","sourceRoot":"","sources":["../../src/config/database.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG;IAC5B,IAAI,EAAE,OAAgB;IACtB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;IAC3C,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC;IAChD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,cAAc;IAClD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,cAAc;IACtD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,YAAY;IACpD,QAAQ,EAAE,CAAC,SAAS,GAAG,kCAAkC,CAAC;IAC1D,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;IAC/C,WAAW,EAAE,IAAI;IACjB,gBAAgB,EAAE,IAAI;IACtB,QAAQ,EAAE,QAAQ;CACnB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.googleOAuthConfig = void 0;
|
|
4
|
+
exports.googleOAuthConfig = {
|
|
5
|
+
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
6
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
7
|
+
callbackUrl: process.env.GOOGLE_CALLBACK_URL || "/auth/google/callback",
|
|
8
|
+
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000",
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=google-oauth.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-oauth.config.js","sourceRoot":"","sources":["../../src/config/google-oauth.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG;IAC/B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;IACtC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;IAC9C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,uBAAuB;IACvE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB;CACjE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.internalConfig = void 0;
|
|
4
|
+
exports.internalConfig = {
|
|
5
|
+
authServiceUrl: process.env.AUTH_SERVICE_URL || "http://service-auth:3001",
|
|
6
|
+
userManagementServiceUrl: process.env.USER_MANAGEMENT_SERVICE_URL ||
|
|
7
|
+
"http://service-user-management:3002",
|
|
8
|
+
communicationServiceUrl: process.env.COMMUNICATION_SERVICE_URL ||
|
|
9
|
+
"http://service-communication:3003",
|
|
10
|
+
mediaServiceUrl: process.env.MEDIA_SERVICE_URL || "http://service-media:3004",
|
|
11
|
+
phuCuongPlusServiceUrl: process.env.PHU_CUONG_PLUS_SERVICE_URL ||
|
|
12
|
+
"http://service-phu-cuong-plus:3005",
|
|
13
|
+
internalSecret: process.env.INTERNAL_SECRET || "internal-secret",
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=internal.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.config.js","sourceRoot":"","sources":["../../src/config/internal.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG;IAC5B,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,0BAA0B;IAC1E,wBAAwB,EACtB,OAAO,CAAC,GAAG,CAAC,2BAA2B;QACvC,qCAAqC;IACvC,uBAAuB,EACrB,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACrC,mCAAmC;IACrC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,2BAA2B;IAC7E,sBAAsB,EACpB,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACtC,oCAAoC;IACtC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,iBAAiB;CACjE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jwtConfig = void 0;
|
|
4
|
+
exports.jwtConfig = {
|
|
5
|
+
secret: process.env.JWT_SECRET || "your_jwt_secret_key_here",
|
|
6
|
+
expiresIn: process.env.JWT_EXPIRES_IN || "15m",
|
|
7
|
+
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || "7d",
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=jwt.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.config.js","sourceRoot":"","sources":["../../src/config/jwt.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG;IACvB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,0BAA0B;IAC5D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK;IAC9C,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,IAAI;CAC7D,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const rabbitmqConfig: {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
user: string;
|
|
5
|
+
password: string;
|
|
6
|
+
vhost: string;
|
|
7
|
+
authQueue: string;
|
|
8
|
+
userMgmtQueue: string;
|
|
9
|
+
communicationQueue: string;
|
|
10
|
+
mediaQueue: string;
|
|
11
|
+
phuCuongPlusQueue: string;
|
|
12
|
+
eventsExchange: string;
|
|
13
|
+
readonly url: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const RABBITMQ_ROUTING_KEYS: {
|
|
16
|
+
readonly USER_EMAIL_VERIFICATION: "user.email.verification";
|
|
17
|
+
readonly AUTH_USER_CREATED: "auth.user.created";
|
|
18
|
+
readonly USER_PASSWORD_RESET: "user.password.reset";
|
|
19
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RABBITMQ_ROUTING_KEYS = exports.rabbitmqConfig = void 0;
|
|
4
|
+
exports.rabbitmqConfig = {
|
|
5
|
+
host: process.env.RABBITMQ_HOST || "rabbitmq",
|
|
6
|
+
port: parseInt(process.env.RABBITMQ_PORT, 10) || 5672,
|
|
7
|
+
user: process.env.RABBITMQ_USER || "admin",
|
|
8
|
+
password: process.env.RABBITMQ_PASSWORD || "admin123",
|
|
9
|
+
vhost: process.env.RABBITMQ_VHOST || "/erp",
|
|
10
|
+
authQueue: process.env.AUTH_QUEUE || "auth_queue",
|
|
11
|
+
userMgmtQueue: process.env.USER_MGMT_QUEUE || "user_mgmt_queue",
|
|
12
|
+
communicationQueue: process.env.COMMUNICATION_QUEUE || "communication_queue",
|
|
13
|
+
mediaQueue: process.env.MEDIA_QUEUE || "media_queue",
|
|
14
|
+
phuCuongPlusQueue: process.env.PHU_CUONG_PLUS_QUEUE || "phu_cuong_plus_queue",
|
|
15
|
+
eventsExchange: process.env.RABBITMQ_EVENTS_EXCHANGE || "events_exchange",
|
|
16
|
+
get url() {
|
|
17
|
+
return `amqp://${this.user}:${this.password}@${this.host}:${this.port}/${encodeURIComponent(this.vhost)}`;
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
exports.RABBITMQ_ROUTING_KEYS = {
|
|
21
|
+
USER_EMAIL_VERIFICATION: "user.email.verification",
|
|
22
|
+
AUTH_USER_CREATED: "auth.user.created",
|
|
23
|
+
USER_PASSWORD_RESET: "user.password.reset",
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=rabbitmq.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq.config.js","sourceRoot":"","sources":["../../src/config/rabbitmq.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU;IAC7C,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,IAAI,IAAI;IACrD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;IAC1C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,UAAU;IACrD,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM;IAC3C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,YAAY;IACjD,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,iBAAiB;IAC/D,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,qBAAqB;IAC5E,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,aAAa;IACpD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,sBAAsB;IAC7E,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,iBAAiB;IACzE,IAAI,GAAG;QACL,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,IACtD,IAAI,CAAC,IACP,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACvC,CAAC;CACF,CAAC;AAMW,QAAA,qBAAqB,GAAG;IAKnC,uBAAuB,EAAE,yBAAyB;IAMlD,iBAAiB,EAAE,mBAAmB;IAMtC,mBAAmB,EAAE,qBAAqB;CAClC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redisConfig = void 0;
|
|
4
|
+
exports.redisConfig = {
|
|
5
|
+
host: process.env.SHARED_REDIS_HOST || "localhost",
|
|
6
|
+
port: parseInt(process.env.SHARED_REDIS_PORT || "6379"),
|
|
7
|
+
password: process.env.SHARED_REDIS_PASSWORD || undefined,
|
|
8
|
+
db: parseInt(process.env.SHARED_REDIS_DB || "0"),
|
|
9
|
+
retryDelayOnFailover: 100,
|
|
10
|
+
enableReadyCheck: false,
|
|
11
|
+
maxRetriesPerRequest: null,
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=redis.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.config.js","sourceRoot":"","sources":["../../src/config/redis.config.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,WAAW;IAClD,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,CAAC;IACvD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,SAAS;IACxD,EAAE,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC;IAChD,oBAAoB,EAAE,GAAG;IACzB,gBAAgB,EAAE,KAAK;IACvB,oBAAoB,EAAE,IAAI;CAC3B,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { HttpStatus } from "@nestjs/common";
|
|
2
|
+
export declare const ERROR_MESSAGES: {
|
|
3
|
+
readonly EMAIL_ALREADY_EXISTS: "Email đã tồn tại";
|
|
4
|
+
readonly USER_NOT_FOUND: "Không tìm thấy người dùng";
|
|
5
|
+
readonly INVALID_CREDENTIALS: "Thông tin đăng nhập không hợp lệ";
|
|
6
|
+
readonly USER_ALREADY_ACTIVE: "Người dùng đã được kích hoạt";
|
|
7
|
+
readonly USER_ALREADY_INACTIVE: "Người dùng đã bị vô hiệu hóa";
|
|
8
|
+
readonly VALIDATION_ERROR: "Xác thực thất bại";
|
|
9
|
+
readonly UNAUTHORIZED_ACCESS: "Không có quyền truy cập";
|
|
10
|
+
readonly FORBIDDEN_ACCESS: "Truy cập bị cấm";
|
|
11
|
+
readonly RESOURCE_NOT_FOUND: "Không tìm thấy tài nguyên";
|
|
12
|
+
readonly INTERNAL_ERROR: "Lỗi máy chủ nội bộ";
|
|
13
|
+
readonly DUPLICATE_ENTRY: "Bản ghi đã tồn tại";
|
|
14
|
+
};
|
|
15
|
+
export declare const ERROR_RESPONSES: {
|
|
16
|
+
readonly EMAIL_CONFLICT: {
|
|
17
|
+
readonly status: HttpStatus.CONFLICT;
|
|
18
|
+
readonly description: "Email đã tồn tại";
|
|
19
|
+
};
|
|
20
|
+
readonly USER_NOT_FOUND: {
|
|
21
|
+
readonly status: HttpStatus.NOT_FOUND;
|
|
22
|
+
readonly description: "Không tìm thấy người dùng";
|
|
23
|
+
};
|
|
24
|
+
readonly INVALID_CREDENTIALS: {
|
|
25
|
+
readonly status: HttpStatus.UNAUTHORIZED;
|
|
26
|
+
readonly description: "Thông tin đăng nhập không hợp lệ";
|
|
27
|
+
};
|
|
28
|
+
readonly VALIDATION_ERROR: {
|
|
29
|
+
readonly status: HttpStatus.BAD_REQUEST;
|
|
30
|
+
readonly description: "Xác thực thất bại";
|
|
31
|
+
};
|
|
32
|
+
readonly UNAUTHORIZED: {
|
|
33
|
+
readonly status: HttpStatus.UNAUTHORIZED;
|
|
34
|
+
readonly description: "Không có quyền truy cập";
|
|
35
|
+
};
|
|
36
|
+
readonly FORBIDDEN: {
|
|
37
|
+
readonly status: HttpStatus.FORBIDDEN;
|
|
38
|
+
readonly description: "Truy cập bị cấm";
|
|
39
|
+
};
|
|
40
|
+
readonly NOT_FOUND: {
|
|
41
|
+
readonly status: HttpStatus.NOT_FOUND;
|
|
42
|
+
readonly description: "Không tìm thấy tài nguyên";
|
|
43
|
+
};
|
|
44
|
+
readonly INTERNAL_ERROR: {
|
|
45
|
+
readonly status: HttpStatus.INTERNAL_SERVER_ERROR;
|
|
46
|
+
readonly description: "Lỗi máy chủ nội bộ";
|
|
47
|
+
};
|
|
48
|
+
readonly DUPLICATE_ENTRY: {
|
|
49
|
+
readonly status: HttpStatus.CONFLICT;
|
|
50
|
+
readonly description: "Bản ghi đã tồn tại";
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export declare const SUCCESS_MESSAGES: {
|
|
54
|
+
readonly CREATED_SUCCESSFULLY: "Tạo bản ghi thành công";
|
|
55
|
+
readonly RETRIEVED_SUCCESSFULLY: "Lấy danh sách bản ghi thành công";
|
|
56
|
+
readonly UPDATED_SUCCESSFULLY: "Cập nhật bản ghi thành công";
|
|
57
|
+
readonly DELETED_SUCCESSFULLY: "Xóa bản ghi thành công";
|
|
58
|
+
readonly LOGIN_SUCCESSFUL: "Đăng nhập thành công";
|
|
59
|
+
readonly REGISTERED_SUCCESSFULLY: "Đăng ký người dùng thành công";
|
|
60
|
+
readonly PROFILE_RETRIEVED: "Lấy thông tin người dùng thành công";
|
|
61
|
+
readonly TOKEN_REFRESHED: "Làm mới token thành công";
|
|
62
|
+
readonly EXISTENCE_CHECK: "Kết quả kiểm tra sự tồn tại";
|
|
63
|
+
readonly TOTAL_COUNT: "Tổng số lượng";
|
|
64
|
+
};
|
|
65
|
+
export declare const SUCCESS_RESPONSES: {
|
|
66
|
+
readonly CREATED: {
|
|
67
|
+
readonly status: HttpStatus.CREATED;
|
|
68
|
+
readonly description: "Tạo bản ghi thành công";
|
|
69
|
+
};
|
|
70
|
+
readonly OK: {
|
|
71
|
+
readonly status: HttpStatus.OK;
|
|
72
|
+
readonly description: "Lấy danh sách bản ghi thành công";
|
|
73
|
+
};
|
|
74
|
+
readonly UPDATED: {
|
|
75
|
+
readonly status: HttpStatus.OK;
|
|
76
|
+
readonly description: "Cập nhật bản ghi thành công";
|
|
77
|
+
};
|
|
78
|
+
readonly DELETED: {
|
|
79
|
+
readonly status: HttpStatus.NO_CONTENT;
|
|
80
|
+
readonly description: "Xóa bản ghi thành công";
|
|
81
|
+
};
|
|
82
|
+
readonly LOGIN_SUCCESS: {
|
|
83
|
+
readonly status: HttpStatus.OK;
|
|
84
|
+
readonly description: "Đăng nhập thành công";
|
|
85
|
+
};
|
|
86
|
+
readonly REGISTER_SUCCESS: {
|
|
87
|
+
readonly status: HttpStatus.CREATED;
|
|
88
|
+
readonly description: "Đăng ký người dùng thành công";
|
|
89
|
+
};
|
|
90
|
+
readonly PROFILE_SUCCESS: {
|
|
91
|
+
readonly status: HttpStatus.OK;
|
|
92
|
+
readonly description: "Lấy thông tin người dùng thành công";
|
|
93
|
+
};
|
|
94
|
+
readonly TOKEN_SUCCESS: {
|
|
95
|
+
readonly status: HttpStatus.OK;
|
|
96
|
+
readonly description: "Làm mới token thành công";
|
|
97
|
+
};
|
|
98
|
+
readonly EXISTS_CHECK: {
|
|
99
|
+
readonly status: HttpStatus.OK;
|
|
100
|
+
readonly description: "Kết quả kiểm tra sự tồn tại";
|
|
101
|
+
};
|
|
102
|
+
readonly COUNT_SUCCESS: {
|
|
103
|
+
readonly status: HttpStatus.OK;
|
|
104
|
+
readonly description: "Tổng số lượng";
|
|
105
|
+
};
|
|
106
|
+
};
|