@ticatec/common-express-server 0.0.8 → 0.1.3
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 +491 -0
- package/lib/AppConf.d.ts +31 -0
- package/lib/AppConf.js +57 -0
- package/lib/AppConf.js.map +1 -0
- package/lib/BaseServer.d.ts +72 -26
- package/lib/BaseServer.js +52 -24
- package/lib/BaseServer.js.map +1 -1
- package/lib/CommonRouterHelper.d.ts +45 -22
- package/lib/CommonRouterHelper.js +52 -22
- package/lib/CommonRouterHelper.js.map +1 -1
- package/lib/CommonRoutes.d.ts +21 -3
- package/lib/CommonRoutes.js +16 -1
- package/lib/CommonRoutes.js.map +1 -1
- package/lib/LoggedUser.d.ts +11 -15
- package/lib/common/AdminBaseController.d.ts +14 -10
- package/lib/common/AdminBaseController.js +11 -8
- package/lib/common/AdminBaseController.js.map +1 -1
- package/lib/common/AdminSearchController.d.ts +6 -1
- package/lib/common/AdminSearchController.js +7 -2
- package/lib/common/AdminSearchController.js.map +1 -1
- package/lib/common/BaseController.d.ts +18 -2
- package/lib/common/BaseController.js +18 -3
- package/lib/common/BaseController.js.map +1 -1
- package/lib/common/CommonController.d.ts +49 -25
- package/lib/common/CommonController.js +42 -23
- package/lib/common/CommonController.js.map +1 -1
- package/lib/common/TenantBaseController.d.ts +16 -11
- package/lib/common/TenantBaseController.js +14 -13
- package/lib/common/TenantBaseController.js.map +1 -1
- package/lib/common/TenantSearchController.d.ts +6 -1
- package/lib/common/TenantSearchController.js +7 -2
- package/lib/common/TenantSearchController.js.map +1 -1
- package/lib/index.d.ts +14 -0
- package/lib/index.js +30 -0
- package/lib/index.js.map +1 -0
- package/package.json +54 -14
- package/.idea/common-express-server.iml +0 -9
- package/.idea/inspectionProfiles/Project_Default.xml +0 -11
- package/.idea/misc.xml +0 -5
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/tsconfig.json +0 -13
package/README.md
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
# @ticatec/common-express-server
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/@ticatec%2Fcommon-express-server)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A comprehensive TypeScript library providing common classes, controllers, and middleware for building scalable Express.js applications with multi-tenant support.
|
|
7
|
+
|
|
8
|
+
[中文](./README_CN.md) | English
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🚀 **Express.js Foundation**: Built on Express.js 5.x with full TypeScript support
|
|
13
|
+
- 🏢 **Multi-tenant Architecture**: Built-in support for multi-tenant applications
|
|
14
|
+
- 🔐 **Authentication & Authorization**: User authentication and role-based access control
|
|
15
|
+
- 🎯 **Controller Patterns**: Pre-built base controllers for common CRUD operations
|
|
16
|
+
- 📝 **Validation**: Integrated data validation using bean-validator
|
|
17
|
+
- 🔄 **Error Handling**: Centralized error handling and logging
|
|
18
|
+
- 🌐 **Internationalization**: Built-in language support via headers
|
|
19
|
+
- 📊 **Logging**: Structured logging with log4js integration
|
|
20
|
+
- 🎨 **TypeScript First**: Full TypeScript support with comprehensive type definitions
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @ticatec/common-express-server
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Peer Dependencies
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install express@^5.1.0
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
### 1. Create a Basic Server
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { BaseServer, CommonRouterHelper } from '@ticatec/common-express-server';
|
|
40
|
+
|
|
41
|
+
class MyRouterHelper extends CommonRouterHelper {
|
|
42
|
+
// Add custom middleware or override methods as needed
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class MyServer extends BaseServer<MyRouterHelper> {
|
|
46
|
+
protected getHelper(): MyRouterHelper {
|
|
47
|
+
return new MyRouterHelper();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected async loadConfigFile(): Promise<void> {
|
|
51
|
+
// Load your configuration here
|
|
52
|
+
console.log('Loading configuration...');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected getWebConf() {
|
|
56
|
+
return {
|
|
57
|
+
port: 3000,
|
|
58
|
+
ip: '0.0.0.0',
|
|
59
|
+
contextRoot: '/api'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
protected async setupRoutes(app: Express): Promise<void> {
|
|
64
|
+
// Set up your routes here
|
|
65
|
+
await this.bindRoutes(app, '/users', () => import('./routes/UserRoutes'));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Start the server
|
|
70
|
+
const server = new MyServer();
|
|
71
|
+
BaseServer.startup(server);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Create Routes
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { CommonRoutes, CommonRouterHelper } from '@ticatec/common-express-server';
|
|
78
|
+
|
|
79
|
+
class UserRoutes extends CommonRoutes<CommonRouterHelper> {
|
|
80
|
+
constructor(helper: CommonRouterHelper) {
|
|
81
|
+
super(helper); // checkUser = true by default
|
|
82
|
+
this.setupRoutes();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private setupRoutes() {
|
|
86
|
+
this.router.get('/profile', this.helper.invokeRestfulAction(this.getProfile));
|
|
87
|
+
this.router.post('/update', this.helper.invokeRestfulAction(this.updateProfile));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private getProfile = async (req: Request) => {
|
|
91
|
+
// Your logic here
|
|
92
|
+
return { message: 'User profile' };
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
private updateProfile = async (req: Request) => {
|
|
96
|
+
// Your logic here
|
|
97
|
+
return { message: 'Profile updated' };
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default UserRoutes;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 3. Create Controllers
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { TenantBaseController } from '@ticatec/common-express-server';
|
|
108
|
+
import { ValidationRules, StringValidator } from '@ticatec/bean-validator';
|
|
109
|
+
|
|
110
|
+
interface UserService {
|
|
111
|
+
createNew(user: any, data: any): Promise<any>;
|
|
112
|
+
update(user: any, data: any): Promise<any>;
|
|
113
|
+
search(user: any, query: any): Promise<any>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const userValidationRules: ValidationRules = [
|
|
117
|
+
new StringValidator('name', { required: true, minLen: 2 }),
|
|
118
|
+
new StringValidator('email', {
|
|
119
|
+
required: true,
|
|
120
|
+
format: {
|
|
121
|
+
regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
122
|
+
message: 'Invalid email format'
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
class UserController extends TenantBaseController<UserService> {
|
|
128
|
+
constructor(userService: UserService) {
|
|
129
|
+
super(userService, userValidationRules);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// CRUD methods are inherited and automatically validated
|
|
133
|
+
// createNew(), update(), del() are available
|
|
134
|
+
|
|
135
|
+
// Add custom methods
|
|
136
|
+
search() {
|
|
137
|
+
return async (req: Request): Promise<any> => {
|
|
138
|
+
const query = req.query;
|
|
139
|
+
this.checkInterface('search');
|
|
140
|
+
return await this.invokeServiceInterface('search', [
|
|
141
|
+
this.getLoggedUser(req),
|
|
142
|
+
query
|
|
143
|
+
]);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Core Classes
|
|
150
|
+
|
|
151
|
+
### BaseServer<T>
|
|
152
|
+
|
|
153
|
+
Abstract base server class that provides:
|
|
154
|
+
- Express application setup
|
|
155
|
+
- Configuration loading
|
|
156
|
+
- Route binding
|
|
157
|
+
- Error handling
|
|
158
|
+
- Health check endpoint
|
|
159
|
+
- Static file serving
|
|
160
|
+
|
|
161
|
+
### CommonRouterHelper
|
|
162
|
+
|
|
163
|
+
Middleware utilities for:
|
|
164
|
+
- JSON response formatting
|
|
165
|
+
- Cache control
|
|
166
|
+
- User authentication
|
|
167
|
+
- Error handling
|
|
168
|
+
- Request logging
|
|
169
|
+
|
|
170
|
+
### CommonRoutes<T>
|
|
171
|
+
|
|
172
|
+
Base class for route definitions with:
|
|
173
|
+
- Express router integration
|
|
174
|
+
- User authentication checks
|
|
175
|
+
- Logging capabilities
|
|
176
|
+
|
|
177
|
+
### Controllers Hierarchy
|
|
178
|
+
|
|
179
|
+
- **BaseController<T>**: Basic controller with logging and user context
|
|
180
|
+
- **CommonController<T>**: CRUD operations with validation
|
|
181
|
+
- **AdminBaseController<T>**: Admin-specific operations (tenant-independent)
|
|
182
|
+
- **TenantBaseController<T>**: Tenant-specific operations
|
|
183
|
+
- **AdminSearchController<T>**: Admin search operations
|
|
184
|
+
- **TenantSearchController<T>**: Tenant search operations
|
|
185
|
+
|
|
186
|
+
## Configuration
|
|
187
|
+
|
|
188
|
+
### Application Configuration
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { AppConf } from '@ticatec/common-express-server';
|
|
192
|
+
|
|
193
|
+
// Initialize configuration
|
|
194
|
+
AppConf.init({
|
|
195
|
+
database: {
|
|
196
|
+
host: 'localhost',
|
|
197
|
+
port: 5432
|
|
198
|
+
},
|
|
199
|
+
server: {
|
|
200
|
+
port: 3000
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Use configuration
|
|
205
|
+
const config = AppConf.getInstance();
|
|
206
|
+
const dbHost = config.get('database.host');
|
|
207
|
+
const serverPort = config.get('server.port');
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Gateway Architecture
|
|
211
|
+
|
|
212
|
+
This application is designed to work behind an API Gateway. The gateway handles JWT tokens or session-based authentication and forwards the authenticated user information to the Express application via HTTP headers.
|
|
213
|
+
|
|
214
|
+
#### Architecture Flow
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
Client Request (JWT/Session) → API Gateway → Express Application
|
|
218
|
+
↓
|
|
219
|
+
User Info Headers
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Gateway Responsibilities
|
|
223
|
+
|
|
224
|
+
The API Gateway should:
|
|
225
|
+
|
|
226
|
+
1. **Authenticate requests** using JWT tokens, session cookies, or other authentication mechanisms
|
|
227
|
+
2. **Extract user information** from the authentication token/session
|
|
228
|
+
3. **Forward user data** as HTTP headers to the Express application
|
|
229
|
+
4. **Handle authorization** and rate limiting as needed
|
|
230
|
+
|
|
231
|
+
#### User Authentication Headers
|
|
232
|
+
|
|
233
|
+
The library expects user information in the request headers:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// Headers forwarded by the gateway
|
|
237
|
+
{
|
|
238
|
+
'user': encodeURIComponent(JSON.stringify({
|
|
239
|
+
accountCode: 'user123',
|
|
240
|
+
name: 'John Doe',
|
|
241
|
+
tenant: { code: 'tenant1', name: 'Tenant One' }
|
|
242
|
+
})),
|
|
243
|
+
'x-language': 'en'
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Gateway Implementation Example
|
|
248
|
+
|
|
249
|
+
Here's an example of how the gateway might process authentication:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// Gateway middleware (pseudo-code)
|
|
253
|
+
async function processAuthentication(request) {
|
|
254
|
+
// 1. Validate JWT token or session
|
|
255
|
+
const token = request.headers.authorization?.replace('Bearer ', '');
|
|
256
|
+
const userInfo = await validateJWT(token);
|
|
257
|
+
|
|
258
|
+
// 2. Extract user information
|
|
259
|
+
const user = {
|
|
260
|
+
accountCode: userInfo.sub,
|
|
261
|
+
name: userInfo.name,
|
|
262
|
+
tenant: {
|
|
263
|
+
code: userInfo.tenant_code,
|
|
264
|
+
name: userInfo.tenant_name
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// 3. Forward to Express app with user header
|
|
269
|
+
request.headers['user'] = encodeURIComponent(JSON.stringify(user));
|
|
270
|
+
request.headers['x-language'] = userInfo.preferred_language || 'en';
|
|
271
|
+
|
|
272
|
+
// 4. Proxy request to Express application
|
|
273
|
+
return proxyToExpressApp(request);
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### Security Considerations
|
|
278
|
+
|
|
279
|
+
- **No direct authentication**: This Express application does NOT handle JWT validation or session management
|
|
280
|
+
- **Trust boundary**: The application trusts that the gateway has properly authenticated users
|
|
281
|
+
- **Header validation**: User headers are parsed and validated but not authenticated
|
|
282
|
+
- **Network security**: Ensure secure communication between gateway and Express app (internal network/VPN)
|
|
283
|
+
|
|
284
|
+
### User Impersonation
|
|
285
|
+
|
|
286
|
+
The library supports user impersonation, which allows privileged system users to act as another user (including cross-tenant operations) for debugging and troubleshooting purposes.
|
|
287
|
+
|
|
288
|
+
#### How It Works
|
|
289
|
+
|
|
290
|
+
When a privileged user needs to impersonate another user, the gateway should include both the original user and the target user in the headers:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// Headers with user impersonation
|
|
294
|
+
{
|
|
295
|
+
'user': encodeURIComponent(JSON.stringify({
|
|
296
|
+
// Original privileged user
|
|
297
|
+
accountCode: 'admin123',
|
|
298
|
+
name: 'System Admin',
|
|
299
|
+
tenant: { code: 'system', name: 'System Tenant' },
|
|
300
|
+
|
|
301
|
+
// User being impersonated
|
|
302
|
+
actAs: {
|
|
303
|
+
accountCode: 'user456',
|
|
304
|
+
name: 'Target User',
|
|
305
|
+
tenant: { code: 'client-a', name: 'Client A' }
|
|
306
|
+
}
|
|
307
|
+
})),
|
|
308
|
+
'x-language': 'en'
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Implementation in Controllers
|
|
313
|
+
|
|
314
|
+
The `BaseController.getLoggedUser()` method automatically handles impersonation:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
class MyController extends TenantBaseController<MyService> {
|
|
318
|
+
|
|
319
|
+
async getUserData(req: Request) {
|
|
320
|
+
// This will return the impersonated user if actAs is present,
|
|
321
|
+
// otherwise returns the original user
|
|
322
|
+
const currentUser = this.getLoggedUser(req);
|
|
323
|
+
|
|
324
|
+
console.log('Operating as:', currentUser.name);
|
|
325
|
+
console.log('Tenant context:', currentUser.tenant.code);
|
|
326
|
+
|
|
327
|
+
// All operations will be performed in the context of the impersonated user
|
|
328
|
+
return await this.service.getUserData(currentUser);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
#### Use Cases
|
|
335
|
+
|
|
336
|
+
- **Debug user issues**: Support staff can reproduce problems by acting as the affected user
|
|
337
|
+
- **Cross-tenant troubleshooting**: System administrators can debug issues across different tenants
|
|
338
|
+
- **Testing user permissions**: Verify that user-specific access controls work correctly
|
|
339
|
+
- **Data migration**: Perform operations on behalf of users during system migrations
|
|
340
|
+
|
|
341
|
+
#### Express Application Responsibilities
|
|
342
|
+
|
|
343
|
+
The Express application simply:
|
|
344
|
+
- **Trusts the gateway**: Accepts user impersonation information from authenticated gateway requests
|
|
345
|
+
- **Processes context**: Uses the `actAs` user for all business operations when present
|
|
346
|
+
- **No validation**: Does not validate impersonation privileges or restrictions
|
|
347
|
+
|
|
348
|
+
#### Gateway Responsibilities for Impersonation
|
|
349
|
+
|
|
350
|
+
All impersonation controls should be handled by the gateway:
|
|
351
|
+
- **Privilege validation**: Verify users have permission to impersonate others
|
|
352
|
+
- **Audit logging**: Record all impersonation activities for security auditing
|
|
353
|
+
- **Time limits**: Implement time-based restrictions on impersonation sessions
|
|
354
|
+
- **Session management**: Handle impersonation session lifecycle
|
|
355
|
+
- **Cross-tenant controls**: Apply additional checks for cross-tenant impersonation
|
|
356
|
+
- **Notification**: Optionally notify target users when their accounts are being impersonated
|
|
357
|
+
|
|
358
|
+
## Multi-tenant Support
|
|
359
|
+
|
|
360
|
+
The library provides built-in multi-tenant support:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// Tenant-specific controller
|
|
364
|
+
class ProductController extends TenantBaseController<ProductService> {
|
|
365
|
+
// Automatically receives logged user context
|
|
366
|
+
// All operations are tenant-scoped
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Admin controller (cross-tenant)
|
|
370
|
+
class SystemController extends AdminBaseController<SystemService> {
|
|
371
|
+
// Operations across all tenants
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Validation
|
|
376
|
+
|
|
377
|
+
Built-in validation using `@ticatec/bean-validator`:
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { ValidationRules, StringValidator, NumberValidator } from '@ticatec/bean-validator';
|
|
381
|
+
|
|
382
|
+
const rules: ValidationRules = [
|
|
383
|
+
new StringValidator('name', { required: true, minLen: 2, maxLen: 50 }),
|
|
384
|
+
new StringValidator('email', {
|
|
385
|
+
required: true,
|
|
386
|
+
format: {
|
|
387
|
+
regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
388
|
+
message: 'Invalid email format'
|
|
389
|
+
}
|
|
390
|
+
}),
|
|
391
|
+
new NumberValidator('age', { required: false, minValue: 18, maxValue: 120 })
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
class UserController extends CommonController<UserService> {
|
|
395
|
+
constructor(service: UserService) {
|
|
396
|
+
super(service, rules); // Validation applied automatically
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Error Handling
|
|
402
|
+
|
|
403
|
+
Centralized error handling with `@ticatec/express-exception`:
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import {
|
|
407
|
+
ActionNotFoundError,
|
|
408
|
+
UnauthenticatedError,
|
|
409
|
+
IllegalParameterError
|
|
410
|
+
} from '@ticatec/express-exception';
|
|
411
|
+
|
|
412
|
+
// Errors are automatically handled and formatted
|
|
413
|
+
throw new ActionNotFoundError('Resource not found');
|
|
414
|
+
throw new UnauthenticatedError('User not authenticated');
|
|
415
|
+
throw new IllegalParameterError('Invalid input data');
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## API Reference
|
|
419
|
+
|
|
420
|
+
### Types
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Function signatures
|
|
424
|
+
export type RestfulFunction = (req: Request) => any;
|
|
425
|
+
export type ControlFunction = (req: Request, res: Response) => any;
|
|
426
|
+
export type moduleLoader = () => Promise<any>;
|
|
427
|
+
|
|
428
|
+
// Validation types (from @ticatec/bean-validator)
|
|
429
|
+
export type ValidationRules = Array<BaseValidator>;
|
|
430
|
+
|
|
431
|
+
// User interfaces
|
|
432
|
+
export interface CommonUser {
|
|
433
|
+
accountCode: string;
|
|
434
|
+
name: string;
|
|
435
|
+
tenant: {
|
|
436
|
+
code: string;
|
|
437
|
+
name: string;
|
|
438
|
+
};
|
|
439
|
+
[key: string]: any;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export interface LoggedUser extends CommonUser {
|
|
443
|
+
actAs?: CommonUser; // For user impersonation
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Development
|
|
448
|
+
|
|
449
|
+
### Build
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
npm run build # Build the project
|
|
453
|
+
npm run dev # Development mode with watch
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Requirements
|
|
457
|
+
|
|
458
|
+
- Node.js >= 18.0.0
|
|
459
|
+
- Express.js ^5.1.0
|
|
460
|
+
- TypeScript ^5.0.0
|
|
461
|
+
|
|
462
|
+
## Dependencies
|
|
463
|
+
|
|
464
|
+
- `@ticatec/bean-validator`: Data validation
|
|
465
|
+
- `@ticatec/express-exception`: Error handling
|
|
466
|
+
- `@ticatec/node-common-library`: Common utilities
|
|
467
|
+
- `log4js`: Logging framework
|
|
468
|
+
|
|
469
|
+
## Contributing
|
|
470
|
+
|
|
471
|
+
1. Fork the repository
|
|
472
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
473
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
474
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
475
|
+
5. Open a Pull Request
|
|
476
|
+
|
|
477
|
+
## License
|
|
478
|
+
|
|
479
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
480
|
+
|
|
481
|
+
## Support
|
|
482
|
+
|
|
483
|
+
For support and questions:
|
|
484
|
+
|
|
485
|
+
- 📧 Email: henry@ticatec.com
|
|
486
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/ticatec/common-express-server/issues)
|
|
487
|
+
- 📚 Documentation: [GitHub Repository](https://github.com/ticatec/common-express-server)
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
Made with ❤️ by [TicaTec](https://github.com/ticatec)
|
package/lib/AppConf.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application configuration singleton class
|
|
3
|
+
*/
|
|
4
|
+
export default class AppConf {
|
|
5
|
+
/** Configuration object */
|
|
6
|
+
private readonly conf;
|
|
7
|
+
/** Singleton instance */
|
|
8
|
+
static instance: AppConf;
|
|
9
|
+
/**
|
|
10
|
+
* Private constructor for singleton pattern
|
|
11
|
+
* @param conf Configuration object
|
|
12
|
+
*/
|
|
13
|
+
private constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Gets the singleton instance
|
|
16
|
+
* @returns AppConf instance or null if not initialized
|
|
17
|
+
*/
|
|
18
|
+
static getInstance(): AppConf;
|
|
19
|
+
/**
|
|
20
|
+
* Initializes the configuration singleton
|
|
21
|
+
* @param config Configuration object
|
|
22
|
+
* @returns AppConf instance
|
|
23
|
+
*/
|
|
24
|
+
static init(config: any): AppConf;
|
|
25
|
+
/**
|
|
26
|
+
* Gets configuration value by key (supports dot notation)
|
|
27
|
+
* @param key Configuration key (can use dot notation like 'server.port')
|
|
28
|
+
* @returns Configuration value or undefined if not found
|
|
29
|
+
*/
|
|
30
|
+
get(key: string): any;
|
|
31
|
+
}
|
package/lib/AppConf.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Application configuration singleton class
|
|
5
|
+
*/
|
|
6
|
+
class AppConf {
|
|
7
|
+
/**
|
|
8
|
+
* Private constructor for singleton pattern
|
|
9
|
+
* @param conf Configuration object
|
|
10
|
+
*/
|
|
11
|
+
constructor(conf) {
|
|
12
|
+
this.conf = conf;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets the singleton instance
|
|
16
|
+
* @returns AppConf instance or null if not initialized
|
|
17
|
+
*/
|
|
18
|
+
static getInstance() {
|
|
19
|
+
return AppConf.instance;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Initializes the configuration singleton
|
|
23
|
+
* @param config Configuration object
|
|
24
|
+
* @returns AppConf instance
|
|
25
|
+
*/
|
|
26
|
+
static init(config) {
|
|
27
|
+
console.debug('Initializing configuration center', config);
|
|
28
|
+
if (AppConf.instance == null) {
|
|
29
|
+
AppConf.instance = new AppConf(config);
|
|
30
|
+
}
|
|
31
|
+
return AppConf.instance;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Gets configuration value by key (supports dot notation)
|
|
35
|
+
* @param key Configuration key (can use dot notation like 'server.port')
|
|
36
|
+
* @returns Configuration value or undefined if not found
|
|
37
|
+
*/
|
|
38
|
+
get(key) {
|
|
39
|
+
if (!key)
|
|
40
|
+
return undefined;
|
|
41
|
+
const keys = key.split('.');
|
|
42
|
+
let result = this.conf;
|
|
43
|
+
for (const k of keys) {
|
|
44
|
+
if (result && typeof result === 'object' && k in result) {
|
|
45
|
+
result = result[k];
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Singleton instance */
|
|
55
|
+
AppConf.instance = null;
|
|
56
|
+
exports.default = AppConf;
|
|
57
|
+
//# sourceMappingURL=AppConf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppConf.js","sourceRoot":"src/","sources":["AppConf.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,MAAqB,OAAO;IAOxB;;;OAGG;IACH,YAAoB,IAAS;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,WAAW;QACd,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,MAAW;QACnB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,MAAM,CAAC,CAAC;QAC3D,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;YAC3B,OAAO,CAAC,QAAQ,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,GAAW;QACX,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAE3B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC;QAEvB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACnB,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;gBACtD,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACJ,OAAO,SAAS,CAAC;YACrB,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;;AApDD,yBAAyB;AAClB,gBAAQ,GAAY,IAAI,CAAC;kBALf,OAAO"}
|